1 19 20 package org.netbeans.modules.web.project.ui; 21 22 import java.awt.Image ; 23 import java.beans.PropertyChangeEvent ; 24 import java.beans.PropertyChangeListener ; 25 import java.io.File ; 26 import java.util.ArrayList ; 27 import java.util.Arrays ; 28 import java.util.Collection ; 29 import java.util.HashMap ; 30 import java.util.HashSet ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 import javax.swing.SwingUtilities ; 36 import javax.swing.event.ChangeEvent ; 37 import javax.swing.event.ChangeListener ; 38 import org.netbeans.api.project.Project; 39 import org.netbeans.api.project.ProjectUtils; 40 import org.netbeans.api.project.SourceGroup; 41 import org.netbeans.api.project.Sources; 42 import org.netbeans.api.queries.VisibilityQuery; 43 import org.netbeans.modules.j2ee.deployment.devmodules.spi.ConfigurationFilesListener; 44 import org.netbeans.modules.web.api.webmodule.WebFrameworkSupport; 45 import org.netbeans.modules.web.api.webmodule.WebModule; 46 import org.netbeans.modules.web.project.ProjectWebModule; 47 import org.netbeans.modules.web.project.WebProject; 48 import org.netbeans.modules.web.spi.webmodule.WebFrameworkProvider; 49 import org.netbeans.spi.project.ui.support.NodeFactory; 50 import org.netbeans.spi.project.ui.support.NodeList; 51 import org.openide.ErrorManager; 52 import org.openide.actions.FindAction; 53 import org.openide.filesystems.FileChangeAdapter; 54 import org.openide.filesystems.FileChangeListener; 55 import org.openide.filesystems.FileEvent; 56 import org.openide.filesystems.FileObject; 57 import org.openide.filesystems.FileRenameEvent; 58 import org.openide.filesystems.FileStateInvalidException; 59 import org.openide.filesystems.FileStatusEvent; 60 import org.openide.filesystems.FileStatusListener; 61 import org.openide.filesystems.FileSystem; 62 import org.openide.filesystems.FileUtil; 63 import org.openide.loaders.DataFolder; 64 import org.openide.loaders.DataObject; 65 import org.openide.loaders.DataObjectNotFoundException; 66 import org.openide.nodes.Children; 67 import org.openide.nodes.Node; 68 import org.openide.util.HelpCtx; 69 import org.openide.util.Lookup; 70 import org.openide.util.NbBundle; 71 import org.openide.util.RequestProcessor; 72 import org.openide.util.Utilities; 73 import org.openide.util.WeakListeners; 74 import org.openide.util.actions.CookieAction; 75 import org.openide.util.actions.SystemAction; 76 import org.openide.util.lookup.Lookups; 77 78 82 public final class ConfFilesNodeFactory implements NodeFactory { 83 84 85 public ConfFilesNodeFactory() { 86 } 87 88 public NodeList createNodes(Project p) { 89 WebProject project = (WebProject)p.getLookup().lookup(WebProject.class); 90 assert project != null; 91 return new ConfFilesNodeList(project); 92 } 93 94 private static class ConfFilesNodeList implements NodeList<String >, PropertyChangeListener { 95 private static final String CONF_FILES = "confFiles"; 97 private final WebProject project; 98 private final ArrayList <ChangeListener > listeners = new ArrayList <ChangeListener >(); 99 100 ConfFilesNodeList(WebProject proj) { 101 project = proj; 102 WebLogicalViewProvider logView = (WebLogicalViewProvider) project.getLookup().lookup(WebLogicalViewProvider.class); 103 assert logView != null; 104 } 105 106 public List <String > keys() { 107 List <String > result = new ArrayList <String >(); 108 result.add(CONF_FILES); 109 return result; 110 } 111 112 public synchronized void addChangeListener(ChangeListener l) { 113 listeners.add(l); 114 } 115 116 public synchronized void removeChangeListener(ChangeListener l) { 117 listeners.remove(l); 118 } 119 120 private void fireChange() { 121 ArrayList <ChangeListener > list = new ArrayList <ChangeListener >(); 122 synchronized (this) { 123 list.addAll(listeners); 124 } 125 Iterator <ChangeListener > it = list.iterator(); 126 while (it.hasNext()) { 127 ChangeListener elem = it.next(); 128 elem.stateChanged(new ChangeEvent ( this )); 129 } 130 } 131 132 public Node node(String key) { 133 if (key == CONF_FILES) { 134 return new ConfFilesNode(project); 135 } 136 assert false: "No node for key: " + key; 137 return null; 138 } 139 140 public void addNotify() { 141 } 142 143 public void removeNotify() { 144 } 145 146 public void propertyChange(PropertyChangeEvent evt) { 147 SwingUtilities.invokeLater(new Runnable () { 149 public void run() { 150 fireChange(); 151 } 152 }); 153 } 154 155 } 156 157 private static Lookup createLookup(Project project) { 158 DataFolder rootFolder = DataFolder.findFolder(project.getProjectDirectory()); 159 return Lookups.fixed(new Object [] {project, rootFolder}); 161 } 162 163 private static final class ConfFilesNode extends org.openide.nodes.AbstractNode implements Runnable , FileStatusListener, ChangeListener , PropertyChangeListener { 164 private static final Image CONFIGURATION_FILES_BADGE = Utilities.loadImage( "org/netbeans/modules/web/project/ui/resources/config-badge.gif", true ); 166 private Node projectNode; 167 168 private Set files; 170 private Map fileSystemListeners; 171 private RequestProcessor.Task task; 172 private final Object privateLock = new Object (); 173 private boolean iconChange; 174 private boolean nameChange; 175 private ChangeListener sourcesListener; 176 private Map groupsListeners; 177 private final Project project; 178 180 public ConfFilesNode(Project prj) { 181 super(ConfFilesChildren.forProject(prj), createLookup(prj)); 182 this.project = prj; 183 setName("configurationFiles"); 185 FileObject projectDir = prj.getProjectDirectory(); 186 try { 187 DataObject projectDo = DataObject.find(projectDir); 188 if (projectDo != null) 189 projectNode = projectDo.getNodeDelegate(); 190 } 191 catch (DataObjectNotFoundException e) {} 192 } 193 194 public Image getIcon(int type) { 195 Image img = computeIcon(false, type); 196 return (img != null) ? img: super.getIcon(type); 197 } 198 199 public Image getOpenedIcon(int type) { 200 Image img = computeIcon(true, type); 201 return (img != null) ? img: super.getIcon(type); 202 } 203 204 private Image computeIcon(boolean opened, int type) { 205 if (projectNode == null) 206 return null; 207 208 Image image = opened ? projectNode.getOpenedIcon(type) : projectNode.getIcon(type); 209 image = Utilities.mergeImages(image, CONFIGURATION_FILES_BADGE, 7, 7); 210 return image; 211 } 212 213 public String getDisplayName() { 214 return NbBundle.getMessage(ConfFilesNodeFactory.class, "LBL_Node_Config"); } 216 217 public javax.swing.Action [] getActions(boolean context) { 218 return new javax.swing.Action [] { 219 SystemAction.get(FindAction.class), 220 }; 221 } 222 223 public void run() { 224 boolean fireIcon; 225 boolean fireName; 226 synchronized (privateLock) { 227 fireIcon = iconChange; 228 fireName = nameChange; 229 iconChange = false; 230 nameChange = false; 231 } 232 if (fireIcon) { 233 fireIconChange(); 234 fireOpenedIconChange(); 235 } 236 if (fireName) { 237 fireDisplayNameChange(null, null); 238 } 239 } 240 241 public void annotationChanged(FileStatusEvent event) { 242 if (task == null) { 243 task = RequestProcessor.getDefault().create(this); 244 } 245 246 synchronized (privateLock) { 247 if ((!iconChange && event.isIconChange()) || (!nameChange && event.isNameChange())) { 248 Iterator it = files.iterator(); 249 while (it.hasNext()) { 250 FileObject fo = (FileObject) it.next(); 251 if (event.hasChanged(fo)) { 252 iconChange |= event.isIconChange(); 253 nameChange |= event.isNameChange(); 254 } 255 } 256 } 257 } 258 259 task.schedule(50); } 261 262 public void stateChanged(ChangeEvent e) { 263 setProjectFiles(project); 264 } 265 266 public void propertyChange(PropertyChangeEvent evt) { 267 setProjectFiles(project); 268 } 269 270 protected void setProjectFiles(Project project) { 271 Sources sources = ProjectUtils.getSources(project); if (sourcesListener == null) { 273 sourcesListener = WeakListeners.change(this, sources); 274 sources.addChangeListener(sourcesListener); 275 } 276 setGroups(Arrays.asList(sources.getSourceGroups(Sources.TYPE_GENERIC))); 277 } 278 279 private void setGroups(Collection groups) { 280 if (groupsListeners != null) { 281 Iterator it = groupsListeners.keySet().iterator(); 282 while (it.hasNext()) { 283 SourceGroup group = (SourceGroup) it.next(); 284 PropertyChangeListener pcl = (PropertyChangeListener ) groupsListeners.get(group); 285 group.removePropertyChangeListener(pcl); 286 } 287 } 288 groupsListeners = new HashMap (); 289 Set roots = new HashSet (); 290 Iterator it = groups.iterator(); 291 while (it.hasNext()) { 292 SourceGroup group = (SourceGroup) it.next(); 293 PropertyChangeListener pcl = WeakListeners.propertyChange(this, group); 294 groupsListeners.put(group, pcl); 295 group.addPropertyChangeListener(pcl); 296 FileObject fo = group.getRootFolder(); 297 roots.add(fo); 298 } 299 setFiles(roots); 300 } 301 302 protected void setFiles(Set files) { 303 if (fileSystemListeners != null) { 304 Iterator it = fileSystemListeners.keySet().iterator(); 305 while (it.hasNext()) { 306 FileSystem fs = (FileSystem) it.next(); 307 FileStatusListener fsl = (FileStatusListener) fileSystemListeners.get(fs); 308 fs.removeFileStatusListener(fsl); 309 } 310 } 311 312 fileSystemListeners = new HashMap (); 313 this.files = files; 314 if (files == null) return; 315 316 Iterator it = files.iterator(); 317 Set hookedFileSystems = new HashSet (); 318 while (it.hasNext()) { 319 FileObject fo = (FileObject) it.next(); 320 try { 321 FileSystem fs = fo.getFileSystem(); 322 if (hookedFileSystems.contains(fs)) { 323 continue; 324 } 325 hookedFileSystems.add(fs); 326 FileStatusListener fsl = FileUtil.weakFileStatusListener(this, fs); 327 fs.addFileStatusListener(fsl); 328 fileSystemListeners.put(fs, fsl); 329 } catch (FileStateInvalidException e) { 330 ErrorManager err = ErrorManager.getDefault(); 331 err.annotate(e, "Can not get " + fo + " filesystem, ignoring..."); err.notify(ErrorManager.INFORMATIONAL, e); 333 } 334 } 335 } 336 } 337 338 private static final class ConfFilesChildren extends Children.Keys { 339 340 private final static String [] wellKnownFiles = { 341 "web.xml", 342 "webservices.xml", 343 "struts-config.xml", 344 "faces-config.xml", 345 "portlet.xml", 346 "navigator.xml", 348 "managed-beans.xml" 349 }; 351 private final ProjectWebModule pwm; 352 private final HashSet keys; 353 private final java.util.Comparator comparator = new NodeComparator(); 354 355 private final FileChangeListener webInfListener = new FileChangeAdapter() { 356 public void fileDataCreated(FileEvent fe) { 357 if (isWellKnownFile(fe.getFile().getNameExt())) 358 addKey(fe.getFile()); 359 } 360 361 public void fileRenamed(FileRenameEvent fe) { 362 if (keys.contains(fe.getFile())) { 365 if (!isWellKnownFile(fe.getFile().getNameExt())) 367 removeKey(fe.getFile()); 368 else 369 doSetKeys(); 371 } else { 372 if (isWellKnownFile(fe.getFile().getNameExt())) 374 addKey(fe.getFile()); 375 } 376 } 377 378 public void fileDeleted(FileEvent fe) { 379 if (isWellKnownFile(fe.getFile().getNameExt())) { 380 removeKey(fe.getFile()); 381 } 382 } 383 }; 384 385 private final FileChangeListener anyFileListener = new FileChangeAdapter() { 386 public void fileDataCreated(FileEvent fe) { 387 addKey(fe.getFile()); 388 } 389 390 public void fileFolderCreated(FileEvent fe) { 391 addKey(fe.getFile()); 392 } 393 394 public void fileRenamed(FileRenameEvent fe) { 395 addKey(fe.getFile()); 396 } 397 398 public void fileDeleted(FileEvent fe) { 399 removeKey(fe.getFile()); 400 } 401 }; 402 403 private final ConfigurationFilesListener serverSpecificFilesListener = new ConfigurationFilesListener() { 404 public void fileCreated(FileObject fo) { 405 addKey(fo); 406 } 407 408 public void fileDeleted(FileObject fo) { 409 removeKey(fo); 410 } 411 }; 412 413 private ConfFilesChildren(ProjectWebModule pwm) { 414 this.pwm = pwm; 415 keys = new HashSet (); 416 } 417 418 public static Children forProject(Project project) { 419 ProjectWebModule pwm = (ProjectWebModule)project.getLookup().lookup(ProjectWebModule.class); 420 return new ConfFilesChildren(pwm); 421 } 422 423 protected void addNotify() { 424 createKeys(); 425 doSetKeys(); 426 } 427 428 protected void removeNotify() { 429 removeListeners(); 430 } 431 432 public Node[] createNodes(Object key) { 433 Node n = null; 434 435 if (keys.contains(key)) { 436 FileObject fo = (FileObject)key; 437 try { 438 DataObject dataObject = DataObject.find(fo); 439 n = dataObject.getNodeDelegate().cloneNode(); 440 } 441 catch (DataObjectNotFoundException dnfe) {} 442 } 443 444 return (n == null) ? new Node[0] : new Node[] { n }; 445 } 446 447 public synchronized void refreshNodes() { 448 addNotify(); 449 } 450 451 private synchronized void addKey(FileObject key) { 452 if (VisibilityQuery.getDefault().isVisible(key)) { 453 keys.add(key); 455 doSetKeys(); 456 } 457 } 458 459 private synchronized void removeKey(FileObject key) { 460 keys.remove(key); 462 doSetKeys(); 463 } 464 465 private synchronized void createKeys() { 466 keys.clear(); 467 468 addWellKnownFiles(); 469 addConfDirectoryFiles(); 470 addServerSpecificFiles(); 471 addFrameworkFiles(); 472 } 473 474 private void doSetKeys() { 475 Object [] result = keys.toArray(); 476 java.util.Arrays.sort(result, comparator); 477 setKeys(result); 480 } 481 482 private void addWellKnownFiles() { 483 FileObject webInf = pwm.getWebInf(true); 484 if (webInf == null) 485 return; 486 487 for (int i = 0; i < wellKnownFiles.length; i++) { 488 FileObject fo = webInf.getFileObject(wellKnownFiles[i]); 489 if (fo != null) 490 keys.add(fo); 491 } 492 493 webInf.addFileChangeListener(webInfListener); 494 } 495 496 private void addConfDirectoryFiles() { 497 FileObject conf = pwm.getConfDir(); 498 if (conf == null) 499 return; 500 501 FileObject[] children = conf.getChildren(); 502 for (int i = 0; i < children.length; i++) { 503 if (VisibilityQuery.getDefault().isVisible(children[i])) 504 keys.add(children[i]); 505 } 506 507 conf.addFileChangeListener(anyFileListener); 508 } 509 510 private void addServerSpecificFiles() { 511 FileObject[] files = pwm.getConfigurationFiles(); 512 513 for (int i = 0; i < files.length; i++) { 514 keys.add(files[i]); 515 } 516 517 pwm.addConfigurationFilesListener(serverSpecificFilesListener); 518 } 519 520 private void addFrameworkFiles(){ 521 List providers = WebFrameworkSupport.getFrameworkProviders(); 522 for (int i = 0; i < providers.size(); i++){ 523 WebFrameworkProvider provider = (WebFrameworkProvider)providers.get(i); 524 FileObject wmBase = pwm.getDocumentBase(); 525 File files[] = null; 526 if (wmBase != null) { 527 files = provider.getConfigurationFiles(WebModule.getWebModule(wmBase)); 528 } 529 if (files != null){ 530 for (int j = 0; j < files.length; j++){ 531 FileObject fo = FileUtil.toFileObject(files[j]); 532 if (fo != null){ 533 keys.add(fo); 534 } 537 } 538 } 539 } 540 } 541 542 private void removeListeners() { 543 pwm.removeConfigurationFilesListener(serverSpecificFilesListener); 544 545 FileObject webInf = pwm.getWebInf(true); 546 if (webInf != null) 547 pwm.getWebInf().removeFileChangeListener(webInfListener); 548 549 FileObject conf = pwm.getConfDir(); 550 if (conf != null) 551 conf.removeFileChangeListener(anyFileListener); 552 } 553 554 private boolean isWellKnownFile(String name) { 555 for (int i = 0; i < wellKnownFiles.length; i++) 556 if (name.equals(wellKnownFiles[i])) 557 return true; 558 559 return false; 560 } 561 562 private static final class NodeComparator implements java.util.Comparator { 563 public int compare(Object o1, Object o2) { 564 FileObject fo1 = (FileObject)o1; 565 FileObject fo2 = (FileObject)o2; 566 567 int result = compareType(fo1, fo2); 568 if (result == 0) 569 result = compareNames(fo1, fo2); 570 if (result == 0) 571 return fo1.getPath().compareTo(fo2.getPath()); 572 573 return result; 574 } 575 576 private int compareType(FileObject fo1, FileObject fo2) { 577 int folder1 = fo1.isFolder() ? 0 : 1; 578 int folder2 = fo2.isFolder() ? 0 : 1; 579 580 return folder1 - folder2; 581 } 582 583 private int compareNames(FileObject do1, FileObject do2) { 584 return do1.getNameExt().compareTo(do2.getNameExt()); 585 } 586 587 public boolean equals(Object o) { 588 return (o instanceof NodeComparator); 589 } 590 } 591 } 592 593 private static class ConfFilesRefreshAction extends CookieAction { 594 595 protected Class [] cookieClasses() { 596 return new Class [] { RefreshCookie.class }; 597 } 598 599 protected boolean enable(Node[] activatedNodes) { 600 return true; 601 } 602 603 protected int mode() { 604 return CookieAction.MODE_EXACTLY_ONE; 605 } 606 607 protected boolean asynchronous() { 608 return false; 609 } 610 611 public String getName() { 612 return NbBundle.getMessage(ConfFilesNodeFactory.class, "LBL_Refresh"); } 614 615 public HelpCtx getHelpCtx() { 616 return HelpCtx.DEFAULT_HELP; 617 } 618 619 public void performAction(Node[] selectedNodes) { 620 for (int i = 0; i < selectedNodes.length; i++) { 621 RefreshCookie cookie = (RefreshCookie)selectedNodes[i].getCookie(RefreshCookie.class); 622 cookie.refresh(); 623 } 624 } 625 626 private interface RefreshCookie extends Node.Cookie { 627 public void refresh(); 628 } 629 } 630 631 } 632 | Popular Tags |