Sample

Schnappinger/argoUML/org.argouml.uml.ui.PropPanel

Human rating uses the original dataset scale.

Human3
Lines734

Scores

MethodScoreScaleDataset rank
(0–100)
Posnett00–1; higher is more readable
14.4Δ 12.4
Scalabrino0.8020–1; higher is more readable
62.7Δ 35.9
Dorn00–1; higher is more readable
8.9Δ 17.8
Mi0.5970–1; higher is more readable
61.4Δ 34.7
LLOC225Logical lines; fewer is more readable
12.2Δ 14.5
DeepSeek V4 Pro14.330–20; mean of three runs
32.3Δ 5.6
GPT-6.1 Sol140–20; mean of three runs
16.2Δ 10.6
BTTF0.5080–1; higher is more readable
45.5Δ 18.8
Human31–4; original rating
26.7

Views

Source code

/* $Id: PropPanel.java 19907 2012-12-30 13:06:01Z closettop_nightlybuild $ ***************************************************************************** * Copyright (c) 2009-2012 Contributors - see below * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * tfmorris ***************************************************************************** * * Some portions of this file was previously release using the BSD License: */ // Copyright (c) 1996-2008 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.uml.ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.Action; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JToolBar; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.border.TitledBorder; import javax.swing.event.EventListenerList; import org.argouml.application.api.AbstractArgoJPanel; import org.argouml.application.helpers.ResourceLoaderWrapper; import org.argouml.i18n.Translator; import org.argouml.kernel.ProfileConfiguration; import org.argouml.kernel.ProjectManager; import org.argouml.model.Model; import org.argouml.ui.ActionCreateContainedModelElement; import org.argouml.ui.LookAndFeelMgr; import org.argouml.ui.targetmanager.TargetEvent; import org.argouml.ui.targetmanager.TargetListener; import org.argouml.ui.targetmanager.TargettableModelView; import org.tigris.gef.presentation.Fig; import org.tigris.swidgets.GridLayout2; import org.tigris.swidgets.Orientation; import org.tigris.toolbar.ToolBarFactory; /** * This abstract class provides the basic layout and event dispatching support * for all Property Panels.<p> * * The property panel is {@link org.argouml.uml.ui.LabelledLayout} layed out as * a number (specified in the constructor) of equally sized panels that split * the available space. Each panel has a column of "captions" and matching * column of "fields" which are laid out independently from the other * panels.<p> * * The Properties panels for UML Model Elements are structured in an inheritance * hierarchy that matches the UML metamodel. */ public abstract class PropPanel extends AbstractArgoJPanel implements UMLUserInterfaceContainer, ComponentListener { /** * Logger. */ private static final Logger LOG = Logger.getLogger(PropPanel.class.getName()); private Object target; private Object modelElement; /** * List of event listeners to notify. This is computed one time and frozen * the first time any target change method (e.g. setTarget, targetAdded) is * called. */ private EventListenerList listenerList; private JPanel buttonPanel = new JPanel(new GridLayout()); private JLabel titleLabel; /** * A list with "actions".<p> * * Action in this respect are one of:<ul> * <li> {@link Action} * <li> {@link JButton} * <li> {@link Object}[] * </ul> */ private List actions = new ArrayList(); private static Font stdFont = LookAndFeelMgr.getInstance().getStandardFont(); /** * Construct new PropPanel using LabelledLayout. * <p> * @param icon The icon to display for the panel * @param label The label for the title of the panel (to be localized). */ public PropPanel(String label, ImageIcon icon) { super(Translator.localize(label)); LabelledLayout layout = new LabelledLayout(); layout.setHgap(5); setLayout(layout); if (icon != null) { setTitleLabel(new JLabel(Translator.localize(label), icon, SwingConstants.LEFT)); } else { setTitleLabel(new JLabel(Translator.localize(label))); } titleLabel.setLabelFor(buttonPanel); add(titleLabel); add(buttonPanel); addComponentListener(this); } /* * @see org.tigris.swidgets.Orientable#setOrientation(org.tigris.swidgets.Orientation) */ @Override public void setOrientation(Orientation orientation) { // TODO: Do we need to change the layout manager when // changing orientation to match the behavior of the constructor? // if (getOrientation() != orientation) { // LabelledLayout layout = new LabelledLayout(orientation == Vertical // .getInstance()); // setLayout(layout); // } super.setOrientation(orientation); } /** * Add a button to the toolbar of a property panel using the action to * control the behavior of the action. * * @param action * the action which will be used in the toolbar button. */ protected void addAction(Action action) { actions.add(action); } /** * Add a button to the toolbar of a property panel using the action to * control the behavior of the action. * * @param action * the action which will be used in the toolbar button. * @param tooltip * the tooltip to set, or null to skip setting of a new tooltip. */ protected void addAction(Action action, String tooltip) { JButton button = new TargettableButton(action); if (tooltip != null) { button.setToolTipText(tooltip); } button.setText(""); button.setFocusable(false); actions.add(button); } /** * Add multiple buttons at once. * * @param actionArray the Actions. */ protected void addAction(Object[] actionArray) { actions.add(actionArray); } public void buildToolbar() { LOG.log(Level.FINE, "Building toolbar"); ToolBarFactory factory = new ToolBarFactory(getActions()); factory.setRollover(true); factory.setFloatable(false); JToolBar toolBar = factory.createToolBar(); toolBar.setName("misc.toolbar.properties"); buttonPanel.removeAll(); buttonPanel.add(BorderLayout.WEST, toolBar); // Set the tooltip of the arrow to open combined tools: buttonPanel.putClientProperty("ToolBar.toolTipSelectTool", Translator.localize("action.select")); } /** * Get the actions that will make up the toolbar on this panel. * @return The list of actions to show for this panel. */ protected List getActions() { return actions; } private static class TargettableButton extends JButton implements TargettableModelView { public TargettableButton(Action action) { super(action); } public TargetListener getTargettableModel() { if (getAction() instanceof TargetListener) { return (TargetListener) getAction(); } return null; } } /** * Add a component with the specified label.<p> * * @param label * the label for the component * @param component * the component * @return the label added */ public JLabel addField(String label, Component component) { JLabel jlabel = createLabelFor(label, component); component.setFont(stdFont); add(jlabel); add(component); if (component instanceof UMLStereotypeList) { UMLModelElementListModel2 list = (UMLModelElementListModel2) ((UMLStereotypeList) component).getModel(); ActionCreateContainedModelElement newAction = new ActionCreateContainedModelElement( list.getMetaType(), list.getTarget(), "New..."); // TODO: i18n } return jlabel; } /** * @param label The text of the label (the method cares about i18n) * @param comp The component that this label is for * @return a new JLabel */ private JLabel createLabelFor(String label, Component comp) { JLabel jlabel = new JLabel(Translator.localize(label)); jlabel.setToolTipText(Translator.localize(label)); jlabel.setFont(stdFont); jlabel.setLabelFor(comp); return jlabel; } /** * Add a component with the specified label positioned after another * component. * * @param label * the label for the component * @param component * the component * @param afterComponent * the component before * @return the newly added label */ public JLabel addFieldAfter(String label, Component component, Component afterComponent) { int nComponent = getComponentCount(); for (int i = 0; i < nComponent; ++i) { if (getComponent(i) == afterComponent) { JLabel jlabel = createLabelFor(label, component); component.setFont(stdFont); add(jlabel, ++i); add(component, ++i); return jlabel; } } throw new IllegalArgumentException("Component not found"); } /** * Add a component with the specified label positioned before another * component.<p> * * @param label * the label for the component * @param component * the to be added component * @param beforeComponent * the component before its label we add * @return the newly added component */ public JLabel addFieldBefore(String label, Component component, Component beforeComponent) { int nComponent = getComponentCount(); for (int i = 0; i < nComponent; ++i) { if (getComponent(i) == beforeComponent) { JLabel jlabel = createLabelFor(label, component); component.setFont(stdFont); add(jlabel, i - 1); add(component, i++); return jlabel; } } throw new IllegalArgumentException("Component not found"); } /** * Add a separator. */ protected final void addSeparator() { add(LabelledLayout.getSeparator()); } /** * Set the target to be associated with a particular property panel.<p> * * This involves resetting the third party listeners. * * @param t * The object to be set as a target. */ public void setTarget(Object t) { LOG.log(Level.FINE, "setTarget called with {0} as parameter (not target!)", t); t = (t instanceof Fig) ? ((Fig) t).getOwner() : t; // If the target has changed notify the third party listener if it // exists and dispatch a new element event listener to // ourself. Otherwise dispatch a target reasserted to ourself. Runnable dispatch = null; if (t != target) { // Set up the target and its model element variant. target = t; modelElement = null; if (listenerList == null) { listenerList = collectTargetListeners(this); } if (Model.getFacade().isAUMLElement(target)) { modelElement = target; } // This will add a new ModelElement event listener // after update is complete dispatch = new UMLChangeDispatch(this, UMLChangeDispatch.TARGET_CHANGED_ADD); buildToolbar(); } else { dispatch = new UMLChangeDispatch(this, UMLChangeDispatch.TARGET_REASSERTED); } SwingUtilities.invokeLater(dispatch); // update the titleLabel // MVW: This overrules the icon set initiallly... Why do we need this? if (titleLabel != null) { Icon icon = null; if (t != null) { icon = ResourceLoaderWrapper.getInstance().lookupIcon(t); } if (icon != null) { titleLabel.setIcon(icon); } } } /** * Builds a eventlistenerlist of all targetlisteners that are part of this * container and its children. Components do not need to register * themselves. They are registered implicitly if they implement the * TargetListener interface. * * @param container * the container to search for targetlisteners * @return an EventListenerList with all TargetListeners on this container * and its children. */ private EventListenerList collectTargetListeners(Container container) { Component[] components = container.getComponents(); EventListenerList list = new EventListenerList(); for (int i = 0; i < components.length; i++) { if (components[i] instanceof TargetListener) { list.add(TargetListener.class, (TargetListener) components[i]); } if (components[i] instanceof TargettableModelView) { list.add(TargetListener.class, ((TargettableModelView) components[i]) .getTargettableModel()); } if (components[i] instanceof Container) { EventListenerList list2 = collectTargetListeners( (Container) components[i]); Object[] objects = list2.getListenerList(); for (int j = 1; j < objects.length; j += 2) { list.add(TargetListener.class, (TargetListener) objects[j]); } } } if (container instanceof PropPanel) { /* We presume that the container equals this PropPanel. */ for (TargetListener action : collectTargetListenerActions()) { list.add(TargetListener.class, action); } } return list; } private Collection<TargetListener> collectTargetListenerActions() { Collection<TargetListener> set = new HashSet<TargetListener>(); for (Object obj : actions) { if (obj instanceof TargetListener) { set.add((TargetListener) obj); } } return set; } /* * @see org.argouml.ui.TabTarget#getTarget() */ public final Object getTarget() { return target; } /* * @see org.argouml.ui.TabTarget#refresh() */ public void refresh() { SwingUtilities.invokeLater(new UMLChangeDispatch(this, 0)); } /* * @see org.argouml.ui.TabTarget#shouldBeEnabled(java.lang.Object) */ public boolean shouldBeEnabled(Object t) { t = (t instanceof Fig) ? ((Fig) t).getOwner() : t; return Model.getFacade().isAUMLElement(t); } /** * This method can be overridden in derived Panels where the appropriate * namespace for display may not be the same as the namespace of the target. * * @return the namespace */ protected Object getDisplayNamespace() { Object ns = null; Object theTarget = getTarget(); if (Model.getFacade().isAModelElement(theTarget)) { ns = Model.getFacade().getNamespace(theTarget); } return ns; } /* * @see org.argouml.uml.ui.UMLUserInterfaceContainer#getProfile() */ public ProfileConfiguration getProfile() { return ProjectManager.getManager().getCurrentProject() .getProfileConfiguration(); } /* * @see org.argouml.uml.ui.UMLUserInterfaceContainer#getModelElement() */ public final Object getModelElement() { return modelElement; } /* * @see org.argouml.uml.ui.UMLUserInterfaceContainer#formatElement(java.lang.Object) */ public String formatElement(Object element) { return getProfile().getFormatingStrategy().formatElement(element, getDisplayNamespace()); } /* * @see org.argouml.uml.ui.UMLUserInterfaceContainer#formatNamespace(java.lang.Object) */ public String formatNamespace(Object namespace) { return getProfile().getFormatingStrategy().formatElement(namespace, null); } /* * @see org.argouml.uml.ui.UMLUserInterfaceContainer#formatCollection(java.util.Iterator) */ public String formatCollection(Iterator iter) { Object namespace = getDisplayNamespace(); return getProfile().getFormatingStrategy().formatCollection(iter, namespace); } /** * Get the delete action. * * @return the delete action */ protected final Action getDeleteAction() { return ActionDeleteModelElements.getTargetFollower(); } /** * Check whether this element can be deleted. Currently it only checks * whether we delete the main model. ArgoUML does not like that. * * @since 0.13.2 * @return whether this element can be deleted */ public boolean isRemovableElement() { return ((getTarget() != null) && (getTarget() != (ProjectManager .getManager().getCurrentProject().getModel()))); } /* * @see TargetListener#targetAdded(TargetEvent) */ public void targetAdded(TargetEvent e) { if (listenerList == null) { listenerList = collectTargetListeners(this); } setTarget(e.getNewTarget()); if (isVisible()) { fireTargetAdded(e); } } /* * @see TargetListener#targetRemoved(TargetEvent) */ public void targetRemoved(TargetEvent e) { setTarget(e.getNewTarget()); if (isVisible()) { fireTargetRemoved(e); } } /* * @see TargetListener#targetSet(TargetEvent) */ public void targetSet(TargetEvent e) { setTarget(e.getNewTarget()); if (isVisible()) { fireTargetSet(e); } } private void fireTargetSet(TargetEvent targetEvent) { if (listenerList == null) { listenerList = collectTargetListeners(this); } // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TargetListener.class) { ((TargetListener) listeners[i + 1]).targetSet(targetEvent); } } } private void fireTargetAdded(TargetEvent targetEvent) { if (listenerList == null) { listenerList = collectTargetListeners(this); } // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TargetListener.class) { ((TargetListener) listeners[i + 1]).targetAdded(targetEvent); } } } private void fireTargetRemoved(TargetEvent targetEvent) { if (listenerList == null) { listenerList = collectTargetListeners(this); } // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TargetListener.class) { ((TargetListener) listeners[i + 1]).targetRemoved(targetEvent); } } } /** * @param theTitleLabel * the title of the panel shown at the top */ protected void setTitleLabel(JLabel theTitleLabel) { titleLabel = theTitleLabel; titleLabel.setFont(stdFont); } /** * @return the title of the panel shown at the top */ protected JLabel getTitleLabel() { return titleLabel; } protected final JPanel createBorderPanel(String title) { return new GroupPanel(Translator.localize(title)); } private class GroupPanel extends JPanel { public GroupPanel(String title) { super(new GridLayout2()); TitledBorder border = new TitledBorder(Translator.localize(title)); border.setTitleFont(stdFont); setBorder(border); } public void setEnabled(boolean enabled) { super.setEnabled(enabled); for (final Component component : getComponents()) { component.setEnabled(enabled); } } } /** * If there are no buttons to show in the toolbar, * then set the height to e.g. 18, so that the title * is aligned right by the LabelledLayout. * * @param height the height */ protected void setButtonPanelSize(int height) { /* Set the minimum and preferred equal, * so that the size is fixed for the labelledlayout. */ buttonPanel.setMinimumSize(new Dimension(0, height)); buttonPanel.setPreferredSize(new Dimension(0, height)); } /** * Look up an icon. * * @param name * the resource name. * @return an ImageIcon corresponding to the given resource name */ protected static ImageIcon lookupIcon(String name) { return ResourceLoaderWrapper.lookupIconResource(name); } /* * @see java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent) */ public void componentHidden(ComponentEvent e) { // TODO: do we want to fire targetRemoved here or is it enough to just // stop updating the targets? } /* * @see java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent) */ public void componentShown(ComponentEvent e) { // Refresh the target for all our children which weren't getting // while not visible fireTargetSet(new TargetEvent( this, TargetEvent.TARGET_SET, null, new Object[] {target})); } /* * @see java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent) */ public void componentMoved(ComponentEvent e) { // ignored } /* * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent) */ public void componentResized(ComponentEvent e) { // ignored } }

