source: java/main/src/main/java/com/framsticks/gui/Frame.java @ 100

Last change on this file since 100 was 100, checked in by psniegowski, 11 years ago

HIGHLIGHTS:

  • add <include/> to configuration
  • add side notes to tree
    • used to store arbitrary information alongside the tree structure
  • migrate to log4j2
    • supports lazy string evaluation of passed arguments
  • improve GUI tree
    • it stays in synchronization with actual state (even in high load test scenario)
  • improve panel management in GUI
  • make loading objects in GUI more lazy
  • offload parsing to connection receiver thread
    • info parsing
    • first step of objects parsing
  • fix connection parsing bug (eof in long values)
  • support zero-arguments procedure in table view

CHANGELOG:
Implement procedure calls from table view.

Refactorization around procedures in tables.

Add table editor for buttons.

Render buttons in the the list view.

Further improve Columns.

Add Column class for TableModel?.

Accept also non-arguments ProcedureParams? in tableView.

Increase maximal TextAreaControl? size.

Add tooltip to ProcedureControl?.

Fix bug of interpreting eofs in long values by connection reader.

Further rework connection parsing.

Simplify client connection processing.

Test ListChange? modification.

Test ListChange? events with java server.

Add TestChild?.

Fix bug with fast deregistering when connecting to running server.

Another minor refactorization in TreeOperations?.

Fix bug in SimpleAbstractAccess? loading routine.

Another minor improvement.

Minor change.

Make reading of List objects two-phase.

Another minor change.

Dispatch parsing into receiver thread.

Another step.

Enclose passing value in ObjectParam? case in closure.

Minor step.

Minor change on way to offload parsing.

Temporarily comment out single ValueParam? get.

It will be generalized to multi ValueParam?.

Process info in receiver thread.

Add DispatchingExceptionHandler?.

Make waits in browser test longer.

Use FETCHED_MARK.

It is honored in GUI, where it used to decide whether to get values

after user action.

It is set in standard algorithm for processing fetched values.

Add remove operation to side notes.

Make loading more lazy.

Improve loading policy.

On node choose load itself, on node expansion, load children.

Minor improvement.

Fix bug with panel interleaving.

Minor improvements.

Improve panel management.

More cleaning around panels.

Reorganize panels.

Further improve tree.

Fix bug in TreeModel?.

Remove children from TreeNode?.

Implement TreeNode? hashCode and equals.

Make TreeNode? delegate equals and hashcode to internal reference.

Move listeners from TreeNode? to side notes.

Store path.textual as a side note.

Side note params instead of accesses for objects.

More refactorizations.

In TreeNode? bindAccess based on side notes.

Minor step.

Hide createAccess.

Rename AccessInterface? to Access.

Minor changes.

Several improvements in high load scenarios.

Change semantics of ArrayListAccess?.set(index, null);

It now removes the element, making list shorter
(it was set to null before).

Add path remove handler.

Handle exceptions in Connection.

Update .gitignore

Configure logging to file.

Move registration to TreeModel?.

Further refactorization.

Minor refactorization.

Minor improvements.

Use specialized event also for Modify action of ListChange?.

Use remove events.

Use the insertion events for tree.

Further improve tree refreshing.

Further improve reacting on events in GUI.

Fix problem with not adding objects on addition list change.

Migrate to log4j lazy String construction interface.

Migrate imports to log4j2.

Drop dependency on adapter to version 1.2.

Switch log4j implementation to log4j2.

Add dirty mark to the NodeAtFrame?.

Make selecting in AccessInterfaces? type safe.

Ignore containers size settings in Model and Genotype.

Use tree side notes to remember local changes and panels.

Add sideNotes to tree.

They will be used to store various accompanying information
right in the tree.

Use ReferenceIdentityMap? from apache in TreeNode?.

It suits the need perfectly (weak semantics on both key and value).

Make ArrayListParam? do not react size changes.

Guard in TableModel? before not yet loaded objects.

Add <include/> clause and AutoInjector?.

Extract common columns configuration to separate xml,
that can be included by other configurations.

