001: /*
002: * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
003: * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
004: */
005: package org.netbeans.modules.etl.ui.view.wizards;
006:
007: import org.netbeans.api.project.Project;
008: import org.netbeans.api.project.ProjectInformation;
009: import org.netbeans.api.project.ProjectUtils;
010: import org.netbeans.api.project.SourceGroup;
011: import org.netbeans.api.project.Sources;
012: import org.netbeans.api.queries.VisibilityQuery;
013:
014: import org.netbeans.spi.project.ui.support.CommonProjectActions;
015:
016: import org.openide.ErrorManager;
017:
018: import org.openide.filesystems.FileObject;
019: import org.openide.filesystems.FileUtil;
020:
021: import org.openide.loaders.ChangeableDataFilter;
022: import org.openide.loaders.DataFilter;
023: import org.openide.loaders.DataFolder;
024: import org.openide.loaders.DataObject;
025: import org.openide.loaders.DataObjectNotFoundException;
026:
027: import org.openide.nodes.FilterNode;
028: import org.openide.nodes.Node;
029: import org.openide.nodes.NodeNotFoundException;
030: import org.openide.nodes.NodeOp;
031:
032: import org.openide.util.Lookup;
033: import org.openide.util.NbBundle;
034: import org.openide.util.WeakListeners;
035: import org.openide.util.lookup.Lookups;
036: import org.openide.util.lookup.ProxyLookup;
037:
038: import java.beans.PropertyChangeEvent;
039: import java.beans.PropertyChangeListener;
040:
041: import java.text.MessageFormat;
042:
043: import java.util.ArrayList;
044: import java.util.Collections;
045: import java.util.StringTokenizer;
046:
047: import javax.swing.Action;
048: import javax.swing.event.ChangeEvent;
049: import javax.swing.event.ChangeListener;
050: import javax.swing.event.EventListenerList;
051: import net.java.hulp.i18n.Logger;
052: import org.netbeans.modules.etl.logger.Localizer;
053: import org.netbeans.modules.etl.logger.LogUtil;
054:
055: /**
056: * Support for creating logical views.
057: *
058: * @author Jesse Glick, Petr Hrebejk
059: */
060: public class PhysicalView {
061:
062: private static transient final Logger mLogger = LogUtil
063: .getLogger(PhysicalView.class.getName());
064: private static transient final Localizer mLoc = Localizer.get();
065:
066: /**
067: * DOCUMENT ME!
068: *
069: * @param n DOCUMENT ME!
070: *
071: * @return DOCUMENT ME!
072: */
073: public static boolean isProjectDirNode(Node n) {
074: return n instanceof GroupNode && ((GroupNode) n).isProjectDir;
075: }
076:
077: /**
078: * DOCUMENT ME!
079: *
080: * @param p DOCUMENT ME!
081: *
082: * @return DOCUMENT ME!
083: */
084: public static Node[] createNodesForProject(Project p) {
085: Sources s = ProjectUtils.getSources(p);
086: SourceGroup[] groups = s.getSourceGroups(Sources.TYPE_GENERIC);
087:
088: if ((groups == null) || (groups.length < 1)) {
089: groups = s.getSourceGroups(Sources.TYPE_GENERIC);
090: }
091:
092: FileObject projectDirectory = p.getProjectDirectory();
093: SourceGroup projectDirGroup = null;
094:
095: // First find the source group which will represent the project
096: for (int i = 0; i < groups.length; i++) {
097: FileObject groupRoot = groups[i].getRootFolder();
098:
099: if (projectDirectory.equals(groupRoot)
100: || FileUtil.isParentOf(groupRoot, projectDirectory)) {
101: if (projectDirGroup != null) {
102: // more than once => Illegal
103: projectDirGroup = null;
104:
105: break;
106: } else {
107: projectDirGroup = groups[i];
108: }
109: }
110: }
111:
112: if (projectDirGroup == null) {
113: // Illegal project
114: ErrorManager.getDefault().notify(
115: ErrorManager.INFORMATIONAL,
116: new IllegalStateException("Project "
117: + p
118: + // NOI18N
119: "either does not contain it's project directory under the "
120: + // NOI18N
121: "Generic source groups or the project directory is under"
122: + // NOI18N
123: "more than one source group")); // NOI18N
124:
125: return new Node[0];
126: }
127:
128: // Create the nodes
129: ArrayList nodesList = new ArrayList(groups.length);
130: nodesList
131: .add(new GroupNode(p, projectDirGroup, true, DataFolder
132: .findFolder(projectDirGroup.getRootFolder())));
133:
134: for (int i = 0; i < groups.length; i++) {
135: if (groups[i] == projectDirGroup) {
136: continue;
137: }
138:
139: nodesList.add(new GroupNode(p, groups[i], false, DataFolder
140: .findFolder(groups[i].getRootFolder())));
141: }
142:
143: Node[] nodes = new Node[nodesList.size()];
144: nodesList.toArray(nodes);
145:
146: return nodes;
147: }
148:
149: /**
150: * DOCUMENT ME!
151: */
152: static final class VisibilityQueryDataFilter implements
153: ChangeListener, ChangeableDataFilter {
154:
155: /**
156: * DOCUMENT ME!
157: */
158: EventListenerList ell = new EventListenerList();
159:
160: /**
161: * Creates a new VisibilityQueryDataFilter object.
162: */
163: public VisibilityQueryDataFilter() {
164: VisibilityQuery.getDefault().addChangeListener(this );
165: }
166:
167: /**
168: * DOCUMENT ME!
169: *
170: * @param obj DOCUMENT ME!
171: *
172: * @return DOCUMENT ME!
173: */
174: public boolean acceptDataObject(DataObject obj) {
175: FileObject fo = obj.getPrimaryFile();
176:
177: return VisibilityQuery.getDefault().isVisible(fo);
178: }
179:
180: /**
181: * DOCUMENT ME!
182: *
183: * @param e DOCUMENT ME!
184: */
185: public void stateChanged(ChangeEvent e) {
186: Object[] listeners = ell.getListenerList();
187: ChangeEvent event = null;
188:
189: for (int i = listeners.length - 2; i >= 0; i -= 2) {
190: if (listeners[i] == ChangeListener.class) {
191: if (event == null) {
192: event = new ChangeEvent(this );
193: }
194:
195: ((ChangeListener) listeners[i + 1])
196: .stateChanged(event);
197: }
198: }
199: }
200:
201: /**
202: * DOCUMENT ME!
203: *
204: * @param listener DOCUMENT ME!
205: */
206: public void addChangeListener(ChangeListener listener) {
207: ell.add(ChangeListener.class, listener);
208: }
209:
210: /**
211: * DOCUMENT ME!
212: *
213: * @param listener DOCUMENT ME!
214: */
215: public void removeChangeListener(ChangeListener listener) {
216: ell.remove(ChangeListener.class, listener);
217: }
218: }
219:
220: /**
221: * DOCUMENT ME!
222: */
223: static final class GroupNode extends FilterNode implements
224: PropertyChangeListener {
225:
226: private static final DataFilter VISIBILITY_QUERY_FILTER = new VisibilityQueryDataFilter();
227: //private Project project;
228: private ProjectInformation pi;
229: private SourceGroup group;
230: private boolean isProjectDir;
231: private DataFolder dataFolder;
232: /**
233: * DOCUMENT ME!
234: */
235: String nbBundle1 = mLoc.t("PRSR001: {1} - {0}", pi
236: .getDisplayName(), dataFolder.getName());
237: final String GROUP_NAME_PATTERN = Localizer.parse(nbBundle1); // NOI18N
238:
239: /**
240: * Creates a new GroupNode object.
241: *
242: * @param project DOCUMENT ME!
243: * @param group DOCUMENT ME!
244: * @param isProjectDir DOCUMENT ME!
245: * @param dataFolder DOCUMENT ME!
246: */
247: public GroupNode(Project project, SourceGroup group,
248: boolean isProjectDir, DataFolder dataFolder) {
249: super (dataFolder.getNodeDelegate(), dataFolder
250: .createNodeChildren(VISIBILITY_QUERY_FILTER),
251: createLookup(project, group, dataFolder));
252:
253: //this.project = project;
254: this .pi = ProjectUtils.getInformation(project);
255: this .group = group;
256: this .isProjectDir = isProjectDir;
257: pi.addPropertyChangeListener(WeakListeners.propertyChange(
258: this , pi));
259: group.addPropertyChangeListener(WeakListeners
260: .propertyChange(this , group));
261: }
262:
263: // XXX May need to change icons as well
264: public String getName() {
265: if (isProjectDir) {
266: return pi.getName();
267: } else {
268: return group.getName();
269: }
270: }
271:
272: /**
273: * DOCUMENT ME!
274: *
275: * @return DOCUMENT ME!
276: */
277: public String getDisplayName() {
278: if (isProjectDir) {
279: return pi.getDisplayName();
280: } else {
281: return MessageFormat.format(GROUP_NAME_PATTERN,
282: new Object[] { group.getDisplayName(),
283: pi.getDisplayName(),
284: getOriginal().getDisplayName() });
285: }
286: }
287:
288: /**
289: * DOCUMENT ME!
290: *
291: * @return DOCUMENT ME!
292: */
293: public String getShortDescription() {
294: FileObject gdir = group.getRootFolder();
295: String dir = FileUtil.getFileDisplayName(gdir);
296:
297: return NbBundle.getMessage(PhysicalView.class,
298: isProjectDir ? "HINT_project" : "HINT_group", // NOI18N
299: dir);
300: }
301:
302: /**
303: * DOCUMENT ME!
304: *
305: * @return DOCUMENT ME!
306: */
307: public boolean canRename() {
308: return false;
309: }
310:
311: /**
312: * DOCUMENT ME!
313: *
314: * @return DOCUMENT ME!
315: */
316: public boolean canCut() {
317: return false;
318: }
319:
320: /**
321: * DOCUMENT ME!
322: *
323: * @return DOCUMENT ME!
324: */
325: public boolean canCopy() {
326: // At least for now.
327: return false;
328: }
329:
330: /**
331: * DOCUMENT ME!
332: *
333: * @return DOCUMENT ME!
334: */
335: public boolean canDestroy() {
336: return false;
337: }
338:
339: /**
340: * DOCUMENT ME!
341: *
342: * @param context DOCUMENT ME!
343: *
344: * @return DOCUMENT ME!
345: */
346: public Action[] getActions(boolean context) {
347: if (context) {
348: return super .getActions(true);
349: } else {
350: Action[] folderActions = super .getActions(false);
351: Action[] projectActions;
352:
353: if (isProjectDir) {
354: // If this is project dir then the properties action
355: // has to be replaced to invoke project customizer
356: projectActions = new Action[folderActions.length];
357:
358: for (int i = 0; i < folderActions.length; i++) {
359: if (folderActions[i] instanceof org.openide.actions.PropertiesAction) {
360: projectActions[i] = CommonProjectActions
361: .customizeProjectAction();
362: } else {
363: projectActions[i] = folderActions[i];
364: }
365: }
366: } else {
367: projectActions = folderActions;
368: }
369:
370: return projectActions;
371: }
372: }
373:
374: // Private methods -------------------------------------------------
375: public void propertyChange(PropertyChangeEvent evt) {
376: String prop = evt.getPropertyName();
377:
378: if (ProjectInformation.PROP_DISPLAY_NAME.equals(prop)) {
379: fireDisplayNameChange(null, null);
380: } else if (ProjectInformation.PROP_NAME.equals(prop)) {
381: fireNameChange(null, null);
382: } else if (ProjectInformation.PROP_ICON.equals(prop)) {
383: // OK, ignore
384: } else if ("name".equals(prop)) { // NOI18N
385: fireNameChange(null, null);
386: } else if ("displayName".equals(prop)) { // NOI18N
387: fireDisplayNameChange(null, null);
388: } else if ("icon".equals(prop)) { // NOI18N
389:
390: // OK, ignore
391: } else if ("rootFolder".equals(prop)) { // NOI18N
392:
393: // XXX Do something to children and lookup
394: fireNameChange(null, null);
395: fireDisplayNameChange(null, null);
396: fireShortDescriptionChange(null, null);
397: } else {
398: assert false : "Attempt to fire an unsupported property change event from "
399: + pi.getClass().getName() + ": " + prop;
400: }
401: }
402:
403: private static Lookup createLookup(Project p,
404: SourceGroup group, DataFolder dataFolder) {
405: return new ProxyLookup(new Lookup[] {
406: dataFolder.getNodeDelegate().getLookup(),
407: Lookups.fixed(new Object[] { p,
408: new PathFinder(group) }), p.getLookup(), });
409: }
410: }
411:
412: /**
413: * DOCUMENT ME!
414: */
415: public static class PathFinder {
416:
417: private SourceGroup group;
418:
419: /**
420: * Creates a new PathFinder object.
421: *
422: * @param group DOCUMENT ME!
423: */
424: public PathFinder(SourceGroup group) {
425: this .group = group;
426: }
427:
428: /**
429: * DOCUMENT ME!
430: *
431: * @param root DOCUMENT ME!
432: * @param object DOCUMENT ME!
433: *
434: * @return DOCUMENT ME!
435: */
436: public Node findPath(Node root, Object object) {
437: if (!(object instanceof FileObject)) {
438: return null;
439: }
440:
441: FileObject fo = (FileObject) object;
442: FileObject groupRoot = group.getRootFolder();
443:
444: if (FileUtil.isParentOf(groupRoot, fo) /* && group.contains( fo ) */) {
445: // The group contains the object
446: String relPath = FileUtil
447: .getRelativePath(groupRoot, fo);
448:
449: ArrayList path = new ArrayList();
450: StringTokenizer strtok = new StringTokenizer(relPath,
451: "/");
452:
453: while (strtok.hasMoreTokens()) {
454: path.add(strtok.nextToken());
455: }
456:
457: String name = fo.getName();
458:
459: try {
460: DataObject dobj = DataObject.find(fo);
461: name = dobj.getNodeDelegate().getName();
462: } catch (DataObjectNotFoundException e) {
463: }
464:
465: path.set(path.size() - 1, name);
466:
467: try {
468: return NodeOp.findPath(root, Collections
469: .enumeration(path));
470: } catch (NodeNotFoundException e) {
471: return null;
472: }
473: } else if (groupRoot.equals(fo)) {
474: return root;
475: }
476:
477: return null;
478: }
479: }
480: }
|