1 33 34 package edu.rice.cs.drjava.ui; 35 36 import java.util.List ; 37 import java.util.ArrayList ; 38 import java.util.LinkedList ; 39 import java.util.Enumeration ; 40 import java.io.*; 41 42 import javax.swing.*; 43 import javax.swing.event.*; 44 import javax.swing.tree.*; 45 import javax.swing.table.*; 46 import javax.swing.text.*; 47 import javax.swing.plaf.*; 48 import javax.swing.plaf.basic.BasicToolTipUI ; 49 import java.awt.event.*; 50 import java.awt.font.*; 51 import java.awt.*; 52 53 import edu.rice.cs.drjava.DrJava; 54 import edu.rice.cs.drjava.model.DocumentRegion; 55 import edu.rice.cs.drjava.model.SingleDisplayModel; 56 import edu.rice.cs.drjava.model.debug.*; 57 import edu.rice.cs.drjava.model.OpenDefinitionsDocument; 58 import edu.rice.cs.drjava.model.definitions.ClassNameNotFoundException; 59 import edu.rice.cs.drjava.config.*; 60 import edu.rice.cs.util.swing.Utilities; 61 import edu.rice.cs.util.UnexpectedException; 62 import edu.rice.cs.util.StringOps; 63 import edu.rice.cs.util.swing.RightClickMouseAdapter; 64 65 69 public abstract class RegionsTreePanel<R extends DocumentRegion> extends TabbedPanel { 70 protected JPanel _leftPane; 71 72 protected DefaultMutableTreeNode _regionRootNode; 73 protected DefaultTreeModel _regTreeModel; 74 protected JTree _regTree; 75 protected String _title; 76 77 protected JPopupMenu _regionPopupMenu; 78 79 protected final SingleDisplayModel _model; 80 protected final MainFrame _frame; 81 82 protected JPanel _buttonPanel; 83 84 protected DefaultTreeCellRenderer dtcr; 85 86 91 public RegionsTreePanel(MainFrame frame, String title) { 92 super(frame, title); 93 _title = title; 94 this.setLayout(new BorderLayout()); 95 96 _frame = frame; 97 _model = frame.getModel(); 98 99 this.removeAll(); 101 _closePanel = new JPanel(new BorderLayout()); 103 _closePanel.add(_closeButton, BorderLayout.NORTH); 104 105 _leftPane = new JPanel(new BorderLayout()); 106 _setupRegionTree(); 107 108 this.add(_leftPane, BorderLayout.CENTER); 109 110 _buttonPanel = new JPanel(new BorderLayout()); 111 _setupButtonPanel(); 112 this.add(_buttonPanel, BorderLayout.EAST); 113 updateButtons(); 114 115 _setColors(_regTree); 117 } 118 119 120 private static void _setColors(Component c) { 121 new ForegroundColorListener(c); 122 new BackgroundColorListener(c); 123 } 124 125 126 protected void _close() { 127 super._close(); 128 updateButtons(); 129 } 130 131 134 public boolean requestFocusInWindow() { 135 Runnable doCommand = new Runnable () { 137 public void run() { 138 Enumeration documents = _regionRootNode.children(); 140 boolean found = false; 141 while ((!found) && (documents.hasMoreElements())) { 142 DefaultMutableTreeNode doc = (DefaultMutableTreeNode)documents.nextElement(); 143 Enumeration existingRegions = doc.children(); 145 while (existingRegions.hasMoreElements()) { 146 DefaultMutableTreeNode existing = (DefaultMutableTreeNode)existingRegions.nextElement(); 147 _regTreeModel.nodeChanged(existing); 148 } 149 _regTreeModel.nodeChanged(doc); 150 } 151 updateButtons(); 152 } 153 }; 154 Utilities.invokeLater(doCommand); 155 return super.requestFocusInWindow(); 156 } 157 158 159 private void _setupRegionTree() { 160 _regionRootNode = new DefaultMutableTreeNode(_title); 161 _regTreeModel = new DefaultTreeModel(_regionRootNode); 162 _regTree = new RegionTree(_regTreeModel); 163 _regTree.setEditable(false); 164 _regTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); 165 _regTree.setShowsRootHandles(true); 166 _regTree.setRootVisible(false); 167 _regTree.putClientProperty("JTree.lineStyle", "Angled"); 168 _regTree.setScrollsOnExpand(true); 169 _regTree.addTreeSelectionListener(new TreeSelectionListener() { 170 public void valueChanged(TreeSelectionEvent e) { 171 updateButtons(); 172 } 173 }); 174 _regTree.addKeyListener(new KeyAdapter() { 175 public void keyPressed(KeyEvent e) { 176 if (e.getKeyCode() == KeyEvent.VK_ENTER) { 177 performDefaultAction(); 178 } 179 } 180 }); 181 182 dtcr = new RegionRenderer(); 184 dtcr.setOpaque(false); 185 _setColors(dtcr); 186 _regTree.setCellRenderer(dtcr); 187 188 _leftPane.add(new JScrollPane(_regTree)); 189 190 _initPopup(); 191 192 ToolTipManager.sharedInstance().registerComponent(_regTree); 193 } 194 195 196 protected void updateButtons() { 197 } 198 199 200 class RegionRenderer extends DefaultTreeCellRenderer { 201 202 public void setBackground(Color c) { 203 this.setBackgroundNonSelectionColor(c); 204 } 205 206 public void setForeground(Color c) { 207 this.setTextNonSelectionColor(c); 208 } 209 210 private RegionRenderer() { 211 this.setTextSelectionColor(Color.black); 212 setLeafIcon(null); 213 setOpenIcon(null); 214 setClosedIcon(null); 215 } 216 217 220 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean isSelected, boolean isExpanded, 221 boolean leaf, int row, boolean hasFocus) { 222 Component renderer = super.getTreeCellRendererComponent(tree, value, isSelected, isExpanded, leaf, row, hasFocus); 223 224 if (renderer instanceof JComponent) { ((JComponent) renderer).setOpaque(false); } 225 226 _setColors(renderer); 227 228 String tooltip = null; 230 if (DrJava.getConfig().getSetting(OptionConstants.SHOW_CODE_PREVIEW_POPUPS).booleanValue()) { 231 if (leaf) { 232 DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; 233 if (node.getUserObject() instanceof RegionTreeUserObj) { 234 @SuppressWarnings ("unchecked") R r = ((RegionTreeUserObj<R>)(node.getUserObject())).region(); 235 236 OpenDefinitionsDocument doc = r.getDocument(); 237 doc.acquireReadLock(); 238 try { 239 int lnr = doc.getLineOfOffset(r.getStartOffset())+1; 240 int startOffset = doc.getOffset(lnr-3); 241 if (startOffset<0) { startOffset = 0; } 242 int endOffset = doc.getOffset(lnr+3); 243 if (endOffset<0) { endOffset = doc.getLength()-1; } 244 245 String s = doc.getText(startOffset, endOffset-startOffset); 247 248 int rStart = r.getStartOffset()-startOffset; 250 if (rStart<0) { rStart = 0; } 251 int rEnd = r.getEndOffset()-startOffset; 252 if (rEnd>s.length()) { rEnd = s.length(); } 253 if ((rStart<=s.length()) && (rEnd>=rStart)) { 254 String t1 = StringOps.encodeHTML(s.substring(0,rStart)); 255 String t2 = StringOps.encodeHTML(s.substring(rStart,rEnd)); 256 String t3 = StringOps.encodeHTML(s.substring(rEnd)); 257 s = t1 + "<font color=#ff0000>" + t2 + "</font>" + t3; 258 } 259 else { 260 s = StringOps.encodeHTML(s); 261 } 262 tooltip = "<html><pre>"+s+"</pre></html>"; 263 } 264 catch(javax.swing.text.BadLocationException ble) { tooltip = null; } 265 finally { doc.releaseReadLock(); } 266 setText(node.getUserObject().toString()); 267 renderer = this; 268 } 269 } 270 } 271 setToolTipText(tooltip); 272 return renderer; 273 } 274 } 275 276 277 protected void performDefaultAction() { 278 } 279 280 281 protected JComponent[] makeButtons() { 282 return new JComponent[0]; 283 } 284 285 286 private void _setupButtonPanel() { 287 JPanel mainButtons = new JPanel(); 288 JPanel emptyPanel = new JPanel(); 289 JPanel closeButtonPanel = new JPanel(new BorderLayout()); 290 GridBagLayout gbLayout = new GridBagLayout(); 291 GridBagConstraints c = new GridBagConstraints(); 292 mainButtons.setLayout(gbLayout); 293 294 JComponent[] buts = makeButtons(); 295 296 closeButtonPanel.add(_closeButton, BorderLayout.NORTH); 297 for (JComponent b: buts) { mainButtons.add(b); } 298 mainButtons.add(emptyPanel); 299 300 c.fill = GridBagConstraints.HORIZONTAL; 301 c.anchor = GridBagConstraints.NORTH; 302 c.gridwidth = GridBagConstraints.REMAINDER; 303 c.weightx = 1.0; 304 305 for (JComponent b: buts) { gbLayout.setConstraints(b, c); } 306 307 c.fill = GridBagConstraints.BOTH; 308 c.anchor = GridBagConstraints.SOUTH; 309 c.gridheight = GridBagConstraints.REMAINDER; 310 c.weighty = 1.0; 311 312 gbLayout.setConstraints(emptyPanel, c); 313 314 _buttonPanel.add(mainButtons, BorderLayout.CENTER); 315 _buttonPanel.add(closeButtonPanel, BorderLayout.EAST); 316 } 317 318 319 protected AbstractAction[] makePopupMenuActions() { 320 return null; 321 } 322 323 324 private void _initPopup() { 325 _regionPopupMenu = new JPopupMenu(_title); 326 AbstractAction[] acts = makePopupMenuActions(); 327 if (acts!=null) { 328 for (AbstractAction a: acts) { 329 _regionPopupMenu.add(a); 330 } 331 _regTree.addMouseListener(new RegionMouseAdapter()); 332 } 333 } 334 335 338 protected ArrayList <R> getSelectedRegions() { 339 ArrayList <R> regs = new ArrayList <R>(); 340 TreePath[] paths = _regTree.getSelectionPaths(); 341 if (paths!=null) { 342 for (TreePath path: paths) { 343 if (path != null && path.getPathCount() == 3) { 344 DefaultMutableTreeNode lineNode = (DefaultMutableTreeNode)path.getLastPathComponent(); 345 @SuppressWarnings ("unchecked") R r = ((RegionTreeUserObj<R>) lineNode.getUserObject()).region(); 346 regs.add(r); 347 } 348 } 349 } 350 return regs; 351 } 352 353 354 protected void goToRegion() { 355 ArrayList <R> r = getSelectedRegions(); 356 if (r.size() == 1) _frame.scrollToDocumentAndOffset(r.get(0).getDocument(), r.get(0).getStartOffset(), false); 357 } 358 359 362 public void addRegion(final R r) { 363 String name = ""; 364 try { name = r.getDocument().getQualifiedClassName(); } 365 catch (ClassNameNotFoundException cnnfe) { name = r.getDocument().toString(); } 366 367 DefaultMutableTreeNode regDocNode = new DefaultMutableTreeNode(name); 368 369 Enumeration documents = _regionRootNode.children(); 372 boolean done = false; 373 while (!done && (documents.hasMoreElements())) { 374 DefaultMutableTreeNode doc = (DefaultMutableTreeNode)documents.nextElement(); 375 if (doc.getUserObject().equals(regDocNode.getUserObject())) { 376 377 Enumeration existingRegions = doc.children(); 381 while (existingRegions.hasMoreElements()) { 382 DefaultMutableTreeNode existing = (DefaultMutableTreeNode)existingRegions.nextElement(); 383 384 int ofs = r.getStartOffset(); 386 if (((RegionTreeUserObj)existing.getUserObject()).region().getStartOffset() == ofs) { 387 _regTree.scrollPathToVisible(new TreePath(existing)); 390 done = true; 391 break; 392 } 393 else if (((RegionTreeUserObj)existing.getUserObject()).region().getStartOffset() > ofs) { 394 395 DefaultMutableTreeNode newRegion = new DefaultMutableTreeNode(makeRegionTreeUserObj(r)); 397 _regTreeModel.insertNodeInto(newRegion, doc, doc.getIndex(existing)); 398 399 _regTree.scrollPathToVisible(new TreePath(newRegion.getPath())); 401 done = true; 402 break; 403 } 404 } 405 if (done) { break; } 406 407 DefaultMutableTreeNode newRegion = new DefaultMutableTreeNode(makeRegionTreeUserObj(r)); 409 _regTreeModel.insertNodeInto(newRegion, doc, doc.getChildCount()); 410 411 _regTree.scrollPathToVisible(new TreePath(newRegion.getPath())); 413 done = true; 414 break; 415 } 416 } 417 418 if (!done) { 419 _regTreeModel.insertNodeInto(regDocNode, _regionRootNode, _regionRootNode.getChildCount()); 421 DefaultMutableTreeNode newRegion = new DefaultMutableTreeNode(makeRegionTreeUserObj(r)); 422 _regTreeModel.insertNodeInto(newRegion, regDocNode, regDocNode.getChildCount()); 423 424 TreePath pathToNewRegion = new TreePath(newRegion.getPath()); 426 _regTree.scrollPathToVisible(pathToNewRegion); 427 } 428 429 updateButtons(); 430 } 431 432 435 public void removeRegion(final R r) { 436 Runnable doCommand = new Runnable () { 438 public void run() { 439 String name = ""; 440 try { 441 name = r.getDocument().getQualifiedClassName(); 442 } 443 catch (ClassNameNotFoundException cnnfe) { 444 name = r.getDocument().toString(); 445 } 446 447 DefaultMutableTreeNode regDocNode = new DefaultMutableTreeNode(name); 448 449 Enumeration documents = _regionRootNode.children(); 451 boolean found = false; 452 while ((!found) && (documents.hasMoreElements())) { 453 DefaultMutableTreeNode doc = (DefaultMutableTreeNode)documents.nextElement(); 454 if (doc.getUserObject().equals(regDocNode.getUserObject())) { 455 Enumeration existingRegions = doc.children(); 457 while (existingRegions.hasMoreElements()) { 458 DefaultMutableTreeNode existing = (DefaultMutableTreeNode)existingRegions.nextElement(); 459 if (((RegionTreeUserObj)existing.getUserObject()).region().getStartOffset()==r.getStartOffset()) { 460 _regTreeModel.removeNodeFromParent(existing); 461 if (doc.getChildCount() == 0) { 463 _regTreeModel.removeNodeFromParent(doc); 465 } 466 found = true; 467 break; 468 } 469 } 470 } 471 } 472 updateButtons(); 473 } 474 }; 475 Utilities.invokeLater(doCommand); 476 } 477 478 480 public void removeRegions(final OpenDefinitionsDocument odd) { 481 Runnable doCommand = new Runnable () { 483 public void run() { 484 String name = ""; 485 try { 486 name = odd.getQualifiedClassName(); 487 } 488 catch (ClassNameNotFoundException cnnfe) { 489 name = odd.toString(); 490 } 491 492 DefaultMutableTreeNode regDocNode = new DefaultMutableTreeNode(name); 493 494 Enumeration documents = _regionRootNode.children(); 496 while (documents.hasMoreElements()) { 497 DefaultMutableTreeNode doc = (DefaultMutableTreeNode)documents.nextElement(); 498 if (doc.getUserObject().equals(regDocNode.getUserObject())) { 499 while(doc.getChildCount()>0) { 500 DefaultMutableTreeNode existing = (DefaultMutableTreeNode)doc.getFirstChild(); 501 @SuppressWarnings ("unchecked") R r = ((RegionTreeUserObj<R>)existing.getUserObject()).region(); 502 _regTreeModel.removeNodeFromParent(existing); 503 } 504 _regTreeModel.removeNodeFromParent(doc); 505 } 506 } 507 updateButtons(); 508 } 509 }; 510 Utilities.invokeLater(doCommand); 511 } 512 513 516 protected class RegionMouseAdapter extends RightClickMouseAdapter { 517 protected void _popupAction(MouseEvent e) { 518 int x = e.getX(); 519 int y = e.getY(); 520 TreePath path = _regTree.getPathForLocation(x, y); 521 if (path != null && path.getPathCount() == 3) { 522 _regTree.setSelectionRow(_regTree.getRowForLocation(x, y)); 523 _regionPopupMenu.show(e.getComponent(), x, y); 524 } 525 } 526 527 public void mousePressed(MouseEvent e) { 528 super.mousePressed(e); 529 if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) { 530 performDefaultAction(); 531 } 532 } 533 } 534 535 537 protected RegionTreeUserObj<R> makeRegionTreeUserObj(R r) { 538 return new RegionTreeUserObj<R>(r); 539 } 540 541 protected class RegionTree extends JTree { 542 public RegionTree(DefaultTreeModel s) { 543 super(s); 544 } 545 546 public void setForeground(Color c) { 547 super.setForeground(c); 548 if (dtcr != null) dtcr.setTextNonSelectionColor(c); 549 } 550 551 public void setBackground(Color c) { 552 super.setBackground(c); 553 if (RegionsTreePanel.this != null && dtcr != null) dtcr.setBackgroundNonSelectionColor(c); 554 } 555 } 556 557 558 protected static class RegionTreeUserObj<R extends DocumentRegion> { 559 protected R _region; 560 public int lineNumber() { return _region.getDocument().getLineOfOffset(_region.getStartOffset())+1; } 561 public R region() { return _region; } 562 public RegionTreeUserObj(R r) { _region = r; } 563 public String toString() { 564 final StringBuilder sb = new StringBuilder (); 565 _region.getDocument().acquireReadLock(); 566 try { 567 sb.append(lineNumber()); 568 try { 569 sb.append(": "); 570 int length = Math.min(120, _region.getEndOffset()-_region.getStartOffset()); 571 sb.append(_region.getDocument().getText(_region.getStartOffset(), length).trim()); 572 } catch(BadLocationException bpe) { } 573 } finally { _region.getDocument().releaseReadLock(); } 574 return sb.toString(); 575 } 576 public boolean equals(Object other) { 577 @SuppressWarnings ("unchecked") RegionTreeUserObj<R> o = (RegionTreeUserObj<R>)other; 578 return (o.region().getDocument().equals(region().getDocument())) && 579 (o.region().getStartOffset()==region().getStartOffset()) && 580 (o.region().getEndOffset()==region().getEndOffset()); 581 } 582 } 583 } 584 | Popular Tags |