From 37cb8fda0f3bf3824401364056e8a717b4e02b53 Mon Sep 17 00:00:00 2001 From: AmlanDalai Date: Sat, 7 Mar 2026 23:33:11 +0530 Subject: [PATCH 1/2] fix(LearningPanel): replace == with .equals() for ActionEvent comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace reference equality (==) with .equals() for ActionEvent dispatch in doAction() — same class of bug fixed in GuiPanel (PR #6) - Remove System.out.println debug statements from doAction() and updateClassifier() - Add full Javadoc to all methods and class --- src/activeSegmentation/gui/LearningPanel.java | 676 +++++++++--------- 1 file changed, 329 insertions(+), 347 deletions(-) diff --git a/src/activeSegmentation/gui/LearningPanel.java b/src/activeSegmentation/gui/LearningPanel.java index 7fb6939a..31da975a 100644 --- a/src/activeSegmentation/gui/LearningPanel.java +++ b/src/activeSegmentation/gui/LearningPanel.java @@ -1,347 +1,329 @@ -package activeSegmentation.gui; - - -import java.awt.Color; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.ArrayList; -//import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.ImageIcon; - -import activeSegmentation.ASCommon; -import activeSegmentation.learning.ClassifierManager; -import activeSegmentation.learning.weka.WekaClassifier; -import weka.classifiers.AbstractClassifier; -import weka.classifiers.Classifier; -import weka.core.OptionHandler; -import weka.core.Utils; -import weka.gui.GenericObjectEditor; -import weka.gui.PropertyPanel; - -import activeSegmentation.IClassifier; -import activeSegmentation.IDataSet; -import activeSegmentation.IFeatureSelection; -import activeSegmentation.prj.LearningInfo; -import activeSegmentation.prj.ProjectInfo; -import activeSegmentation.prj.ProjectManager; -//import activeSegmentation.util.GuiUtil; -//import ijaux.Util; - - -/** - * This is a Weka-specific panel, so it is OK to expose Weka classes. - * @author Sumit Vohra, Dimiter Prodanov - * - */ -public class LearningPanel extends JFrame implements Runnable, ASCommon { - - //platform-level variables - private ProjectManager projectManager; - private ProjectInfo projectInfo; - private JList featureSelList; - - //class-specific variables - private String defaultOptions=""; - private String defaultClassifierName=""; - private boolean hasChanged=false; - - //UI variables -// private final JFrame frame = new JFrame("Learning"); - private final ActionEvent LOAD_BUTTON_PRESSED = new ActionEvent(this, 1, "Load"); - private final ActionEvent SAVE_BUTTON_PRESSED = new ActionEvent(this, 2, "Save"); - private ClassifierManager learningManager; - - //Weka-specific variables - private AbstractClassifier aclass=null; - private GenericObjectEditor wekaClassifierEditor ; - - /** - * - * @param projectManager - * @param learningManager - */ - public LearningPanel(ProjectManager projectManager, ClassifierManager learningManager ) { - this.projectManager = projectManager; - this.learningManager=learningManager; - this.projectInfo = projectManager.getMetaInfo(); - try { - this.wekaClassifierEditor = new GenericObjectEditor(); - }catch (Exception ex ) { - ex.printStackTrace(); - } - DefaultListModel model = new DefaultListModel<>(); - featureSelectionUI(model); - featureSelList = new JList<>(model); - } - - /** - * - * @param event - */ - public void doAction(ActionEvent event) { - if (event == SAVE_BUTTON_PRESSED) { - updateClassifier(); - if (aclass!=null ) { - IClassifier classifier = new WekaClassifier(aclass); - - learningManager.setClassifier(classifier); - learningManager.saveLearningMetaData(); - projectManager.updateMetaInfo(projectInfo); - - // to avoid data creep because we are changing the learning method. - IDataSet data = projectManager.getDataSet(); - if (data!=null) - data.delete(); - } - - } // end SAVE - if (event == LOAD_BUTTON_PRESSED) { - LearningInfo li=learningManager.getLearningMetaData(); - String[] options= li.getOptionsArray(); - - String cname=li.getClassifierName(); - System.out.println("loading "+cname); - //GuiUtil.printStringArray(options); - try { - if (cname!="") { - // TODO change into loadClass from TestLoadClass - aclass = (AbstractClassifier) Class.forName(cname).newInstance(); - //cls.setOptions(options); - IClassifier classifier = new WekaClassifier(aclass); - learningManager.setClassifier(classifier); - wekaClassifierEditor.setClassType(Classifier.class); - Object obj =learningManager.getClassifier(); - System.out.println(obj); - - aclass.setOptions(options); - wekaClassifierEditor.setValue(aclass); - - defaultOptions = Utils.joinOptions(options); - System.out.println(defaultOptions); - } - - } catch (Exception e) { - e.printStackTrace(); - } - - } // end LOAD - } - - - - @Override - public void run() { - showPanel(); - } - - /** - * - */ - private void showPanel() { - setTitle("Learning"); - setIconImage(Toolkit.getDefaultToolkit().getImage(LearningPanel.class.getResource("logo.png"))); - setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - getContentPane().setBackground(Color.GRAY); - setLocationRelativeTo(null); - setSize(600, 300); - - - final int xOffsetCol1=10; - - JPanel aPanel = new JPanel(); - aPanel.setLayout(null); - aPanel.setBackground(Color.GRAY); - - JPanel learningJPanel = new JPanel(); - learningJPanel.setBorder(BorderFactory.createTitledBorder("Learning")); - - PropertyPanel wekaCEPanel = new PropertyPanel(wekaClassifierEditor); - wekaClassifierEditor.setClassType(Classifier.class); - wekaClassifierEditor.setValue(learningManager.getClassifier()); - Object c = wekaClassifierEditor.getValue(); - defaultOptions = ""; - defaultClassifierName = c.getClass().getName(); - - if ((c instanceof OptionHandler)) { - defaultOptions = Utils.joinOptions(((OptionHandler)c).getOptions()); - } - - wekaCEPanel.setBounds(30, 30, 250, 30); - learningJPanel.add(wekaCEPanel); - learningJPanel.setBounds(xOffsetCol1, 20, 300, 150); - - ////////////////////////////////Will be enabled in the future - - JPanel options = new JPanel(); - - options.setBorder(BorderFactory.createTitledBorder("Learning Options")); - options.setBounds(xOffsetCol1, 120, 300, 120); - - - JRadioButton pasiveLearning = new JRadioButton ("Passive Learning" ); - JRadioButton activeLearning = new JRadioButton ("Active Learning" ); - ButtonGroup bg=new ButtonGroup(); - bg.add(pasiveLearning); - bg.add(activeLearning); - options.add(pasiveLearning); - options.add(activeLearning); - pasiveLearning.setSelected(true); - - pasiveLearning.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - projectInfo.getLearning().setFeatureSelection(PASSIVELEARNING); - hasChanged=true; - updateClassifier(); - } - }); - - activeLearning.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - projectInfo.getLearning().setFeatureSelection(ACTIVELEARNING); - hasChanged=true; - updateClassifier(); - } - }); - - final int xOffsetCol2=370; - - ///////////////////////////// - JPanel featurePanel = new JPanel(); - featurePanel.setBorder(BorderFactory.createTitledBorder("Feature Selection")); - featurePanel.setBounds(xOffsetCol2, 20, 200, 150); - - - JScrollPane classScrolPanel = new JScrollPane(featurePanel); - classScrolPanel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - - featureSelList.setBackground(Color.WHITE); - featureSelList.setSelectedIndex(0); - featureSelList.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent evt) { - - String fv=""; - //System.out.println("Learning: Feature selection: " + fv); - TreeMap hm=learningManager.getFeatureSelMap(); - - int ind=featureSelList.getSelectedIndex(); - //System.out.println(ind); - - Iterator> iter=hm.entrySet().iterator(); - List> result = new ArrayList<>(); - while (iter.hasNext()){ - result.add(iter.next()); - } - Entry ee=result.get(ind); - fv=ee.getKey(); - System.out.println("Learning: Feature selection: " + fv); - projectInfo.getLearning().setLearningOption(fv); - - hasChanged=true; - updateClassifier(); - - } - }); - - //classScrolPanel.add(featureSelList); - featurePanel.add(featureSelList); - learningJPanel.add(classScrolPanel); - - //////////////////////////// - JPanel IOpanel = new JPanel(); - IOpanel.setBackground(Color.GRAY); - IOpanel.setBounds(xOffsetCol2, 200, 200, 80); - - IOpanel.add(addButton("Save", null, xOffsetCol2, 120, 200, 50, SAVE_BUTTON_PRESSED)); - - IOpanel.add(addButton("Load", null, xOffsetCol2+200+100, 200, 450, 50, LOAD_BUTTON_PRESSED)); - - aPanel.add(learningJPanel); - aPanel.add(featurePanel); - aPanel.add(IOpanel); - // aPanel.add(options); - - add(aPanel); - setVisible(true); - setResizable(false); - } - - /** - * @param model - */ - private void featureSelectionUI(DefaultListModel model) { - //model.addElement("NONE"); - TreeMap compset=learningManager.getFeatureSelMap(); - Set set=compset.keySet(); - for (String s:set) { - final String s2=compset.get(s).getName(); - model.addElement(s2); - } - } - - /** - * - * @return - */ - private void updateClassifier() { - System.out.println("Learning panel: in updateClassifier"); - Object c = wekaClassifierEditor.getValue(); - //String options = "updateClassifier: default options "; - String[] optionsArray = ((OptionHandler)c).getOptions(); - System.out.println(""+defaultOptions); - - try { - // TODO change into loadClass from TestLoadClass - final AbstractClassifier cls = (AbstractClassifier)c.getClass().newInstance(); - cls.setOptions(optionsArray); - - final LearningInfo li=projectInfo.getLearning(); - li.setClassifier(cls); - li.updateOptionList(); - hasChanged=true; - aclass= cls; - } catch (Exception ex) { - ex.printStackTrace(); - } - - } - - private JButton addButton(String label, ImageIcon icon, int x, int y, int width, int height, final ActionEvent action) { - JButton button = new JButton(label, icon); - button.setFont(labelFONT); - button.setBorderPainted(false); - button.setFocusPainted(false); - button.setBackground(buttonBGColor); - button.setForeground(buttonColor); - button.setBounds(x, y, width, height); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - doAction(action); - } - }); - return button; - } -} +package activeSegmentation.gui; + + +import java.awt.Color; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; + +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.ImageIcon; + +import activeSegmentation.ASCommon; +import activeSegmentation.learning.ClassifierManager; +import activeSegmentation.learning.weka.WekaClassifier; +import weka.classifiers.AbstractClassifier; +import weka.classifiers.Classifier; +import weka.core.OptionHandler; +import weka.core.Utils; +import weka.gui.GenericObjectEditor; +import weka.gui.PropertyPanel; + +import activeSegmentation.IClassifier; +import activeSegmentation.IDataSet; +import activeSegmentation.IFeatureSelection; +import activeSegmentation.prj.LearningInfo; +import activeSegmentation.prj.ProjectInfo; +import activeSegmentation.prj.ProjectManager; + +/** + * Panel for configuring the machine learning classifier used during + * the Active Segmentation training pipeline. + * + *

This is a Weka-specific panel; it is intentional that Weka classes + * are exposed at this level.

+ * + * @author Sumit Vohra, Dimiter Prodanov + */ +public class LearningPanel extends JFrame implements Runnable, ASCommon { + + // Platform-level variables + private ProjectManager projectManager; + private ProjectInfo projectInfo; + private JList featureSelList; + + // Class-specific variables + private String defaultOptions = ""; + private String defaultClassifierName = ""; + private boolean hasChanged = false; + + private final ActionEvent LOAD_BUTTON_PRESSED = new ActionEvent(this, 1, "Load"); + private final ActionEvent SAVE_BUTTON_PRESSED = new ActionEvent(this, 2, "Save"); + private ClassifierManager learningManager; + + // Weka-specific variables + private AbstractClassifier aclass = null; + private GenericObjectEditor wekaClassifierEditor; + + /** + * Constructs a {@code LearningPanel} and initialises the Weka classifier + * editor and feature selection list. + * + * @param projectManager the active {@link ProjectManager} instance + * @param learningManager the {@link ClassifierManager} managing classifiers + */ + public LearningPanel(ProjectManager projectManager, ClassifierManager learningManager) { + this.projectManager = projectManager; + this.learningManager = learningManager; + this.projectInfo = projectManager.getMetaInfo(); + try { + this.wekaClassifierEditor = new GenericObjectEditor(); + } catch (Exception ex) { + ex.printStackTrace(); + } + DefaultListModel model = new DefaultListModel<>(); + featureSelectionUI(model); + featureSelList = new JList<>(model); + } + + /** + * Handles button-press actions for Save and Load operations. + * + *

Note: {@link ActionEvent#equals(Object)} is used for comparison + * instead of reference equality ({@code ==}) to ensure correct dispatch + * regardless of how the event object was constructed.

+ * + * @param event the {@link ActionEvent} to dispatch + */ + public void doAction(ActionEvent event) { + if (event.equals(SAVE_BUTTON_PRESSED)) { + updateClassifier(); + if (aclass != null) { + IClassifier classifier = new WekaClassifier(aclass); + learningManager.setClassifier(classifier); + learningManager.saveLearningMetaData(); + projectManager.updateMetaInfo(projectInfo); + + // Avoid data creep when changing the learning method + IDataSet data = projectManager.getDataSet(); + if (data != null) + data.delete(); + } + } // end SAVE + + if (event.equals(LOAD_BUTTON_PRESSED)) { + LearningInfo li = learningManager.getLearningMetaData(); + String[] options = li.getOptionsArray(); + String cname = li.getClassifierName(); + + try { + if (!cname.isEmpty()) { + aclass = (AbstractClassifier) Class.forName(cname).newInstance(); + IClassifier classifier = new WekaClassifier(aclass); + learningManager.setClassifier(classifier); + wekaClassifierEditor.setClassType(Classifier.class); + wekaClassifierEditor.setValue(aclass); + aclass.setOptions(options); + defaultOptions = Utils.joinOptions(options); + } + } catch (Exception e) { + e.printStackTrace(); + } + } // end LOAD + } + + @Override + public void run() { + showPanel(); + } + + /** + * Builds and displays the learning configuration panel. + */ + private void showPanel() { + setTitle("Learning"); + setIconImage(Toolkit.getDefaultToolkit().getImage( + LearningPanel.class.getResource("logo.png"))); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + getContentPane().setBackground(Color.GRAY); + setLocationRelativeTo(null); + setSize(600, 300); + + final int xOffsetCol1 = 10; + + JPanel aPanel = new JPanel(); + aPanel.setLayout(null); + aPanel.setBackground(Color.GRAY); + + JPanel learningJPanel = new JPanel(); + learningJPanel.setBorder(BorderFactory.createTitledBorder("Learning")); + + PropertyPanel wekaCEPanel = new PropertyPanel(wekaClassifierEditor); + wekaClassifierEditor.setClassType(Classifier.class); + wekaClassifierEditor.setValue(learningManager.getClassifier()); + Object c = wekaClassifierEditor.getValue(); + defaultOptions = ""; + defaultClassifierName = c.getClass().getName(); + + if (c instanceof OptionHandler) { + defaultOptions = Utils.joinOptions(((OptionHandler) c).getOptions()); + } + + wekaCEPanel.setBounds(30, 30, 250, 30); + learningJPanel.add(wekaCEPanel); + learningJPanel.setBounds(xOffsetCol1, 20, 300, 150); + + JPanel options = new JPanel(); + options.setBorder(BorderFactory.createTitledBorder("Learning Options")); + options.setBounds(xOffsetCol1, 120, 300, 120); + + JRadioButton pasiveLearning = new JRadioButton("Passive Learning"); + JRadioButton activeLearning = new JRadioButton("Active Learning"); + ButtonGroup bg = new ButtonGroup(); + bg.add(pasiveLearning); + bg.add(activeLearning); + options.add(pasiveLearning); + options.add(activeLearning); + pasiveLearning.setSelected(true); + + pasiveLearning.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + projectInfo.getLearning().setFeatureSelection(PASSIVELEARNING); + hasChanged = true; + updateClassifier(); + } + }); + + activeLearning.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + projectInfo.getLearning().setFeatureSelection(ACTIVELEARNING); + hasChanged = true; + updateClassifier(); + } + }); + + final int xOffsetCol2 = 370; + + JPanel featurePanel = new JPanel(); + featurePanel.setBorder(BorderFactory.createTitledBorder("Feature Selection")); + featurePanel.setBounds(xOffsetCol2, 20, 200, 150); + + JScrollPane classScrolPanel = new JScrollPane(featurePanel); + classScrolPanel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + + featureSelList.setBackground(Color.WHITE); + featureSelList.setSelectedIndex(0); + featureSelList.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent evt) { + TreeMap hm = learningManager.getFeatureSelMap(); + int ind = featureSelList.getSelectedIndex(); + + Iterator> iter = hm.entrySet().iterator(); + List> result = new ArrayList<>(); + while (iter.hasNext()) { + result.add(iter.next()); + } + Entry ee = result.get(ind); + String fv = ee.getKey(); + projectInfo.getLearning().setLearningOption(fv); + hasChanged = true; + updateClassifier(); + } + }); + + featurePanel.add(featureSelList); + learningJPanel.add(classScrolPanel); + + JPanel IOpanel = new JPanel(); + IOpanel.setBackground(Color.GRAY); + IOpanel.setBounds(xOffsetCol2, 200, 200, 80); + + IOpanel.add(addButton("Save", null, xOffsetCol2, 120, 200, 50, SAVE_BUTTON_PRESSED)); + IOpanel.add(addButton("Load", null, xOffsetCol2 + 200 + 100, 200, 450, 50, LOAD_BUTTON_PRESSED)); + + aPanel.add(learningJPanel); + aPanel.add(featurePanel); + aPanel.add(IOpanel); + + add(aPanel); + setVisible(true); + setResizable(false); + } + + /** + * Populates the feature selection list from the classifier manager. + * + * @param model the {@link DefaultListModel} to populate + */ + private void featureSelectionUI(DefaultListModel model) { + TreeMap compset = learningManager.getFeatureSelMap(); + Set set = compset.keySet(); + for (String s : set) { + final String s2 = compset.get(s).getName(); + model.addElement(s2); + } + } + + /** + * Reads the current classifier configuration from the Weka editor and + * updates the project's {@link LearningInfo} accordingly. + */ + private void updateClassifier() { + Object c = wekaClassifierEditor.getValue(); + String[] optionsArray = ((OptionHandler) c).getOptions(); + + try { + final AbstractClassifier cls = (AbstractClassifier) c.getClass().newInstance(); + cls.setOptions(optionsArray); + + final LearningInfo li = projectInfo.getLearning(); + li.setClassifier(cls); + li.updateOptionList(); + hasChanged = true; + aclass = cls; + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * Creates and returns a styled {@link JButton} with the given properties. + * + * @param label button text + * @param icon optional button icon + * @param x x position (absolute layout) + * @param y y position (absolute layout) + * @param width button width + * @param height button height + * @param action the {@link ActionEvent} to dispatch on click + * @return a configured {@link JButton} + */ + private JButton addButton(String label, ImageIcon icon, int x, int y, + int width, int height, final ActionEvent action) { + JButton button = new JButton(label, icon); + button.setFont(labelFONT); + button.setBorderPainted(false); + button.setFocusPainted(false); + button.setBackground(buttonBGColor); + button.setForeground(buttonColor); + button.setBounds(x, y, width, height); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + doAction(action); + } + }); + return button; + } +} From 010cf3f22de0a8d84aa48820781aaac51e821cf8 Mon Sep 17 00:00:00 2001 From: AmlanDalai Date: Tue, 10 Mar 2026 16:26:10 +0530 Subject: [PATCH 2/2] docs: add comprehensive UI audit report for ASP/IJ panels --- docs/UI_AUDIT.md | 304 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 docs/UI_AUDIT.md diff --git a/docs/UI_AUDIT.md b/docs/UI_AUDIT.md new file mode 100644 index 00000000..600efc57 --- /dev/null +++ b/docs/UI_AUDIT.md @@ -0,0 +1,304 @@ +# UI Audit Report — Active Segmentation Plugin (ASP/IJ) + +**Audit conducted by:** Amlan Dalai +**Date:** March 2026 +**Tool:** Eclipse IDE with WindowBuilder Swing Designer +**Repository:** https://github.com/sumit3203/ACTIVESEGMENTATION + +--- + +## 1. Overview + +This document presents a comprehensive audit of the graphical user interface +of the Active Segmentation Plugin for ImageJ (ASP/IJ), conducted as part of +GSoC 2026 preparation. The goal is to identify UI issues and establish a +baseline for the planned UI modernization effort using WindowBuilder for Eclipse. + +--- + +## 2. Summary + +| Metric | Value | +|--------|-------| +| Total GUI files audited | 10 | +| Files using `setLayout(null)` | 6 | +| Inline `Font` declarations bypassing ASCommon | 17 | +| Inline `Color` declarations bypassing ASCommon | 5 | +| WindowBuilder-fully-compatible panels | 2 / 10 | +| `ActionEvent ==` bug occurrences | 10+ | +| `System.out.println` debug logs in production | 15+ | +| Navigation panels (old + new) | 2 (GuiPanel, UIPanel) | + +--- + +## 3. Panel-by-Panel Analysis + +### 3.1 UIPanel.java — PRIMARY TARGET ⚠️ + +**Author:** Dimiter Prodanov (mentor) +**Purpose:** Primary navigation dashboard — newer experimental design +**WindowBuilder:** ✅ All components visible in Design view + +**Issues found:** +- `setLayout(null)` with hardcoded `setBounds()` coordinates +- 6 inline `new Font("Tahoma")` declarations — inconsistent with + `ASCommon` which defines `"Arial"` fonts throughout +- 4 `System.out.println` debug statements in constructor +- No button background/foreground styling (missing `buttonBGColor`) +- Missing buttons compared to GuiPanel: Visualization, Back, Exit + (pending mentor confirmation on intended button set) + +**Priority:** High — this is the target design direction + +--- + +### 3.2 GuiPanel.java — LEGACY ✅ PARTIALLY FIXED + +**Purpose:** Legacy navigation dashboard (older design) +**WindowBuilder:** ✅ All components visible (fixed in PR #98) + +**Issues fixed:** +- Replaced `setLayout(null)` with `GridBagLayout` ✅ +- Named button fields for WindowBuilder compatibility ✅ +- Removed `System.out.println` debug statements ✅ +- Fixed `ActionEvent ==` comparison bug ✅ +- Fixed missing `SessionGUI.setVisible(true)` ✅ +- Added Javadoc ✅ + +--- + +### 3.3 FeaturePanel.java — COMPLEX ❌ + +**Purpose:** Main interaction panel for feature extraction and ROI labeling +**WindowBuilder:** ❌ Complete parsing failure — 0 components visible + +**Issues found:** +- Extends `ImageWindow` (ImageJ class) — intentional, required for + live image canvas; cannot be changed to `JFrame` +- UI built inside `showPanel()` method, not in constructor +- `setLayout(null)` on line 198 +- 3 inline `Font` declarations +- Complex conditional UI construction spread across 10+ private methods +- 998 lines — largest GUI file in the codebase + +**Note:** The `ImageWindow` architecture is intentional and must be preserved. +Only safe targeted fixes (inline fonts, debug logs) are appropriate here. + +**Priority:** Medium — targeted fixes only, no architectural changes + +--- + +### 3.4 SessionGUI.java ⚠️ + +**Purpose:** Session management panel — view/delete training sessions +**WindowBuilder:** Partial parse + +**Issues found:** +- `setLayout(null)` on line 650 +- Locally redefines `labelFONT` — shadows `ASCommon` constant +- Multiple `System.out.println` debug statements + +**Priority:** Medium + +--- + +### 3.5 LearningPanel.java ✅ PARTIALLY FIXED + +**Purpose:** Weka classifier configuration and model training panel +**WindowBuilder:** Partial parse (UI built in `showPanel()` method) + +**Issues fixed:** +- `ActionEvent ==` replaced with `.equals()` ✅ +- `cname != ""` replaced with `!cname.isEmpty()` ✅ +- `System.out.println` debug statements removed ✅ + +**Remaining issues:** +- `setLayout(null)` on line 172 +- UI built in `showPanel()` — not WindowBuilder compatible + +**Priority:** Medium + +--- + +### 3.6 CreateOpenProjectGUI.java ✅ PARTIALLY FIXED + +**Purpose:** Project creation and opening wizard +**WindowBuilder:** Uses `CardLayout` — partial parse + +**Issues fixed:** +- `ActionEvent ==` replaced with `.equals()` for all comparisons ✅ +- `System.out.println` debug statement removed ✅ + +**Remaining issues:** +- `setLayout(null)` in `createProjectPanel()` method +- Form layout not responsive on different screen resolutions + +**Priority:** Medium + +--- + +### 3.7 FilterPanel.java ⚠️ + +**Purpose:** Filter selection and configuration panel +**WindowBuilder:** Partial parse + +**Issues found:** +- `setLayout(null)` on lines 105, 188, 256 +- 2 inline `new Color` declarations +- JavaFX dependency (`import javafx.*`) causing compilation + errors when JavaFX SDK is not on the build path + +**Priority:** Medium + +--- + +### 3.8 ViewFilterOutputPanel.java ⚠️ + +**Purpose:** Filter output visualization with ROI overlay support +**WindowBuilder:** Partial parse + +**Issues found:** +- `setLayout(null)` on line 204 +- 4 inline `Font` declarations bypassing ASCommon +- 1 inline `Color` declaration + +**Priority:** Medium + +--- + +### 3.9 VisualizationPanel.java ⚠️ + +**Purpose:** ROC curve and precision-recall visualization panel +**WindowBuilder:** Partial parse + +**Issues found:** +- Locally redefines `labelFONT` — shadows `ASCommon` constant +- Locally redefines `buttonBGColor` with same value as `ASCommon` +- 1 inline `Font` declaration + +**Priority:** Low + +--- + +### 3.10 EvaluationPanel.java ✅ ACCEPTABLE + +**Purpose:** Model evaluation panel — wraps Weka Explorer UI +**WindowBuilder:** Partial parse — frame visible, no inner components + +**Analysis:** +- UI built in `showPanel()` called from constructor +- No `setLayout(null)` ✅ +- No inline Font or Color declarations ✅ +- Does not implement `ASCommon` interface +- Weka Explorer manages its own UI internally — blank + WindowBuilder parse is expected and not a problem + +**Priority:** Low — Weka Explorer UI is intentionally delegated + +--- + +## 4. ASCommon Design System Analysis + +### 4.1 Current Constants (ASCommon.java) +```java +// Fonts +Font mediumFONT = new Font("Arial", Font.BOLD, 16); +Font labelFONT = new Font("Arial", Font.BOLD, 13); +Font panelFONT = new Font("Arial", Font.BOLD, 10); +Font FONT = new Font("Arial", Font.PLAIN, 10); +Font largeFONT = new Font("Arial", Font.BOLD, 32); + +// Colors +Color buttonColor = Color.BLUE; +Color buttonBGColor = new Color(192, 192, 192); +Color panelColor = Color.GRAY; +``` + +### 4.2 Problems + +1. **Incomplete** — no small font, no standard button dimensions +2. **Ignored by UIPanel** — uses `"Tahoma"` instead of `"Arial"` +3. **Shadowed locally** — `SessionGUI` and `VisualizationPanel` + redefine constants locally instead of using the interface + +### 4.3 Proposed Extensions +```java +// Additional fonts needed +Font smallFONT = new Font("Arial", Font.PLAIN, 11); +Font titleFONT = new Font("Arial", Font.BOLD, 24); + +// Standard dimensions +int BUTTON_HEIGHT = 35; +int BUTTON_WIDTH = 150; +int PANEL_PADDING = 10; + +// Additional colors +Color ACCENT_COLOR = Color.ORANGE; +Color PANEL_BG = new Color(240, 240, 240); +``` + +--- + +## 5. Bug Summary + +### Bug 1 — ActionEvent Reference Comparison +**Severity:** Medium +**Files affected:** GuiPanel, LearningPanel, CreateOpenProjectGUI +**Description:** `ActionEvent` objects compared using `==` (reference +equality) instead of `.equals()`. Can cause button actions to silently +fail under certain JVM conditions. +**Status:** Fixed in PRs #97, #100, #101 ✅ + +### Bug 2 — SessionGUI Never Visible +**Severity:** High +**File:** GuiPanel.java +**Description:** `SessionGUI` instance created in `doAction()` but +`setVisible(true)` never called — panel never appears on screen. +**Status:** Fixed in PR #95 ✅ + +### Bug 3 — UIPanel Uses Wrong Font Family +**Severity:** Low +**File:** UIPanel.java +**Description:** 6 inline `new Font("Tahoma")` declarations override +the `ASCommon` design system which standardizes on `"Arial"`. +**Status:** Pending + +--- + +## 6. WindowBuilder Compatibility Rules + +Based on analysis of working vs broken panels, the following rules +ensure full WindowBuilder compatibility: + +1. UI must be built in the constructor — not in `showPanel()` or + other helper methods +2. Components must be assigned to named instance fields — not + local variables or factory method return values +3. Each component needs its own `GridBagConstraints` instance — + sharing a single instance causes parsing failures +4. No conditional UI construction — WindowBuilder cannot parse + `if/else` blocks that add different components + +--- + +## 7. Recommended Fix Priority + +| Priority | Panel | Fix Required | +|----------|-------|-------------| +| 1 | UIPanel | Replace `setLayout(null)` → `GridBagLayout`, fix fonts, add missing buttons | +| 2 | SessionGUI | Replace `setLayout(null)`, fix local font redefinition | +| 3 | LearningPanel | Replace `setLayout(null)`, move UI to constructor | +| 4 | CreateOpenProjectGUI | Replace form layout with `GridBagLayout` | +| 5 | ViewFilterOutputPanel | Replace `setLayout(null)`, fix inline fonts | +| 6 | FilterPanel | Replace `setLayout(null)`, fix inline colors | +| 7 | VisualizationPanel | Fix local constant redefinitions | +| 8 | FeaturePanel | Targeted fixes only — preserve `ImageWindow` architecture | + +--- + +## 8. References + +- [GSoC 2026 Project Idea #26](https://summerofcode.withgoogle.com) +- [Eclipse WindowBuilder Documentation](https://www.eclipse.org/windowbuilder/) +- [ImageJ Plugin Development Guide](https://imagej.nih.gov/ij/developer/) +- [Active Segmentation Research Paper](https://pmc.ncbi.nlm.nih.gov/articles/PMC8699732/)