Loading feature diagnosis…

Source regions

Feature contributions

Feature contributions

FeatureValueContribution
(log-odds)
Halstead volumeHow much symbolic information the code contains. It combines the total number of operators and values with the number of distinct ones.20431.416−674.237
Source linesThe number of non-empty source lines.734+293.6
Byte entropyHow varied the bytes in the source text are. Repeated bytes give a lower value; a more even mixture gives a higher value.4.611−6.916

Intercept 8.87 + feature contributions = -378.683 (log-odds).
Score = sigmoid(-378.683) = 0.

Score0.802

Feature contributions

FeatureValueContribution
(log-odds)
Comment layout frequencyHow frequently the layout switches between lines containing only comments or whitespace and lines containing code.735−24.988
Indentation frequencyHow rapidly indentation changes from line to line.502+16.626
Number layout frequencyHow rapidly the number of numeric values per line changes through the code.502−11.098
Identifier layout (vertical)How rapidly the visual pattern of identifier characters changes from top to bottom.733.904+9.849
Comment layout (horizontal)How rapidly the visual pattern of comment characters changes from left to right.92.83+0.693
Operator visual areaThe share of the code’s visual area occupied by operators such as +, =, and *.0.057+0.385
Identifier layout (horizontal)How rapidly the visual pattern of identifier characters changes from left to right. It measures spatial frequency, not the meaning of the names.92.976−0.273

