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

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

HIGHLIGHTS:

CHANGELOG:
Make ProcedureParam? hold only ValueParams?.

Use id instead of names when naming gui components internally.

Basic procedure calling in GUI.

The actual procedure call is currently only backed
by the ObjectInstance?.

Add UnimplementedException?.

Improve naming of various gui elements.

Allow easy navigating in FEST Swing testing.

Add optional explicit order attribute to FramsClassAnnotation?.

That's because java reflection does return declared members
in any specific order. That ordering is needed only for
classes that have no representation in framsticks and need
a deterministic ordering of params.

Add ControlOwner? interface.

Add test for procedure calling in Browser.

First version of ParamAnnotation? for procedures.

Development of ProcedureParam?.

Add draft version of ProcedureParam? implementation in ReflectionAccess?.

Allow viewing FramsClasses? in gui Browser.

Extract ResourceBuilder? from ModelBuilder?.

Remove internalId from Param.

It was currently completely not utilised. Whether it is still needed
after introduction of ParamAnnotation? is arguable.

Add remaining param attributes to ParamAnnotation?.

Change AutoBuilder? semantics.

AutoBuilder? returns list of objects that are to be appended
with methods @AutoAppendAnnotation?.

This allows to omit explicit addition of ModelPackage? to instance
if the instance uses ModelBuilder? (registration of ModelPackage? comes
from schema).

Fix params ordering problem in auto created FramsClasses?.

Improve ObjectInstance?.

Several fixes to ModelBuilder?.

Improve test for ObjectInstance? in Browser.

Make initialization of robot static.

With robot recreated for second browser test, the test hanged
deep in AWT.

Add base convenience base test for Browser tests.

More tests to ObjectInstance?.

Rename Dispatcher.invokeLater() to dispatch().

Add assertDispatch.

It allows assertions in other threads, than TestNGInvoker.
Assertions are gathered after each method invocation and rethrown.

Use timeOut annotation attribute for tests involving some waiting.

Remove firstTask method (merge with joinableStart).

Clean up leftovers.

Remove unused FavouritesXMLFactory (the reading part is already
completely done with generic XmlLoader?, and writing part will be done
based on the same approach if needed).
Move UserFavourite? to the com.framsticks.gui.configuration package.

Remove GenotypeBrowser? as to specific.

This functionality will be available in ObjectInstance?.

Add interface ParamsPackage?.

Package containing registration of Java classes meant to use with
ReflectionAccess? may be in Instance using configuration.

Minor changes.

Make Group immutable.

Add AutoBuilder? interface extending Builder - only those would
be used to automatically build from XML.

Fix groups in FramsClass?.

Minor naming cleanup in Registry.

Add ModelComponent? interface.

All class creating the Model are implementing that interface.

Extract Model.build into ModelBuilder?.

ModelBuilder? will be compatible with other builders
and allow using it from configuration.

Fix NeuroConnection?.

Add synchronous get operation for dispatchers.

Rename JoinableMonitor? to Monitor.

Add ObjectInstance?.

This class is mainly for demonstration
and testing purposes.

Improve FramsServer? runner.

  • improve ExternalProcess? runner,
  • runner can kill the server but also react properly, when the server exists on it's own,
  • set default path to search for framsticks server installation,
  • add LoggingOutputListener?.
