1 19 20 package org.netbeans.modules.project.ui; 21 22 import java.awt.BorderLayout ; 23 import java.awt.Image ; 24 import java.awt.Rectangle ; 25 import java.awt.event.ActionEvent ; 26 import java.beans.PropertyChangeEvent ; 27 import java.beans.PropertyChangeListener ; 28 import java.beans.PropertyVetoException ; 29 import java.io.IOException ; 30 import java.io.ObjectInput ; 31 import java.io.ObjectOutput ; 32 import java.util.ArrayList ; 33 import java.util.Arrays ; 34 import java.util.Enumeration ; 35 import java.util.HashMap ; 36 import java.util.Iterator ; 37 import java.util.List ; 38 import java.util.Map ; 39 import javax.swing.AbstractAction ; 40 import javax.swing.Action ; 41 import javax.swing.ActionMap ; 42 import javax.swing.SwingUtilities ; 43 import javax.swing.text.DefaultEditorKit ; 44 import javax.swing.tree.DefaultTreeModel ; 45 import javax.swing.tree.TreeNode ; 46 import javax.swing.tree.TreePath ; 47 import javax.swing.tree.TreeModel ; 48 import org.netbeans.api.project.FileOwnerQuery; 49 import org.netbeans.api.project.Project; 50 import org.netbeans.api.project.ProjectUtils; 51 import org.netbeans.api.project.ui.OpenProjects; 52 import org.netbeans.modules.project.ui.groups.Group; 53 import org.netbeans.spi.project.ActionProvider; 54 import org.openide.DialogDisplayer; 55 import org.openide.ErrorManager; 56 import org.openide.NotifyDescriptor; 57 import org.openide.awt.StatusDisplayer; 58 import org.openide.explorer.ExplorerManager; 59 import org.openide.explorer.ExplorerUtils; 60 import org.openide.explorer.view.BeanTreeView; 61 import org.openide.explorer.view.Visualizer; 62 import org.openide.filesystems.FileObject; 63 import org.openide.nodes.Node; 64 import org.openide.nodes.NodeNotFoundException; 65 import org.openide.nodes.NodeOp; 66 import org.openide.util.HelpCtx; 67 import org.openide.util.NbBundle; 68 import org.openide.util.RequestProcessor; 69 import org.openide.util.Utilities; 70 import org.openide.windows.TopComponent; 71 import org.openide.windows.WindowManager; 72 73 79 public class ProjectTab extends TopComponent 80 implements ExplorerManager.Provider { 81 82 public static final String ID_LOGICAL = "projectTabLogical_tc"; public static final String ID_PHYSICAL = "projectTab_tc"; 85 private static final Image ICON_LOGICAL = org.openide.util.Utilities.loadImage( "org/netbeans/modules/project/ui/resources/projectTab.gif" ); 86 private static final Image ICON_PHYSICAL = org.openide.util.Utilities.loadImage( "org/netbeans/modules/project/ui/resources/filesTab.gif" ); 87 88 private static Map <String , ProjectTab> tabs = new HashMap <String , ProjectTab>(); 89 90 private transient final ExplorerManager manager; 91 private transient Node rootNode; 92 93 private String id; 94 private transient final ProjectTreeView btv; 95 96 public ProjectTab( String id ) { 97 this(); 98 this.id = id; 99 initValues(); 100 } 101 102 public ProjectTab() { 103 104 manager = new ExplorerManager(); 106 107 ActionMap map = getActionMap(); 108 map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager)); 109 map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager)); 110 map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager)); 111 map.put("delete", new DelegatingAction(ActionProvider.COMMAND_DELETE, ExplorerUtils.actionDelete(manager, true))); 112 113 initComponents(); 114 115 btv = new ProjectTreeView(); 117 btv.setDragSource (true); 118 119 btv.setRootVisible(false); 120 121 add( btv, BorderLayout.CENTER ); 122 123 associateLookup( ExplorerUtils.createLookup(manager, map) ); 124 125 } 126 127 131 public void setGroup(Group g) { 132 if (id.equals(ID_LOGICAL)) { 133 if (g != null) { 134 setName(NbBundle.getMessage(ProjectTab.class, "LBL_projectTabLogical_tc_with_group", g.getName())); 135 } else { 136 setName(NbBundle.getMessage(ProjectTab.class, "LBL_projectTabLogical_tc")); 137 } 138 } else { 139 setName(NbBundle.getMessage(ProjectTab.class, "LBL_projectTab_tc")); 140 } 141 } 143 144 private void initValues() { 145 setGroup(Group.getActiveGroup()); 146 147 if (id.equals(ID_LOGICAL)) { 148 setIcon( ICON_LOGICAL ); 149 } 150 else { 151 setIcon( ICON_PHYSICAL ); 152 } 153 154 if ( rootNode == null ) { 155 rootNode = new ProjectsRootNode(id.equals(ID_LOGICAL) ? ProjectsRootNode.LOGICAL_VIEW : ProjectsRootNode.PHYSICAL_VIEW); 157 } 158 manager.setRootContext( rootNode ); 159 } 160 161 163 public ExplorerManager getExplorerManager() { 164 return manager; 165 } 166 167 173 public static synchronized ProjectTab findDefault( String tcID ) { 174 175 ProjectTab tab = tabs.get(tcID); 176 177 if ( tab == null ) { 178 181 TopComponent tc = WindowManager.getDefault().findTopComponent( tcID ); 182 if (tc != null) { 183 if (!(tc instanceof ProjectTab)) { 184 IllegalStateException exc = new IllegalStateException 188 ("Incorrect settings file. Unexpected class returned." + " Expected:" + ProjectTab.class.getName() + " Returned:" + tc.getClass().getName()); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, exc); 192 tab = ProjectTab.getDefault( tcID ); 194 } 195 else { 196 tab = (ProjectTab)tc; 197 } 198 } 199 else { 200 tab = ProjectTab.getDefault( tcID ); 204 } 205 } 206 return tab; 207 } 208 209 212 public static synchronized ProjectTab getDefault( String tcID ) { 213 214 ProjectTab tab = tabs.get(tcID); 215 216 if ( tab == null ) { 217 tab = new ProjectTab( tcID ); 218 tabs.put( tcID, tab ); 219 } 220 221 return tab; 222 } 223 224 public static TopComponent getLogical() { 225 return getDefault( ID_LOGICAL ); 226 } 227 228 public static TopComponent getPhysical() { 229 return getDefault( ID_PHYSICAL ); 230 } 231 232 protected String preferredID () { 233 return id; 234 } 235 236 public HelpCtx getHelpCtx() { 237 return ExplorerUtils.getHelpCtx( 238 manager.getSelectedNodes(), 239 ID_LOGICAL.equals( id ) ? new HelpCtx( "ProjectTab_Projects" ) : new HelpCtx( "ProjectTab_Files" ) ); 240 } 241 242 243 public int getPersistenceType() { 244 return TopComponent.PERSISTENCE_ALWAYS; 245 } 246 247 249 254 private void initComponents() { 256 setLayout(new java.awt.BorderLayout ()); 257 258 } 260 261 264 @SuppressWarnings ("deprecation") 265 public boolean requestFocusInWindow() { 266 super.requestFocusInWindow(); 267 return btv.requestFocusInWindow(); 268 } 269 270 @SuppressWarnings ("deprecation") 272 public void requestFocus() { 273 super.requestFocus(); 274 btv.requestFocus(); 275 } 276 277 279 private static final long serialVersionUID = 9374872358L; 280 281 public void writeExternal (ObjectOutput out) throws IOException { 282 super.writeExternal( out ); 283 284 out.writeObject( id ); 285 out.writeObject( rootNode.getHandle() ); 286 out.writeObject( btv.getExpandedPaths() ); 287 out.writeObject( getSelectedPaths() ); 288 } 289 290 @SuppressWarnings ("unchecked") 291 public void readExternal (ObjectInput in) throws IOException , ClassNotFoundException { 292 super.readExternal( in ); 293 id = (String )in.readObject(); 294 rootNode = ((Node.Handle )in.readObject()).getNode(); 295 List <String []> exPaths = (List <String []>)in.readObject(); 296 List <String []> selPaths = null; 297 try { 298 selPaths = (List <String []>)in.readObject(); 299 } 300 catch ( java.io.OptionalDataException e ) { 301 } 303 initValues(); 304 if (System.getProperty ("netbeans.keep.expansion") != null) 309 { 310 btv.expandNodes( exPaths ); 311 selectPaths( selPaths ); 312 } 313 314 } 315 316 318 protected void componentActivated() { 319 ExplorerUtils.activateActions(manager, true); 320 } 321 322 protected void componentDeactivated() { 323 ExplorerUtils.activateActions(manager, false); 324 } 325 326 @Override 327 public Action [] getActions() { 328 Action [] actions = super.getActions(); 329 if (ID_LOGICAL.equals(id)) { 330 List <Action > allActions = new ArrayList <Action >(Arrays.asList(manager.getRootContext().getActions(false))); 331 allActions.add(null); 332 allActions.addAll(Arrays.asList(actions)); 333 return allActions.toArray(new Action [allActions.size()]); 334 } else { 335 return actions; 336 } 337 } 338 339 340 341 343 345 private final RequestProcessor RP = new RequestProcessor(); 346 347 public void selectNodeAsync(final FileObject object) { 348 349 setCursor( Utilities.createProgressCursor( this ) ); 350 open(); 351 requestActive(); 352 353 RP.post( new Runnable () { 355 public void run() { 356 ProjectsRootNode root = (ProjectsRootNode)manager.getRootContext(); 357 Node tempNode = root.findNode( object ); 358 if (tempNode == null) { 359 Project project = FileOwnerQuery.getOwner(object); 360 if (project != null && !OpenProjectList.getDefault().isOpen(project)) { 361 DialogDisplayer dd = DialogDisplayer.getDefault(); 362 String message = NbBundle.getMessage(ProjectTab.class, "MSG_openProject_confirm", ProjectUtils.getInformation(project).getDisplayName()); 364 String title = NbBundle.getMessage(ProjectTab.class, "MSG_openProject_confirm_title"); NotifyDescriptor.Confirmation confirm = 366 new NotifyDescriptor.Confirmation(message, title, NotifyDescriptor.OK_CANCEL_OPTION); 367 DialogDisplayer.getDefault().notify(confirm); 368 if (confirm.getValue() == NotifyDescriptor.OK_OPTION) { 369 if (!OpenProjectList.getDefault().isOpen(project)) { 370 OpenProjects.getDefault().open(new Project[] { project }, false); 371 } 372 tempNode = root.findNode( object ); 373 } 374 } 375 } 376 final Node selectedNode = tempNode; 377 SwingUtilities.invokeLater( new Runnable () { 379 public void run() { 380 if ( selectedNode != null ) { 381 try { 382 manager.setSelectedNodes( new Node [] { selectedNode } ); 383 btv.scrollToNode(selectedNode); 384 StatusDisplayer.getDefault().setStatusText( "" ); } 386 catch ( PropertyVetoException e ) { 387 } 389 } 390 else { 391 StatusDisplayer.getDefault().setStatusText( 392 NbBundle.getMessage( ProjectTab.class, 393 ID_LOGICAL.equals( id ) ? "MSG_NodeNotFound_ProjectsTab" : "MSG_NodeNotFound_FilesTab" ) ); } 395 setCursor( null ); 396 } 397 } ); 398 } 399 } ); 400 401 } 402 403 public boolean selectNode(FileObject object) { 404 406 ProjectsRootNode root = (ProjectsRootNode)manager.getRootContext(); 407 Node selectedNode = root.findNode( object ); 408 if ( selectedNode != null ) { 409 try { 410 manager.setSelectedNodes( new Node [] { selectedNode } ); 411 btv.scrollToNode(selectedNode); 412 return true; 413 } 414 catch ( PropertyVetoException e ) { 415 return false; 417 } 418 } 419 420 return false; 421 } 422 423 public void expandNode( Node node ) { 424 btv.expandNode( node ); 425 } 426 427 private List <String []> getSelectedPaths() { 428 Node selectedNodes[] = manager.getSelectedNodes(); 429 List <String []> result = new ArrayList <String []>(); 430 Node rootNode = manager.getRootContext(); 431 432 for( int i = 0; i < selectedNodes.length; i++ ) { 433 String [] path = NodeOp.createPath( selectedNodes[i], rootNode ); 434 if ( path != null ) { 435 result.add( path ); 436 } 437 } 438 439 return result; 440 } 441 442 443 private void selectPaths( List <String []> paths ) { 444 445 if ( paths == null ) { 446 return; 447 } 448 449 List <Node > selectedNodes = new ArrayList <Node >(); 450 451 Node rootNode = manager.getRootContext(); 452 453 for( Iterator <String []> it = paths.iterator(); it.hasNext(); ) { 454 String [] sp = it.next(); 455 try { 456 Node n = NodeOp.findPath( rootNode, sp ); 457 if ( n != null ) { 458 selectedNodes.add( n ); 459 } 460 } 461 catch( NodeNotFoundException e ) { 462 } 464 } 465 466 if ( !selectedNodes.isEmpty() ) { 467 Node nodes[] = new Node [ selectedNodes.size() ]; 468 selectedNodes.toArray( nodes ); 469 try { 470 manager.setSelectedNodes( nodes ); 471 } 472 catch( PropertyVetoException e ) { 473 } 475 } 476 477 } 478 479 481 483 private class ProjectTreeView extends BeanTreeView { 484 public void scrollToNode(Node n) { 485 TreeNode tn = Visualizer.findVisualizer( n ); 486 if (tn == null) return; 487 488 TreeModel model = tree.getModel(); 489 if (!(model instanceof DefaultTreeModel )) return; 490 491 TreePath path = new TreePath (((DefaultTreeModel )model).getPathToRoot(tn)); 492 Rectangle r = tree.getPathBounds(path); 493 if (r != null) tree.scrollRectToVisible(r); 494 } 495 496 public List <String []> getExpandedPaths() { 497 498 List <String []> result = new ArrayList <String []>(); 499 500 TreeNode rtn = Visualizer.findVisualizer( rootNode ); 501 TreePath tp = new TreePath ( rtn ); 503 for( Enumeration exPaths = tree.getExpandedDescendants( tp ); exPaths != null && exPaths.hasMoreElements(); ) { 504 TreePath ep = (TreePath )exPaths.nextElement(); 505 Node en = Visualizer.findNode( ep.getLastPathComponent() ); 506 String [] path = NodeOp.createPath( en, rootNode ); 507 508 510 result.add( path ); 511 } 512 513 return result; 514 515 } 516 517 519 public void expandNodes( List exPaths ) { 520 521 for( Iterator it = exPaths.iterator(); it.hasNext(); ) { 522 String [] sp = (String [])it.next(); 523 TreePath tp = stringPath2TreePath( sp ); 524 525 if ( tp != null ) { 526 showPath( tp ); 527 } 528 } 529 } 530 531 532 533 535 private TreePath stringPath2TreePath( String [] sp ) { 536 537 try { 538 Node n = NodeOp.findPath( rootNode, sp ); 539 540 TreeNode tns[] = new TreeNode [ sp.length + 1 ]; 542 543 for ( int i = sp.length; i >= 0; i--) { 544 if ( n == null ) { return null; } 547 tns[i] = Visualizer.findVisualizer( n ); 548 n = n.getParentNode(); 549 } 550 return new TreePath ( tns ); 551 } 552 catch ( NodeNotFoundException e ) { 553 return null; 554 } 555 } 556 557 } 558 559 private class DelegatingAction extends AbstractAction implements PropertyChangeListener { 560 561 private Action explorerAction; 562 private String projectAction; 563 564 public DelegatingAction(String projectAction, Action explorerAction) { 565 this.projectAction = projectAction; 566 this.explorerAction = explorerAction; 567 568 manager.addPropertyChangeListener(this); 569 explorerAction.addPropertyChangeListener(this); 570 } 571 572 private boolean isProject() { 573 Node [] nodes = manager.getSelectedNodes(); 574 575 if (nodes.length == 1) { 576 return nodes[0].getParentNode() == rootNode; 577 } 578 579 return false; 580 } 581 582 public void actionPerformed(ActionEvent e) { 583 if (isProject()) { 584 Node [] nodes = manager.getSelectedNodes(); 585 Project p = nodes[0].getLookup().lookup(Project.class); 586 587 assert p != null; 588 589 ActionProvider ap = p.getLookup().lookup(ActionProvider.class); 590 591 ap.invokeAction(projectAction, nodes[0].getLookup()); 592 } else { 593 explorerAction.actionPerformed(e); 594 } 595 } 596 597 public void updateIsEnabled() { 598 if (isProject()) { 599 Node [] nodes = manager.getSelectedNodes(); 600 Project p = nodes[0].getLookup().lookup(Project.class); 601 602 if (p == null) { 603 setEnabled(false); 604 return ; 605 } 606 607 ActionProvider ap = p.getLookup().lookup(ActionProvider.class); 608 609 String [] sa = ap != null ? ap.getSupportedActions() : new String [0]; 611 int k = sa.length; 612 613 for (int i = 0; i < k; i++) { 614 if (ActionProvider.COMMAND_DELETE.equals(sa [i])) { 615 setEnabled(ap.isActionEnabled(projectAction, nodes[0].getLookup())); 616 return ; 617 } 618 } 619 620 setEnabled(false); 621 } else { 622 setEnabled(explorerAction.isEnabled()); 623 } 624 } 625 626 public void propertyChange(PropertyChangeEvent evt) { 627 updateIsEnabled(); 629 } 630 631 } 632 633 } 634 | Popular Tags |