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
Line 
1package com.framsticks.gui;
2
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;
13import java.util.IdentityHashMap;
14import java.util.Map;
15
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;
30import javax.swing.event.TreeExpansionEvent;
31import javax.swing.event.TreeExpansionListener;
32import javax.swing.event.TreeSelectionEvent;
33import javax.swing.event.TreeSelectionListener;
34import javax.swing.tree.DefaultTreeSelectionModel;
35import javax.swing.tree.TreePath;
36import javax.swing.tree.TreeSelectionModel;
37
38import org.apache.logging.log4j.Logger;
39import org.apache.logging.log4j.LogManager;
40
41import com.framsticks.core.Path;
42import com.framsticks.core.Tree;
43import com.framsticks.gui.tree.AbstractNode;
44import com.framsticks.gui.tree.MetaNode;
45import com.framsticks.gui.tree.TreeCellRenderer;
46import com.framsticks.gui.tree.TreeModel;
47import com.framsticks.gui.tree.TreeNode;
48import com.framsticks.util.dispatching.Dispatching;
49import com.framsticks.util.dispatching.FutureHandler;
50import com.framsticks.util.dispatching.Joinable;
51import com.framsticks.util.dispatching.JoinableCollection;
52import com.framsticks.util.dispatching.JoinableParent;
53import com.framsticks.util.dispatching.JoinableState;
54import com.framsticks.util.lang.Casting;
55import com.framsticks.util.swing.KeyboardModifier;
56import com.framsticks.util.swing.MenuConstructor;
57
58/**
59 * @author Piotr Sniegowski
60 */
61@SuppressWarnings("serial")
62public class Frame extends FrameJoinable implements JoinableParent {
63
64        private static final Logger log = LogManager.getLogger(Frame.class.getName());
65
66        protected final Browser browser;
67
68        protected final Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
69
70        protected CardLayout cardPanelLayout;
71        protected JPanel cardPanel;
72
73        protected JScrollPane treeScrollPane;
74        protected JTree jtree;
75        protected TreeModel treeModel;
76
77        protected MetaNode rootNode;
78
79        protected JPanel treePanel;
80        protected JPopupMenu treePopupMenu;
81        protected JMenuItem treePopupMenuHeader;
82
83        protected JPanel mainPanel;
84        protected JPanel leftPanel;
85        protected JPanel normalWorkPanel;
86        protected CardLayout mainPanelLayout;
87
88        protected JMenuBar menuBar;
89        protected JMenu fileMenu;
90        protected JMenu editMenu;
91        protected JMenu viewMenu;
92        protected JMenu windowMenu;
93        protected JMenu helpMenu;
94        protected EmptyPanel emptyPanel;
95
96        protected final Map<Tree, TreeAtFrame> treeAtFrames = new IdentityHashMap<>();
97        protected JoinableCollection<Tree> trees = new JoinableCollection<>();
98
99        public Frame(Browser browser) {
100                this.browser = browser;
101        }
102
103        protected void initializeGui() {
104                super.initializeGui();
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);
109                log.debug("creating {}", this);
110
111                cardPanel = new JPanel();
112                cardPanel.setName("card");
113
114                cardPanelLayout = new CardLayout();
115                cardPanel.setLayout(cardPanelLayout);
116
117                emptyPanel = new EmptyPanel(this);
118
119                Container contentPane = getSwing().getContentPane();
120                treePopupMenu = new JPopupMenu("title");
121                treePopupMenu.setName("popup");
122
123                treePanel = new JPanel();
124                treePanel.setLayout(new BorderLayout());
125
126                rootNode = new MetaNode(this);
127                rootNode.setName("root");
128                treeModel = new TreeModel(this);
129
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);
136
137                jtree.addTreeSelectionListener(new TreeSelectionListener() {
138                        @Override
139                        public void valueChanged(TreeSelectionEvent e) {
140                                treeModel.chooseTreeNode(e.getNewLeadSelectionPath());
141                        }
142                });
143
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) {
153                                treeModel.expandTreeNode(e.getPath());
154                        }
155                });
156
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() {
164                        @Override
165                        public void mousePressed(MouseEvent e) {
166                                assert isActive();
167                                showPopup(e);
168                        }
169
170                        @Override
171                        public void mouseReleased(MouseEvent e) {
172                                assert isActive();
173                                showPopup(e);
174                        }
175                });
176
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));
182
183                jtree.setCellRenderer(new TreeCellRenderer(treeModel));
184
185                treeScrollPane = new JScrollPane(jtree);
186                treeScrollPane.setBorder(BorderFactory.createEmptyBorder());
187
188                treePanel.add(treeScrollPane);
189
190
191                normalWorkPanel = new JPanel();
192                normalWorkPanel.setLayout(new BorderLayout());
193                normalWorkPanel.setName("browser");
194
195                mainPanel = new JPanel();
196                mainPanel.setName("main");
197                mainPanelLayout = new CardLayout();
198                mainPanel.setLayout(mainPanelLayout);
199                mainPanel.add(normalWorkPanel, "browser");
200
201                menuBar = new JMenuBar();
202
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"));
208
209                contentPane.add(menuBar, BorderLayout.NORTH);
210                contentPane.add(mainPanel, BorderLayout.CENTER);
211
212                leftPanel = new JPanel();
213                leftPanel.setLayout(new BorderLayout());
214                //leftPanel.add(new ViewerTest(), BorderLayout.PAGE_START);
215                //        JPanel leftTopPanel = createLeftTopPanel();
216                //        if (leftTopPanel != null) {
217                //            leftPanel.add(leftTopPanel, BorderLayout.PAGE_START);
218                //        }
219                leftPanel.add(treePanel, BorderLayout.CENTER);
220                leftPanel.setBackground(Color.WHITE);
221                leftPanel.setForeground(Color.WHITE);
222
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");
230
231                normalWorkPanel.add(split);
232
233                //this.setVisible(true);
234                mainPanelLayout.show(mainPanel, "browser");
235
236
237                getSwing().pack();
238                jtree.requestFocusInWindow();
239
240                log.debug("frame configured: {}", this);
241
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
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
253                                treeModel.loadPath(treeModel.convertToPath(jtree.getSelectionPath()), true);
254                        }
255                });
256
257        }
258
259        protected JPanel createLeftTopPanel() {
260                return null;
261        }
262
263        public void addRootPath(final Path path) {
264                assert isActive();
265
266                Tree tree = path.getTree();
267
268                log.debug("trying mount: {}", path);
269                if (!tree.getAssignedRoot().isResolved()) {
270                        tree.get(path, new FutureHandler<Path>(this) {
271
272                                @Override
273                                protected void result(Path result) {
274                                        addRootPath(result);
275                                }
276                        });
277                        return;
278                }
279
280                assert browser.getTrees().contains(tree);
281
282                TreeAtFrame e = new TreeAtFrame(tree, this);
283                treeAtFrames.put(tree, e);
284                Path rootPath = Path.to(tree, "/");
285
286                rootNode.getChildren().add(new TreeNode(e, rootPath));
287                e.rootNode = tree.getAssignedRoot();
288                treeModel.treeStructureChanged(new TreePath(rootNode));
289                // jtree.expandPath(new TreePath(rootNode));
290        }
291
292
293        public void showPanel(AbstractPanel panel) {
294                assert isActive();
295                assert panel != null;
296                log.debug("showing panel: {}", panel);
297                cardPanelLayout.show(cardPanel, panel.getUniqueName());
298
299                // cardPanel.revalidate();
300        }
301
302
303        private void showPopup(MouseEvent e) {
304                assert isActive();
305                if (!e.isPopupTrigger()) {
306                        return;
307                }
308                TreePath treePath = jtree.getPathForLocation(e.getX(), e.getY());
309
310                Path path = treeModel.convertToPath(treePath);
311                if (path == null) {
312                        return;
313                }
314                treePopupMenu.removeAll();
315
316                for (PopupMenuEntryProvider provider : browser.popupMenuEntryProviders) {
317                        provider.provide(treePopupMenu, path);
318                }
319                treePopupMenu.show(e.getComponent(), e.getX(), e.getY());
320        }
321
322        public void clear() {
323                cardPanel.removeAll();
324                cardPanel.updateUI();
325                jtree.setEnabled(false);
326        }
327
328        public void updatePanelIfIsLeadSelection(Path path) {
329                assert isActive();
330                TreePath treePath = treeModel.convertToTreePath(path, true);
331                if (treePath == null) {
332                        return;
333                }
334                if (treePath.equals(jtree.getSelectionPath())) {
335                        log.debug("updating: {} -> {}", treePath, path);
336                        showPanelForTreePath(treePath);
337                }
338        }
339
340        public void showPanelForTreePath(TreePath treePath) {
341                assert isActive();
342                AbstractNode node = Casting.assertCast(AbstractNode.class, treePath.getLastPathComponent());
343
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        }
353
354
355
356        // public void goTo(Path path) {
357        //      assert isActive();
358        //      final TreePath treePath = treeModel.convertToTreePath(path);
359
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        //      });
369
370        // }
371
372        @Override
373        public String toString() {
374                return title + "@" + browser.getName();
375        }
376
377        @Override
378        protected void joinableStart() {
379                super.joinableStart();
380                Dispatching.use(trees, this);
381        }
382
383        @Override
384        protected void joinableInterrupt() {
385                Dispatching.drop(trees, this);
386                super.joinableInterrupt();
387        }
388
389        @Override
390        protected void joinableFinish() {
391                super.joinableFinish();
392        }
393
394        @Override
395        protected void joinableJoin() throws InterruptedException {
396                Dispatching.join(trees);
397                super.joinableJoin();
398        }
399
400        @Override
401        public void childChangedState(Joinable joinable, JoinableState state) {
402                if (joinable == trees) {
403                        proceedToState(state);
404                }
405        }
406
407        /**
408         * @return the jtree
409         */
410        public JTree getJtree() {
411                return jtree;
412        }
413
414        /**
415         * @return the treeModel
416         */
417        public TreeModel getTreeModel() {
418                return treeModel;
419        }
420
421        /**
422         * @return the rootNode
423         */
424        public MetaNode getRootNode() {
425                return rootNode;
426        }
427
428        /**
429         * @return the emptyPanel
430         */
431        public EmptyPanel getEmptyPanel() {
432                return emptyPanel;
433        }
434
435        /**
436         * @return the treeAtFrames
437         */
438        public Map<Tree, TreeAtFrame> getTreeAtFrames() {
439                return treeAtFrames;
440        }
441
442}
Note: See TracBrowser for help on using the repository browser.