File size: 11.5 KB
RevLine 
[77]1package com.framsticks.gui;
2
[97]3import java.awt.BorderLayout;
4import java.awt.CardLayout;
5import java.awt.Color;
6import java.awt.Container;
7import java.awt.Dimension;
8import java.awt.Toolkit;
9import java.awt.event.ActionEvent;
10import java.awt.event.KeyEvent;
11import java.awt.event.MouseAdapter;
12import java.awt.event.MouseEvent;
[98]13import java.util.IdentityHashMap;
[97]14import java.util.Map;
[88]15
[97]16import javax.swing.AbstractAction;
17import javax.swing.BorderFactory;
18import javax.swing.JComponent;
19import javax.swing.JMenu;
20import javax.swing.JMenuBar;
21import javax.swing.JMenuItem;
22import javax.swing.JPanel;
23import javax.swing.JPopupMenu;
24import javax.swing.JScrollPane;
25import javax.swing.JSplitPane;
26import javax.swing.JTree;
27import javax.swing.KeyStroke;
28import javax.swing.ToolTipManager;
29import javax.swing.UIManager;
[98]30import javax.swing.event.TreeExpansionEvent;
31import javax.swing.event.TreeExpansionListener;
[77]32import javax.swing.event.TreeSelectionEvent;
33import javax.swing.event.TreeSelectionListener;
[97]34import javax.swing.tree.DefaultTreeSelectionModel;
35import javax.swing.tree.TreePath;
36import javax.swing.tree.TreeSelectionModel;
[84]37
[100]38import org.apache.logging.log4j.Logger;
39import org.apache.logging.log4j.LogManager;
[97]40
41import com.framsticks.core.Path;
42import com.framsticks.core.Tree;
[100]43import com.framsticks.gui.tree.AbstractNode;
[99]44import com.framsticks.gui.tree.MetaNode;
45import com.framsticks.gui.tree.TreeCellRenderer;
46import com.framsticks.gui.tree.TreeModel;
47import com.framsticks.gui.tree.TreeNode;
[97]48import com.framsticks.util.dispatching.Dispatching;
[98]49import com.framsticks.util.dispatching.FutureHandler;
[97]50import com.framsticks.util.dispatching.Joinable;
51import com.framsticks.util.dispatching.JoinableCollection;
52import com.framsticks.util.dispatching.JoinableParent;
53import com.framsticks.util.dispatching.JoinableState;
[100]54import com.framsticks.util.lang.Casting;
[97]55import com.framsticks.util.swing.KeyboardModifier;
56import com.framsticks.util.swing.MenuConstructor;
[77]57
58/**
59 * @author Piotr Sniegowski
60 */
[84]61@SuppressWarnings("serial")
[97]62public class Frame extends FrameJoinable implements JoinableParent {
[77]63
[100]64        private static final Logger log = LogManager.getLogger(Frame.class.getName());
[77]65
[84]66        protected final Browser browser;
[77]67
[88]68        protected final Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
[77]69
[88]70        protected CardLayout cardPanelLayout;
71        protected JPanel cardPanel;
[77]72
[84]73        protected JScrollPane treeScrollPane;
[97]74        protected JTree jtree;
[98]75        protected TreeModel treeModel;
76
77        protected MetaNode rootNode;
78
[84]79        protected JPanel treePanel;
80        protected JPopupMenu treePopupMenu;
81        protected JMenuItem treePopupMenuHeader;
[77]82
[84]83        protected JPanel mainPanel;
84        protected JPanel leftPanel;
85        protected JPanel normalWorkPanel;
86        protected CardLayout mainPanelLayout;
[77]87
[84]88        protected JMenuBar menuBar;
89        protected JMenu fileMenu;
90        protected JMenu editMenu;
91        protected JMenu viewMenu;
92        protected JMenu windowMenu;
93        protected JMenu helpMenu;
[100]94        protected EmptyPanel emptyPanel;
[77]95
[98]96        protected final Map<Tree, TreeAtFrame> treeAtFrames = new IdentityHashMap<>();
97        protected JoinableCollection<Tree> trees = new JoinableCollection<>();
[77]98
[97]99        public Frame(Browser browser) {
[88]100                this.browser = browser;
101        }
102
[97]103        protected void initializeGui() {
104                super.initializeGui();
[84]105                /** this is done to remove the current value label from above the slider,
106                 * because it cannot put to work properly with floating-point value sliders,
107                 * nor it can be removed in normal way through JSlider methods  */
108                UIManager.put("Slider.paintValue", false);
[100]109                log.debug("creating {}", this);
[77]110
[100]111                cardPanel = new JPanel();
112                cardPanel.setName("card");
113
114                cardPanelLayout = new CardLayout();
115                cardPanel.setLayout(cardPanelLayout);
116
117                emptyPanel = new EmptyPanel(this);
118
[97]119                Container contentPane = getSwing().getContentPane();
[84]120                treePopupMenu = new JPopupMenu("title");
121                treePopupMenu.setName("popup");
[77]122
[84]123                treePanel = new JPanel();
124                treePanel.setLayout(new BorderLayout());
125
[100]126                rootNode = new MetaNode(this);
[98]127                rootNode.setName("root");
128                treeModel = new TreeModel(this);
[84]129
[97]130                jtree = new JTree(treeModel);
131                jtree.setName("tree");
132                jtree.setRootVisible(false);
133                jtree.setExpandsSelectedPaths(true);
134                jtree.setSelectionModel(new DefaultTreeSelectionModel());
135                ToolTipManager.sharedInstance().registerComponent(jtree);
[77]136
[97]137                jtree.addTreeSelectionListener(new TreeSelectionListener() {
[84]138                        @Override
139                        public void valueChanged(TreeSelectionEvent e) {
[99]140                                treeModel.chooseTreeNode(e.getNewLeadSelectionPath());
[84]141                        }
142                });
[77]143
[98]144                jtree.addTreeExpansionListener(new TreeExpansionListener() {
145
146                        @Override
147                        public void treeCollapsed(TreeExpansionEvent e) {
148
149                        }
150
151                        @Override
152                        public void treeExpanded(TreeExpansionEvent e) {
[100]153                                treeModel.expandTreeNode(e.getPath());
[98]154                        }
155                });
156
[97]157                jtree.setExpandsSelectedPaths(true);
158                jtree.setEditable(false);
159                jtree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
160                jtree.setShowsRootHandles(true);
161                jtree.setRowHeight(26);
162                jtree.setDoubleBuffered(true);
163                jtree.addMouseListener(new MouseAdapter() {
[84]164                        @Override
165                        public void mousePressed(MouseEvent e) {
166                                assert isActive();
167                                showPopup(e);
168                        }
[77]169
[84]170                        @Override
171                        public void mouseReleased(MouseEvent e) {
172                                assert isActive();
173                                showPopup(e);
174                        }
175                });
[77]176
[98]177                new KeyboardModifier(jtree, JComponent.WHEN_FOCUSED)
178                        .join(KeyStroke.getKeyStroke('h'), KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0))
179                        .join(KeyStroke.getKeyStroke('j'), KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0))
180                        .join(KeyStroke.getKeyStroke('k'), KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0))
181                        .join(KeyStroke.getKeyStroke('l'), KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
[77]182
[100]183                jtree.setCellRenderer(new TreeCellRenderer(treeModel));
[77]184
[97]185                treeScrollPane = new JScrollPane(jtree);
[84]186                treeScrollPane.setBorder(BorderFactory.createEmptyBorder());
[77]187
[84]188                treePanel.add(treeScrollPane);
[77]189
190
[84]191                normalWorkPanel = new JPanel();
192                normalWorkPanel.setLayout(new BorderLayout());
193                normalWorkPanel.setName("browser");
[77]194
[84]195                mainPanel = new JPanel();
196                mainPanel.setName("main");
197                mainPanelLayout = new CardLayout();
198                mainPanel.setLayout(mainPanelLayout);
199                mainPanel.add(normalWorkPanel, "browser");
[77]200
[84]201                menuBar = new JMenuBar();
[77]202
[84]203                fileMenu = menuBar.add(new JMenu("File"));
204                editMenu = menuBar.add(new JMenu("Edit"));
205                viewMenu = menuBar.add(new JMenu("View"));
206                windowMenu = menuBar.add(new JMenu("Window"));
207                helpMenu = menuBar.add(new JMenu("Help"));
[77]208
[84]209                contentPane.add(menuBar, BorderLayout.NORTH);
210                contentPane.add(mainPanel, BorderLayout.CENTER);
[77]211
[84]212                leftPanel = new JPanel();
213                leftPanel.setLayout(new BorderLayout());
214                //leftPanel.add(new ViewerTest(), BorderLayout.PAGE_START);
[88]215                //        JPanel leftTopPanel = createLeftTopPanel();
216                //        if (leftTopPanel != null) {
217                //            leftPanel.add(leftTopPanel, BorderLayout.PAGE_START);
218                //        }
[84]219                leftPanel.add(treePanel, BorderLayout.CENTER);
220                leftPanel.setBackground(Color.WHITE);
221                leftPanel.setForeground(Color.WHITE);
[77]222
[84]223                JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, cardPanel);
224                split.setPreferredSize(browser.defaultFrameDimension);
225                split.setMaximumSize(screenDimension);
226                split.setOneTouchExpandable(true);
227                split.setDividerLocation(250);
228                split.setDividerSize(5);
229                split.setName("split");
[77]230
[84]231                normalWorkPanel.add(split);
[77]232
[84]233                //this.setVisible(true);
234                mainPanelLayout.show(mainPanel, "browser");
[77]235
236
[97]237                getSwing().pack();
238                jtree.requestFocusInWindow();
[77]239
[100]240                log.debug("frame configured: {}", this);
[77]241
[88]242                new MenuConstructor(fileMenu).add(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK), new AbstractAction("Close") {
243                        @Override
244                        public void actionPerformed(ActionEvent actionEvent) {
245                                interrupt();
246                        }
247                });
248
[98]249                new MenuConstructor(fileMenu).add(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.CTRL_MASK), new AbstractAction("Reload current") {
250                        @Override
251                        public void actionPerformed(ActionEvent actionEvent) {
252
[99]253                                treeModel.loadPath(treeModel.convertToPath(jtree.getSelectionPath()), true);
[98]254                        }
255                });
256
[84]257        }
[77]258
[84]259        protected JPanel createLeftTopPanel() {
260                return null;
261        }
[77]262
[98]263        public void addRootPath(final Path path) {
[84]264                assert isActive();
[98]265
[97]266                Tree tree = path.getTree();
[98]267
[100]268                log.debug("trying mount: {}", path);
[98]269                if (!tree.getAssignedRoot().isResolved()) {
[99]270                        tree.get(path, new FutureHandler<Path>(this) {
[98]271
272                                @Override
273                                protected void result(Path result) {
274                                        addRootPath(result);
275                                }
276                        });
277                        return;
278                }
279
[97]280                assert browser.getTrees().contains(tree);
[77]281
[97]282                TreeAtFrame e = new TreeAtFrame(tree, this);
283                treeAtFrames.put(tree, e);
[100]284                Path rootPath = Path.to(tree, "/");
[98]285
[100]286                rootNode.getChildren().add(new TreeNode(e, rootPath));
[98]287                e.rootNode = tree.getAssignedRoot();
[100]288                treeModel.treeStructureChanged(new TreePath(rootNode));
[98]289                // jtree.expandPath(new TreePath(rootNode));
[84]290        }
[77]291
292
[100]293        public void showPanel(AbstractPanel panel) {
[84]294                assert isActive();
295                assert panel != null;
[100]296                log.debug("showing panel: {}", panel);
[84]297                cardPanelLayout.show(cardPanel, panel.getUniqueName());
[100]298
299                // cardPanel.revalidate();
[84]300        }
[77]301
[98]302
[84]303        private void showPopup(MouseEvent e) {
304                assert isActive();
305                if (!e.isPopupTrigger()) {
306                        return;
307                }
[98]308                TreePath treePath = jtree.getPathForLocation(e.getX(), e.getY());
[97]309
[98]310                Path path = treeModel.convertToPath(treePath);
[100]311                if (path == null) {
312                        return;
313                }
[97]314                treePopupMenu.removeAll();
315
316                for (PopupMenuEntryProvider provider : browser.popupMenuEntryProviders) {
317                        provider.provide(treePopupMenu, path);
318                }
[84]319                treePopupMenu.show(e.getComponent(), e.getX(), e.getY());
320        }
[77]321
[84]322        public void clear() {
323                cardPanel.removeAll();
324                cardPanel.updateUI();
[97]325                jtree.setEnabled(false);
[84]326        }
[77]327
[100]328        public void updatePanelIfIsLeadSelection(Path path) {
[99]329                assert isActive();
[100]330                TreePath treePath = treeModel.convertToTreePath(path, true);
331                if (treePath == null) {
332                        return;
333                }
[99]334                if (treePath.equals(jtree.getSelectionPath())) {
[100]335                        log.debug("updating: {} -> {}", treePath, path);
336                        showPanelForTreePath(treePath);
[98]337                }
338        }
339
[100]340        public void showPanelForTreePath(TreePath treePath) {
341                assert isActive();
342                AbstractNode node = Casting.assertCast(AbstractNode.class, treePath.getLastPathComponent());
[98]343
[100]344                AbstractPanel panel = node.getPanel();
345                if (panel == null) {
346                        log.error("no panel for {} found", treePath);
347                        return;
348                }
349                panel.fillPanelWith(node);
350                showPanel(panel);
351                // cardPanel.revalidate();
352        }
[84]353
[100]354
355
[98]356        // public void goTo(Path path) {
357        //      assert isActive();
358        //      final TreePath treePath = treeModel.convertToTreePath(path);
[85]359
[98]360        //      this.dispatch(new RunAt<Frame>(this) {
361        //              @Override
362        //              protected void runAt() {
363        //                      log.info("executed");
364        //                      jtree.setSelectionPath(treePath);
365        //                      jtree.makeVisible(treePath);
366        //                      assert jtree.isVisible(treePath);
367        //              }
368        //      });
[77]369
[98]370        // }
[77]371
[84]372        @Override
373        public String toString() {
[88]374                return title + "@" + browser.getName();
[84]375        }
376
[88]377        @Override
[97]378        protected void joinableStart() {
379                super.joinableStart();
380                Dispatching.use(trees, this);
381        }
382
383        @Override
[88]384        protected void joinableInterrupt() {
[97]385                Dispatching.drop(trees, this);
[88]386                super.joinableInterrupt();
387        }
388
389        @Override
390        protected void joinableFinish() {
[97]391                super.joinableFinish();
[88]392        }
393
[97]394        @Override
395        protected void joinableJoin() throws InterruptedException {
396                Dispatching.join(trees);
397                super.joinableJoin();
398        }
[88]399
400        @Override
[97]401        public void childChangedState(Joinable joinable, JoinableState state) {
402                if (joinable == trees) {
403                        proceedToState(state);
404                }
[88]405        }
406
[98]407        /**
[99]408         * @return the jtree
409         */
410        public JTree getJtree() {
411                return jtree;
412        }
413
414        /**
[98]415         * @return the treeModel
416         */
417        public TreeModel getTreeModel() {
418                return treeModel;
419        }
420
[99]421        /**
422         * @return the rootNode
423         */
424        public MetaNode getRootNode() {
425                return rootNode;
426        }
427
428        /**
[100]429         * @return the emptyPanel
430         */
431        public EmptyPanel getEmptyPanel() {
432                return emptyPanel;
433        }
434
435        /**
[99]436         * @return the treeAtFrames
437         */
438        public Map<Tree, TreeAtFrame> getTreeAtFrames() {
439                return treeAtFrames;
440        }
441
[77]442}
Note: See TracBrowser for help on using the repository browser.