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