1 19 20 package org.netbeans.modules.ruby.railsprojects.ui; 21 22 import java.awt.Image ; 23 import java.beans.PropertyChangeEvent ; 24 import java.beans.PropertyChangeListener ; 25 import java.util.ArrayList ; 26 import java.util.Collections ; 27 import java.util.List ; 28 import java.util.StringTokenizer ; 29 import javax.swing.Action ; 30 import javax.swing.Icon ; 31 import javax.swing.event.ChangeEvent ; 32 import javax.swing.event.ChangeListener ; 33 import javax.swing.event.EventListenerList ; 34 import org.netbeans.modules.ruby.railsprojects.GenerateAction; 35 import org.netbeans.modules.ruby.railsprojects.GenerateAction; 36 import org.netbeans.modules.ruby.railsprojects.Generator; 37 import org.netbeans.api.project.SourceGroup; 38 import org.netbeans.api.queries.VisibilityQuery; 39 import org.netbeans.spi.project.ui.support.CommonProjectActions; 40 import org.openide.DialogDisplayer; 41 import org.openide.NotifyDescriptor; 42 import org.openide.filesystems.FileObject; 43 import org.openide.filesystems.FileUtil; 44 import org.openide.loaders.ChangeableDataFilter; 45 import org.openide.loaders.DataFilter; 46 import org.openide.loaders.DataFolder; 47 import org.openide.loaders.DataObject; 48 import org.openide.nodes.FilterNode; 49 import org.openide.nodes.Node; 50 import org.openide.nodes.NodeNotFoundException; 51 import org.openide.nodes.NodeOp; 52 import org.openide.util.NbBundle; 53 import org.openide.util.Utilities; 54 import org.openide.util.WeakListeners; 55 import org.openide.util.actions.SystemAction; 56 import org.openide.util.lookup.Lookups; 57 import org.openide.util.lookup.ProxyLookup; 58 59 61 67 public final class TreeRootNode extends FilterNode implements PropertyChangeListener { 68 69 private static final DataFilter VISIBILITY_QUERY_FILTER = new VisibilityQueryDataFilter(); 70 71 private final SourceGroup g; 72 private final Generator generator; 73 74 public TreeRootNode(SourceGroup g, Generator generator) { 75 this(DataFolder.findFolder(g.getRootFolder()), g, generator); 76 } 77 78 private TreeRootNode(DataFolder folder, SourceGroup g, Generator generator) { 79 this (new FilterNode (folder.getNodeDelegate(), folder.createNodeChildren(VISIBILITY_QUERY_FILTER)), g, generator); 80 } 81 82 private TreeRootNode (Node originalNode, SourceGroup g, Generator generator) { 83 super(originalNode, new PackageFilterChildren(originalNode), 84 new ProxyLookup( 85 originalNode.getLookup(), 86 Lookups.singleton(generator), 87 Lookups.singleton(new PathFinder(g)) 88 )); 90 this.g = g; 91 this.generator = generator; 92 g.addPropertyChangeListener(WeakListeners.propertyChange(this, g)); 93 } 94 95 static Image PACKAGE_BADGE = Utilities.loadImage( "org/netbeans/modules/ruby/railsprojects/ui/packageBadge.gif" ); 97 98 private Image computeIcon(boolean opened, int type) { 99 Icon icon = g.getIcon(opened); 100 if (icon == null) { 101 Image image = opened ? super.getOpenedIcon(type) : super.getIcon(type); 102 return Utilities.mergeImages(image, PACKAGE_BADGE, 7, 7); 103 } else { 104 return Utilities.icon2Image(icon); 105 } 106 } 107 108 public Image getIcon(int type) { 109 return computeIcon(false, type); 110 } 111 112 public Image getOpenedIcon(int type) { 113 return computeIcon(true, type); 114 } 115 116 public String getName() { 117 return g.getName(); 118 } 119 120 public String getDisplayName() { 121 return g.getDisplayName(); 122 } 123 124 public boolean canRename() { 125 return false; 126 } 127 128 public boolean canDestroy() { 129 return false; 130 } 131 132 public boolean canCut() { 133 return false; 134 } 135 136 public void propertyChange(PropertyChangeEvent ev) { 137 fireNameChange(null, null); 139 fireDisplayNameChange(null, null); 140 fireIconChange(); 141 fireOpenedIconChange(); 142 } 143 144 145 public Action [] getActions(boolean context) { 146 Action [] result = initActions(); 147 return result; 148 } 149 150 151 public Action getPreferredAction() { 152 return SystemAction.get(GenerateAction.class); 153 } 154 155 private Action [] actionCache; 157 private Action [] initActions () { 158 if (generator == Generator.NONE) { 159 return super.getActions(); 160 } 161 162 if (actionCache == null) { 163 Action [] existing = super.getActions(); 164 Action [] additional = new Action [] { SystemAction.get(GenerateAction.class), null, CommonProjectActions.newFileAction(), null }; if (existing != null && existing.length > 0) { 166 actionCache = new Action [existing.length+additional.length]; 167 System.arraycopy(additional, 0, actionCache, 0, additional.length); 168 System.arraycopy(existing, 0, actionCache, additional.length, existing.length); 169 } else { 170 actionCache = additional; 171 } 172 } 173 return actionCache; 174 } 175 176 177 178 179 public static final class PathFinder { 180 181 private final SourceGroup g; 182 183 PathFinder(SourceGroup g) { 184 this.g = g; 185 } 186 187 public Node findPath(Node rootNode, Object o) { 188 FileObject fo; 189 if (o instanceof FileObject) { 190 fo = (FileObject) o; 191 } else if (o instanceof DataObject) { 192 fo = ((DataObject) o).getPrimaryFile(); 193 } else { 194 return null; 195 } 196 FileObject groupRoot = g.getRootFolder(); 197 if (FileUtil.isParentOf(groupRoot, fo) ) { 198 FileObject folder = fo.isFolder() ? fo : fo.getParent(); 199 String relPath = FileUtil.getRelativePath(groupRoot, folder); 200 List <String > path = new ArrayList <String >(); 201 StringTokenizer strtok = new StringTokenizer (relPath, "/"); while (strtok.hasMoreTokens()) { 203 String token = strtok.nextToken(); 204 path.add(token); 205 } 206 try { 207 Node folderNode = folder.equals(groupRoot) ? rootNode : NodeOp.findPath(rootNode, Collections.enumeration(path)); 208 if (fo.isFolder()) { 209 return folderNode; 210 } else { 211 Node[] childs = folderNode.getChildren().getNodes(true); 212 for (int i = 0; i < childs.length; i++) { 213 DataObject dobj = childs[i].getLookup().lookup(DataObject.class); 214 if (dobj != null && dobj.getPrimaryFile().getNameExt().equals(fo.getNameExt())) { 215 return childs[i]; 216 } 217 } 218 } 219 } catch (NodeNotFoundException e) { 220 e.printStackTrace(); 221 } 222 } else if (groupRoot.equals(fo)) { 223 return rootNode; 224 } 225 return null; 226 } 227 } 228 229 230 private static final class VisibilityQueryDataFilter implements ChangeListener , ChangeableDataFilter { 231 232 private static final long serialVersionUID = 1L; 234 private final EventListenerList ell = new EventListenerList (); 235 236 public VisibilityQueryDataFilter() { 237 VisibilityQuery.getDefault().addChangeListener(this); 238 } 239 240 public boolean acceptDataObject(DataObject obj) { 241 FileObject fo = obj.getPrimaryFile(); 242 return VisibilityQuery.getDefault().isVisible(fo); 243 } 244 245 public void stateChanged(ChangeEvent e) { 246 Object [] listeners = ell.getListenerList(); 247 ChangeEvent event = null; 248 for (int i = listeners.length - 2; i >= 0; i -= 2) { 249 if (listeners[i] == ChangeListener .class) { 250 if (event == null) { 251 event = new ChangeEvent (this); 252 } 253 ((ChangeListener ) listeners[i+1]).stateChanged(event); 254 } 255 } 256 } 257 258 public void addChangeListener(ChangeListener listener) { 259 ell.add(ChangeListener .class, listener); 260 } 261 262 public void removeChangeListener(ChangeListener listener) { 263 ell.remove(ChangeListener .class, listener); 264 } 265 266 } 267 268 269 private static final class PackageFilterChildren extends FilterNode.Children { 270 271 public PackageFilterChildren (final Node originalNode) { 272 super (originalNode); 273 } 274 275 @Override 276 protected Node copyNode(final Node originalNode) { 277 DataObject dobj = originalNode.getLookup().lookup(DataObject.class); 278 return (dobj instanceof DataFolder) ? new PackageFilterNode (originalNode) : super.copyNode(originalNode); 279 } 280 } 281 282 private static final class PackageFilterNode extends FilterNode { 283 284 public PackageFilterNode (final Node origNode) { 285 super (origNode, new PackageFilterChildren (origNode)); 286 } 287 288 @Override 289 public void setName (final String name) { 290 if (Utilities.isJavaIdentifier (name)) { 291 super.setName (name); 292 } 293 else { 294 DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message ( 295 NbBundle.getMessage(TreeRootNode.class,"MSG_InvalidPackageName"), NotifyDescriptor.INFORMATION_MESSAGE)); 296 } 297 } 298 299 } 300 301 } 302 | Popular Tags |