Intercept 0.07 + feature contributions = -8.735 (log-odds).
Score = sigmoid(-8.735) = 0.

Score0.597
Score225
Run 1

The code demonstrates generally sound structure with clear separation of concerns, appropriate use of constants, and logical method organization. Javadoc comments are extensive and helpful for understanding purpose. However, several issues reduce readability: the setTarget() method is overly complex with nested conditionals and side effects (building toolbar inside target change logic), the collectTargetListeners() method has deep nesting across multiple loops and conditionals, and some methods contain commented-out code that adds noise. There are also inconsistencies: mixed use of tabs/spaces (visible in buildToolbar()), redundant null checks before event dispatch methods, and methods like setOrientation() contain dead commented code. The class manages multiple responsibilities (layout, event handling, toolbar building) which makes it lengthy. Action granularity is mostly good with one operation per line, but some complex expressions (e.g., the ternary for Fig handling) are repeated across multiple methods rather than extracted. Overall, while the code is comprehensible and well-documented, the structural complexity and nesting in event-handling methods detract from its readability.

Run 2

The code is well-structured and readable overall. It follows a logical organization with clear separation of concerns, though the class is quite long. The nesting is generally shallow with only a few levels in the most complex methods like collectTargetListeners. Intent is clearly expressed through method names and documentation comments. However, there are some readability issues: use of raw types (List actions, Iterator), inconsistent indentation, and some methods contain multiple actions per line (e.g., add(jlabel, ++i)). The setTarget method is particularly complex with conditional logic and Runnable dispatch that could be clearer. The code would benefit from more modern Java features like generics and enhanced for loops. Action granularity is mostly good, though some methods mix multiple responsibilities. The reading flow is natural with methods grouped logically, but the copyright header adds substantial noise at the start.

