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
Line 
1package com.framsticks.gui;
2
3import com.framsticks.core.Entity;
4import com.framsticks.core.Instance;
5import com.framsticks.core.Path;
6import com.framsticks.gui.view.*;
7import com.framsticks.gui.view.TreeCellRenderer;
8import com.framsticks.util.dispatching.Dispatcher;
9import com.framsticks.util.dispatching.JoinableCollection;
10import com.framsticks.util.lang.ScopeEnd;
11import com.framsticks.util.swing.KeyboardModifier;
12import com.framsticks.util.swing.MenuConstructor;
13
14import org.apache.log4j.Logger;
15
16import javax.swing.*;
17import javax.swing.event.TreeModelEvent;
18import javax.swing.event.TreeModelListener;
19import javax.swing.event.TreeSelectionEvent;
20import javax.swing.event.TreeSelectionListener;
21import javax.swing.tree.*;
22
23import java.awt.*;
24import java.awt.datatransfer.StringSelection;
25import java.awt.event.*;
26import java.util.HashMap;
27import java.util.Map;
28import com.framsticks.util.dispatching.RunAt;
29
30/**
31 * @author Piotr Sniegowski
32 */
33@SuppressWarnings("serial")
34public class Frame extends JoinableCollection<Instance> implements Entity, Dispatcher<Frame> {
35
36        private static final Logger log = Logger.getLogger(Frame.class.getName());
37
38        protected final Browser browser;
39
40        protected final Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
41
42        protected CardLayout cardPanelLayout;
43        protected JPanel cardPanel;
44
45        protected final String title;
46        protected JFrame swing;
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;
55
56        TreeNode currentlyPoppedTreeNode;
57        protected JLabel statusBar;
58        protected JPanel mainPanel;
59        protected JPanel leftPanel;
60        protected JPanel normalWorkPanel;
61        protected CardLayout mainPanelLayout;
62
63        protected JMenuBar menuBar;
64        protected JMenu fileMenu;
65        protected JMenu editMenu;
66        protected JMenu viewMenu;
67        protected JMenu windowMenu;
68        protected JMenu helpMenu;
69
70        protected final Map<Instance, InstanceAtFrame> instancesAtFrames = new HashMap<Instance, InstanceAtFrame>();
71
72        public Frame(String title, Browser browser) {
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                });
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);
92
93                statusBar = new JLabel("not connected");
94
95                Container contentPane = swing.getContentPane();
96                contentPane.setLayout(new BorderLayout());
97
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
109
110                treePopupMenu.add(new JMenuItem("Refresh"));
111                treePopupMenu.add(new JMenuItem("Open in new frame as root"));
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                });
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
129                        @Override
130                        public void treeNodesChanged(TreeModelEvent arg0) {
131                                log.trace("treeNodesChanged: " + arg0);
132                        }
133
134                        @Override
135                        public void treeNodesInserted(TreeModelEvent arg0) {
136                                // log.trace("treeNodesInserted: " + arg0);
137                        }
138
139                        @Override
140                        public void treeNodesRemoved(TreeModelEvent arg0) {
141                                log.trace("treeNodesRemoved: " + arg0);
142                        }
143
144                        @Override
145                        public void treeStructureChanged(TreeModelEvent arg0) {
146                                log.trace("treeStructureChanged: " + arg0);
147                        }
148                });
149
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);
156
157                tree.addTreeSelectionListener(new TreeSelectionListener() {
158                        @Override
159                        public void valueChanged(TreeSelectionEvent e) {
160                                chooseTreeNode(e.getNewLeadSelectionPath());
161                        }
162                });
163
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                        }
177
178                        @Override
179                        public void mouseReleased(MouseEvent e) {
180                                assert isActive();
181                                showPopup(e);
182                        }
183                });
184
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));
186
187                tree.setCellRenderer(new TreeCellRenderer());
188
189                treeScrollPane = new JScrollPane(tree);
190                treeScrollPane.setBorder(BorderFactory.createEmptyBorder());
191
192                treePanel.add(treeScrollPane);
193
194                rootNode = new DefaultMutableTreeNode();
195                rootNode.setUserObject("root");
196                treeModel.setRoot(rootNode);
197
198                normalWorkPanel = new JPanel();
199                normalWorkPanel.setLayout(new BorderLayout());
200                normalWorkPanel.setName("browser");
201
202                mainPanel = new JPanel();
203                mainPanel.setName("main");
204                mainPanelLayout = new CardLayout();
205                mainPanel.setLayout(mainPanelLayout);
206                mainPanel.add(normalWorkPanel, "browser");
207
208                menuBar = new JMenuBar();
209
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"));
215
216                contentPane.add(menuBar, BorderLayout.NORTH);
217                contentPane.add(mainPanel, BorderLayout.CENTER);
218                contentPane.add(statusBar, BorderLayout.SOUTH);
219
220                leftPanel = new JPanel();
221                leftPanel.setLayout(new BorderLayout());
222                //leftPanel.add(new ViewerTest(), BorderLayout.PAGE_START);
223                //        JPanel leftTopPanel = createLeftTopPanel();
224                //        if (leftTopPanel != null) {
225                //            leftPanel.add(leftTopPanel, BorderLayout.PAGE_START);
226                //        }
227                leftPanel.add(treePanel, BorderLayout.CENTER);
228                leftPanel.setBackground(Color.WHITE);
229                leftPanel.setForeground(Color.WHITE);
230
231                cardPanel = new JPanel();
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");
240
241                normalWorkPanel.add(split);
242
243                //this.setVisible(true);
244                mainPanelLayout.show(mainPanel, "browser");
245
246                cardPanelLayout = new CardLayout();
247                cardPanel.setLayout(cardPanelLayout);
248
249                swing.pack();
250                tree.requestFocusInWindow();
251
252                log.debug("frame configured: " + this);
253
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
261        }
262
263        protected JPanel createLeftTopPanel() {
264                return null;
265        }
266
267        public void addRootPath(Path path) {
268                assert isActive();
269                Instance instance = path.getInstance();
270                assert browser.getInstances().containsValue(instance);
271
272                InstanceAtFrame e = new InstanceAtFrame(instance, this);
273                instance.addListener(e);
274                instancesAtFrames.put(instance, e);
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        }
280
281        @Override
282        public boolean isActive() {
283                return SwingDispatcher.instance.isActive();
284        }
285
286        @Override
287        public void dispatch(RunAt<? extends Frame> runnable) {
288                SwingDispatcher.getInstance().dispatch(runnable);
289        }
290
291        public Action addActionToTreePopupMenu(Action action) {
292                assert isActive();
293                treePopupMenu.add(action);
294                return action;
295        }
296
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        }
310
311        public void showPanel(Panel panel) {
312                assert isActive();
313                assert panel != null;
314                cardPanelLayout.show(cardPanel, panel.getUniqueName());
315        }
316
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        }
330
331        /**
332         * @return the swing
333         */
334        public JFrame getSwing() {
335                return swing;
336        }
337
338        public TreeNode getCurrentlyPoppedTreeNode() {
339                assert isActive();
340                return currentlyPoppedTreeNode;
341        }
342
343        public void clear() {
344                treeModel.setRoot(null);
345                cardPanel.removeAll();
346                cardPanel.updateUI();
347                tree.setEnabled(false);
348        }
349
350        public ScopeEnd startChange(final DefaultMutableTreeNode node) {
351                assert isActive();
352                final TreePath selection = tree.getSelectionPath();
353                return new ScopeEnd() {
354                        @Override
355                        public void close() {
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();
365                /*              final Panel panel = treeNode.getOrCreatePanel();
366                 if (panel == null) {
367                 return;
368                 }
369                 panel.setCurrentTreeNode(treeNode);
370                 treeNode.updateData();
371                 showPanel(panel);*/
372        }
373
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                }
382                return (TreeNode) treePath.getLastPathComponent();
383        }
384
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        }
393
394        public void goTo(Path path) {
395                assert isActive();
396                final TreePath treePath = instancesAtFrames.get(path.getInstance()).getTreePath(path, false);
397                log.info("go to path: " + path + "(" + treePath + ")");
398
399                new RunAt<Frame>(this) {
400                        @Override
401                        public void run() {
402                                log.info("executed");
403                                tree.setSelectionPath(treePath);
404                                tree.makeVisible(treePath);
405                                assert tree.isVisible(treePath);
406                        }
407                };
408
409        }
410
411        public void addNode(TreeNode child, DefaultMutableTreeNode parent) {
412                assert isActive();
413
414                try (ScopeEnd e = startChange(parent)) {
415                        treeModel.insertNodeInto(child, parent, parent.getChildCount());
416                }
417        }
418
419        @Override
420        public String toString() {
421                return title + "@" + browser.getName();
422        }
423
424        @Override
425        protected void joinableInterrupt() {
426                assert isActive();
427                super.joinableInterrupt();
428
429                dispatch(new RunAt<Frame>() {
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
456}
Note: See TracBrowser for help on using the repository browser.