File size: 12.4 KB
RevLine 
[77]1package com.framsticks.gui;
2
[88]3import com.framsticks.core.Entity;
[84]4import com.framsticks.core.Instance;
[77]5import com.framsticks.core.Path;
6import com.framsticks.gui.view.*;
7import com.framsticks.gui.view.TreeCellRenderer;
[84]8import com.framsticks.util.dispatching.Dispatcher;
[88]9import com.framsticks.util.dispatching.JoinableCollection;
[85]10import com.framsticks.util.lang.ScopeEnd;
[84]11import com.framsticks.util.swing.KeyboardModifier;
[88]12import com.framsticks.util.swing.MenuConstructor;
13
[77]14import org.apache.log4j.Logger;
15
16import javax.swing.*;
[84]17import javax.swing.event.TreeModelEvent;
18import javax.swing.event.TreeModelListener;
[77]19import javax.swing.event.TreeSelectionEvent;
20import javax.swing.event.TreeSelectionListener;
21import javax.swing.tree.*;
[84]22
[77]23import java.awt.*;
[78]24import java.awt.datatransfer.StringSelection;
[84]25import java.awt.event.*;
[77]26import java.util.HashMap;
27import java.util.Map;
[85]28import com.framsticks.util.dispatching.RunAt;
[77]29
30/**
31 * @author Piotr Sniegowski
32 */
[84]33@SuppressWarnings("serial")
[88]34public class Frame extends JoinableCollection<Instance> implements Entity, Dispatcher<Frame> {
[77]35
[84]36        private static final Logger log = Logger.getLogger(Frame.class.getName());
[77]37
[84]38        protected final Browser browser;
[77]39
[88]40        protected final Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
[77]41
[88]42        protected CardLayout cardPanelLayout;
43        protected JPanel cardPanel;
[77]44
[88]45        protected final String title;
46        protected JFrame swing;
[84]47        protected JScrollPane treeScrollPane;
48        protected JTree tree;
49        protected DefaultTreeModel treeModel;
50        protected javax.swing.tree.MutableTreeNode rootNode;
51        //final Instance instance;
52        protected JPanel treePanel;
53        protected JPopupMenu treePopupMenu;
54        protected JMenuItem treePopupMenuHeader;
[77]55
[84]56        TreeNode currentlyPoppedTreeNode;
57        protected JLabel statusBar;
58        protected JPanel mainPanel;
59        protected JPanel leftPanel;
60        protected JPanel normalWorkPanel;
61        protected CardLayout mainPanelLayout;
[77]62
[84]63        protected JMenuBar menuBar;
64        protected JMenu fileMenu;
65        protected JMenu editMenu;
66        protected JMenu viewMenu;
67        protected JMenu windowMenu;
68        protected JMenu helpMenu;
[77]69
[88]70        protected final Map<Instance, InstanceAtFrame> instancesAtFrames = new HashMap<Instance, InstanceAtFrame>();
[77]71
[84]72        public Frame(String title, Browser browser) {
[88]73                this.title = title;
74                this.browser = browser;
75        }
76
77        public void configure() {
78                swing = new JFrame(title);
79                swing.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
80                swing.addWindowListener(new WindowAdapter() {
81                        @Override
82                        public void windowClosing(WindowEvent e) {
83                                log.info("received closing");
84                                joinableFinish();
85                        }
86                });
[84]87                /** this is done to remove the current value label from above the slider,
88                 * because it cannot put to work properly with floating-point value sliders,
89                 * nor it can be removed in normal way through JSlider methods  */
90                UIManager.put("Slider.paintValue", false);
91                log.debug("creating " + this);
[77]92
[88]93                statusBar = new JLabel("not connected");
[77]94
[88]95                Container contentPane = swing.getContentPane();
[84]96                contentPane.setLayout(new BorderLayout());
[77]97
[84]98                treePopupMenu = new JPopupMenu("title");
99                treePopupMenu.setName("popup");
100                treePopupMenuHeader = new JMenuItem();
101                treePopupMenuHeader.setForeground(Color.BLUE);
102                treePopupMenu.add(treePopupMenuHeader);
103                treePopupMenu.addSeparator();
104                //TODO: add to favourites
105                //TODO: remove from favourites
106                //TODO: open in new window as root
107                //TODO: refresh
108                //TODO: open in console
[77]109
[84]110                treePopupMenu.add(new JMenuItem("Refresh"));
111                treePopupMenu.add(new JMenuItem("Open in new frame as root"));
[88]112                addNodeActionToTreePopupMenu("Copy path to clipboard", new NodeAction() {
113                        @Override
114                        public void actionPerformed(TreeNode treeNode) {
115                                Path path = treeNode.getInstancePath();
116                                StringSelection selection = new StringSelection(path.toString());
117                                swing.getToolkit().getSystemClipboard().setContents(selection, selection);
118                        }
119                });
[84]120                //this.add(createMenuItem("Add to favourites", null));
121                //this.add(createMenuItem("Remove from favourites", null));
122
123                treePanel = new JPanel();
124                treePanel.setLayout(new BorderLayout());
125
126                treeModel = new DefaultTreeModel(null);
127                treeModel.addTreeModelListener(new TreeModelListener() {
128
[78]129                        @Override
[84]130                        public void treeNodesChanged(TreeModelEvent arg0) {
131                                log.trace("treeNodesChanged: " + arg0);
[78]132                        }
[77]133
[84]134                        @Override
135                        public void treeNodesInserted(TreeModelEvent arg0) {
136                                // log.trace("treeNodesInserted: " + arg0);
137                        }
[77]138
[84]139                        @Override
140                        public void treeNodesRemoved(TreeModelEvent arg0) {
141                                log.trace("treeNodesRemoved: " + arg0);
142                        }
[77]143
[84]144                        @Override
145                        public void treeStructureChanged(TreeModelEvent arg0) {
146                                log.trace("treeStructureChanged: " + arg0);
147                        }
148                });
[77]149
[84]150                tree = new JTree(treeModel);
151                tree.setName("tree");
152                tree.setRootVisible(false);
153                tree.setExpandsSelectedPaths(true);
154                tree.setSelectionModel(new DefaultTreeSelectionModel());
155                ToolTipManager.sharedInstance().registerComponent(tree);
[77]156
[84]157                tree.addTreeSelectionListener(new TreeSelectionListener() {
158                        @Override
159                        public void valueChanged(TreeSelectionEvent e) {
160                                chooseTreeNode(e.getNewLeadSelectionPath());
161                        }
162                });
[77]163
[84]164                tree.setExpandsSelectedPaths(true);
165                tree.setEditable(false);
166                tree.setDoubleBuffered(true);
167                tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
168                tree.setShowsRootHandles(true);
169                tree.setRowHeight(26);
170                tree.setDoubleBuffered(true);
171                tree.addMouseListener(new MouseAdapter() {
172                        @Override
173                        public void mousePressed(MouseEvent e) {
174                                assert isActive();
175                                showPopup(e);
176                        }
[77]177
[84]178                        @Override
179                        public void mouseReleased(MouseEvent e) {
180                                assert isActive();
181                                showPopup(e);
182                        }
183                });
[77]184
[88]185                new KeyboardModifier(tree, JComponent.WHEN_FOCUSED).join(KeyStroke.getKeyStroke('h'), KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)).join(KeyStroke.getKeyStroke('j'), KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)).join(KeyStroke.getKeyStroke('k'), KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)).join(KeyStroke.getKeyStroke('l'), KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
[77]186
[84]187                tree.setCellRenderer(new TreeCellRenderer());
[77]188
[84]189                treeScrollPane = new JScrollPane(tree);
190                treeScrollPane.setBorder(BorderFactory.createEmptyBorder());
[77]191
[84]192                treePanel.add(treeScrollPane);
[77]193
[84]194                rootNode = new DefaultMutableTreeNode();
195                rootNode.setUserObject("root");
196                treeModel.setRoot(rootNode);
[77]197
[84]198                normalWorkPanel = new JPanel();
199                normalWorkPanel.setLayout(new BorderLayout());
200                normalWorkPanel.setName("browser");
[77]201
[84]202                mainPanel = new JPanel();
203                mainPanel.setName("main");
204                mainPanelLayout = new CardLayout();
205                mainPanel.setLayout(mainPanelLayout);
206                mainPanel.add(normalWorkPanel, "browser");
[77]207
[84]208                menuBar = new JMenuBar();
[77]209
[84]210                fileMenu = menuBar.add(new JMenu("File"));
211                editMenu = menuBar.add(new JMenu("Edit"));
212                viewMenu = menuBar.add(new JMenu("View"));
213                windowMenu = menuBar.add(new JMenu("Window"));
214                helpMenu = menuBar.add(new JMenu("Help"));
[77]215
[84]216                contentPane.add(menuBar, BorderLayout.NORTH);
217                contentPane.add(mainPanel, BorderLayout.CENTER);
218                contentPane.add(statusBar, BorderLayout.SOUTH);
[77]219
[84]220                leftPanel = new JPanel();
221                leftPanel.setLayout(new BorderLayout());
222                //leftPanel.add(new ViewerTest(), BorderLayout.PAGE_START);
[88]223                //        JPanel leftTopPanel = createLeftTopPanel();
224                //        if (leftTopPanel != null) {
225                //            leftPanel.add(leftTopPanel, BorderLayout.PAGE_START);
226                //        }
[84]227                leftPanel.add(treePanel, BorderLayout.CENTER);
228                leftPanel.setBackground(Color.WHITE);
229                leftPanel.setForeground(Color.WHITE);
[77]230
[88]231                cardPanel = new JPanel();
[84]232                cardPanel.setName("card");
233                JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, cardPanel);
234                split.setPreferredSize(browser.defaultFrameDimension);
235                split.setMaximumSize(screenDimension);
236                split.setOneTouchExpandable(true);
237                split.setDividerLocation(250);
238                split.setDividerSize(5);
239                split.setName("split");
[77]240
[84]241                normalWorkPanel.add(split);
[77]242
[84]243                //this.setVisible(true);
244                mainPanelLayout.show(mainPanel, "browser");
[77]245
[88]246                cardPanelLayout = new CardLayout();
[84]247                cardPanel.setLayout(cardPanelLayout);
[77]248
[88]249                swing.pack();
[84]250                tree.requestFocusInWindow();
[77]251
[88]252                log.debug("frame configured: " + this);
[77]253
[88]254                new MenuConstructor(fileMenu).add(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK), new AbstractAction("Close") {
255                        @Override
256                        public void actionPerformed(ActionEvent actionEvent) {
257                                interrupt();
258                        }
259                });
260
[84]261        }
[77]262
[84]263        protected JPanel createLeftTopPanel() {
264                return null;
265        }
[77]266
[88]267        public void addRootPath(Path path) {
[84]268                assert isActive();
[88]269                Instance instance = path.getInstance();
270                assert browser.getInstances().containsValue(instance);
[77]271
[88]272                InstanceAtFrame e = new InstanceAtFrame(instance, this);
273                instance.addListener(e);
274                instancesAtFrames.put(instance, e);
[84]275                TreeNode node = new TreeNode(e, path);
276                e.rootTreeNode = node;
277                treeModel.insertNodeInto(node, rootNode, rootNode.getChildCount());
278                tree.expandPath(new TreePath(rootNode));
279        }
[77]280
[84]281        @Override
282        public boolean isActive() {
283                return SwingDispatcher.instance.isActive();
284        }
[77]285
[84]286        @Override
[90]287        public void dispatch(RunAt<? extends Frame> runnable) {
288                SwingDispatcher.getInstance().dispatch(runnable);
[84]289        }
[77]290
[84]291        public Action addActionToTreePopupMenu(Action action) {
292                assert isActive();
293                treePopupMenu.add(action);
294                return action;
295        }
[77]296
[84]297        public Action addNodeActionToTreePopupMenu(String title, final NodeAction nodeAction) {
298                assert isActive();
299                return addActionToTreePopupMenu(new AbstractAction(title) {
300                        @Override
301                        public void actionPerformed(ActionEvent e) {
302                                TreeNode treeNode = getCurrentlyPoppedTreeNode();
303                                if (treeNode == null) {
304                                        return;
305                                }
306                                nodeAction.actionPerformed(treeNode);
307                        }
308                });
309        }
[77]310
[84]311        public void showPanel(Panel panel) {
312                assert isActive();
313                assert panel != null;
314                cardPanelLayout.show(cardPanel, panel.getUniqueName());
315        }
[77]316
[84]317        private void showPopup(MouseEvent e) {
318                assert isActive();
319                if (!e.isPopupTrigger()) {
320                        return;
321                }
322                currentlyPoppedTreeNode = findTreeNodeByTreePath(tree.getPathForLocation(e.getX(), e.getY()));
323                if (currentlyPoppedTreeNode == null) {
324                        return;
325                }
326                treePopupMenu.show(e.getComponent(), e.getX(), e.getY());
327                //currentlyPoppedPanel.getNode().getFramsClass().getName()
328                //treePopupMenuHeader.setText(currentlyPoppedTreeNode.getNode().getPath());
329        }
[77]330
[88]331        /**
332         * @return the swing
333         */
334        public JFrame getSwing() {
335                return swing;
336        }
337
[84]338        public TreeNode getCurrentlyPoppedTreeNode() {
339                assert isActive();
340                return currentlyPoppedTreeNode;
341        }
[77]342
[84]343        public void clear() {
344                treeModel.setRoot(null);
345                cardPanel.removeAll();
346                cardPanel.updateUI();
347                tree.setEnabled(false);
348        }
[77]349
[85]350        public ScopeEnd startChange(final DefaultMutableTreeNode node) {
[84]351                assert isActive();
352                final TreePath selection = tree.getSelectionPath();
[85]353                return new ScopeEnd() {
[84]354                        @Override
[85]355                        public void close() {
[84]356                                assert isActive();
357                                treeModel.nodeChanged(node);
358                                tree.setSelectionPath(selection);
359                        }
360                };
361        }
362
363        public void selectTreeNode(final TreeNode treeNode) {
364                assert isActive();
[88]365                /*              final Panel panel = treeNode.getOrCreatePanel();
366                 if (panel == null) {
367                 return;
368                 }
369                 panel.setCurrentTreeNode(treeNode);
370                 treeNode.updateData();
371                 showPanel(panel);*/
[84]372        }
[77]373
[84]374        public TreeNode findTreeNodeByTreePath(TreePath treePath) {
375                assert isActive();
376                if (treePath == null) {
377                        return null;
378                }
379                if (!(treePath.getLastPathComponent() instanceof TreeNode)) {
380                        return null;
381                }
[88]382                return (TreeNode) treePath.getLastPathComponent();
[84]383        }
[77]384
[84]385        public void chooseTreeNode(TreePath treePath) {
386                assert isActive();
387                final TreeNode treeNode = findTreeNodeByTreePath(treePath);
388                if (treeNode == null) {
389                        return;
390                }
391                treeNode.select();
392        }
[77]393
[84]394        public void goTo(Path path) {
395                assert isActive();
[88]396                final TreePath treePath = instancesAtFrames.get(path.getInstance()).getTreePath(path, false);
[84]397                log.info("go to path: " + path + "(" + treePath + ")");
[85]398
399                new RunAt<Frame>(this) {
[84]400                        @Override
401                        public void run() {
[85]402                                log.info("executed");
[84]403                                tree.setSelectionPath(treePath);
404                                tree.makeVisible(treePath);
405                                assert tree.isVisible(treePath);
406                        }
[85]407                };
[77]408
[84]409        }
[77]410
[84]411        public void addNode(TreeNode child, DefaultMutableTreeNode parent) {
412                assert isActive();
[85]413
414                try (ScopeEnd e = startChange(parent)) {
415                        treeModel.insertNodeInto(child, parent, parent.getChildCount());
416                }
[84]417        }
418
419        @Override
420        public String toString() {
[88]421                return title + "@" + browser.getName();
[84]422        }
423
[88]424        @Override
425        protected void joinableInterrupt() {
426                assert isActive();
427                super.joinableInterrupt();
428
[90]429                dispatch(new RunAt<Frame>() {
[88]430                        @Override
431                        public void run() {
432                                finish();
433                        }
434                });
435        }
436
437        @Override
438        protected void joinableFinish() {
439                assert isActive();
440                log.debug("disposing frame " + this);
441                swing.dispose();
442        }
443
444        // @Override
445        // public boolean isDone() {
446        //      return super.isDone() && !swing.isDisplayable();
447        // }
448
449
450        @Override
451        public String getName() {
452                return title;
453        }
454
455
[77]456}
Note: See TracBrowser for help on using the repository browser.