Run 3

The code is moderately readable. It has a clear logical structure with a well-organized class layout and reasonable method separation, earning points for structure. Nesting is generally shallow, with only a few loops and conditionals. However, clarity of intent is hampered by a large amount of boilerplate (copyright, imports) and several methods with complex logic like collectTargetListeners and setTarget. Code length is unnecessarily long due to duplicate fireTarget* methods and verbose comments. Action granularity is mostly one action per line. Reading flow is natural in simple getters/setters but becomes convoluted in listener collection and target-dispatch logic. The class mixes too many concerns (layout, event handling, listener management), making it harder to follow.

Run 1

Code Structure: Mostly well-organized into focused methods and small inner classes, although layout, toolbar construction, and event management share one large class. Nesting: Generally shallow; recursive listener collection and target updates introduce moderate nesting. Clarity of intent: Descriptive method names and documentation explain most behavior, but raw collections, generic Object targets, unused newAction construction, and stale comments obscure some intent. Code length: Numerous small methods help navigation, but duplicated event-dispatch logic, repetitive documentation, and commented-out code add bulk. Action granularity: Usually one action per statement; index increments embedded in add calls make insertion logic harder to follow. Reading flow: Mostly natural, with related functionality grouped together, but inconsistent indentation, long casts and chained calls, and asynchronous dispatch require extra attention.

