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

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

HIGHLIGHTS:

  • cleanup Instance management
    • extract Instance interface
    • extract Instance common algorithms to InstanceUtils?
  • fix closing issues: Ctrl+C or window close button

properly shutdown whole program

by Java Framsticks framework

  • fix parsing and printing of all request types
  • hide exception passing in special handle method of closures
    • substantially improve readability of closures
    • basically enable use of exception in asynchronous closures

(thrown exception is transported back to the caller)

  • implement call request on both sides

CHANGELOG:
Further improve calling.

Improve instance calling.

Calling is working on both sides.

Improve exception handling in testing.

Waiters do not supercede other apllication exception being thrown.

Finished parsing and printing of all request types (with tests).

Move implementation and tests of request parsing to Request.

Add tests for Requests.

Improve waits in asynchronours tests.

Extract more algorithms to InstanceUtils?.

Extract Instance.resolve to InstanceUtils?.

Improve naming.

Improve passing exception in InstanceClient?.

Hide calling of passed functor in StateCallback?.

Hide Exception passing in asynchronous closures.

Hide exception passing in Future.

Make ResponseCallback? an abstract class.

Make Future an abstract class.

Minor change.

Move getPath to Path.to()

Move bindAccess to InstanceUtils?.

Extract common things to InstanceUtils?.

Fix synchronization bug in Connection.

Move resolve to InstanceUtils?.

Allow names of Joinable to be dynamic.

Add support for set request server side.

More fixes in communication.

Fix issues with parsing in connection.

Cut new line characters when reading.

More improvements.

Migrate closures to FramsticksException?.

Several changes.

Extract resolveAndFetch to InstanceUtils? algorithms.

Test resolving and fetching.

More fixes with function signature deduction.

Do not print default values in SimpleAbstractAccess?.

Add test of FramsClass? printing.

Improve FramsticksException? messages.

Add explicit dispatcher synchronization feature.

Rework assertions in tests.

Previous solution was not generic enough.

Allow addition of joinables to collection after start.

Extract SimulatorInstance? from RemoteInstance?.

Remove PrivateJoinableCollection?.

Improve connections.

Move shutdown hook to inside the Monitor.

It should work in TestNG tests, but it seems that
hooks are not called.

In ServerTest? client connects to testing server.

Move socket initialization to receiver thread.

Add proper closing on Ctrl+C (don't use signals).

Fix bugs with server accepting connections.

Merge Entity into Joinable.

Reworking ServerInstance?.

Extract more algorithm to InstanceUtils?.

Extract some common functionality from AbstractInstance?.

Functions were placed in InstanceUtils?.

Hide registry of Instance.

Use ValueParam? in Instance interface.

Minor change.

Extract Instance interface.

Old Instance is now AbstractInstance?.

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