Run 2

Code Structure: Mostly well-organized into focused methods, but the class combines layout, toolbar construction, target management, and event dispatch. Nesting: Generally shallow; recursive listener collection introduces moderate nesting. Clarity of intent: Descriptive method names and documentation explain most behavior, while raw collections, generic Object targets, numeric dispatch arguments, and an unused newAction variable obscure details. Code length: Numerous small methods help comprehension, but duplicated event-dispatch logic, repetitive documentation, and commented-out code add unnecessary bulk. Action granularity: Usually one operation per statement, although index increments inside add calls combine mutation with insertion and require extra attention. Reading flow: Related methods are largely grouped sensibly, but inconsistent indentation, long casts and call chains, and deferred event handling interrupt an otherwise straightforward flow.

Run 3

Code Structure: Responsibilities are separated into mostly small methods, but layout, toolbar construction, target management, and event dispatch share a large class. Nesting: Generally shallow; recursive listener collection introduces moderate nesting. Clarity of intent: Descriptive method names and documentation explain most behavior, but raw collections, generic Object targets, an unused newAction variable, and numeric dispatch flags obscure details. Code length: Repeated event-dispatch methods, extensive boilerplate, and commented-out code make the class longer than necessary. Action granularity: Most statements perform one action, although increments embedded in add calls combine index mutation with UI changes. Reading flow: Related methods are reasonably grouped and helper extraction supports navigation, but inconsistent indentation, long casts, stale comments, and asynchronous target handling interrupt an otherwise understandable flow.