001: /*
002: * PageFlowNode.java
003: *
004: * Created on April 4, 2007, 12:23 PM
005: *
006: * To change this template, choose Tools | Template Manager
007: * and open the template in the editor.
008: */
009:
010: package org.netbeans.modules.web.jsf.navigation;
011:
012: import java.awt.Image;
013: import java.io.IOException;
014: import java.util.ArrayList;
015: import java.util.Collection;
016: import java.util.Collections;
017: import javax.swing.Action;
018: import javax.swing.event.ChangeEvent;
019: import javax.swing.event.ChangeListener;
020: import org.netbeans.modules.web.jsf.navigation.graph.PageFlowSceneElement;
021: import org.netbeans.modules.web.jsf.navigation.pagecontentmodel.PageContentItem;
022: import org.netbeans.modules.web.jsf.navigation.pagecontentmodel.PageContentModel;
023: import org.netbeans.modules.web.jsf.navigation.pagecontentmodel.PageContentModelProvider;
024: import org.openide.nodes.Node;
025: import org.openide.nodes.Node.Cookie;
026: import org.openide.util.HelpCtx;
027: import org.openide.util.NbBundle;
028: import org.openide.DialogDescriptor;
029: import org.openide.cookies.SaveCookie;
030: import org.openide.filesystems.FileObject;
031: import org.openide.loaders.DataNode;
032: import org.openide.nodes.AbstractNode;
033: import org.openide.nodes.Children;
034: import org.openide.util.Exceptions;
035: import org.openide.util.Utilities;
036: import org.openide.util.actions.SystemAction;
037:
038: /**
039: *
040: * @author joelle
041: */
042: public class Page extends PageFlowSceneElement implements SaveCookie {
043:
044: public final PageFlowController pc;
045: private Node original;
046: private PageContentModel pageContentModel = null;
047:
048: /**
049: * Creates a PageFlowNode
050: * @param pc
051: * @param original
052: */
053: public Page(PageFlowController pc, Node original) {
054: super ();
055: this .pc = pc;
056: setNode(original);
057: /* Update the page only at request
058: updateContentModel();
059: initListeners();
060: */
061: }
062:
063: public void updateContentModel() {
064: if (!isDataNode()) {
065: return;
066: }
067:
068: FileObject fileObject = ((DataNode) original).getDataObject()
069: .getPrimaryFile();
070:
071: destroyListeners(); /* Otherwise initlisteners will not work */
072:
073: for (PageContentModelProvider provider : PageFlowController
074: .getPageContentModelProviders()) {
075: pageContentModel = provider.getPageContentModel(fileObject);
076: //exit when you find one.
077: if (pageContentModel != null) {
078: initListeners();
079: return;
080: }
081: }
082: }
083:
084: // public Node getWrappedNode() {
085: // return original;
086: // }
087: private String nodeDisplayName;
088:
089: private void setNode(Node newNode) {
090: String oldDisplayName = nodeDisplayName;
091: original = newNode;
092: nodeDisplayName = original.getDisplayName();
093: //HACK sometimes the datanode name isn't updated as fast as the filename.
094: if (original instanceof DataNode) {
095: assert pc != null;
096:
097: FileObject fileObj = ((DataNode) original).getDataObject()
098: .getPrimaryFile();
099: assert fileObj != null;
100: nodeDisplayName = getFolderDisplayName(pc.getWebFolder(),
101: fileObj);
102: }
103: if (!nodeDisplayName.equals(oldDisplayName)) {
104: if (oldDisplayName != null) {
105: pc.removePageName2Page(oldDisplayName, false);
106: }
107: pc.putPageName2Page(nodeDisplayName, this );
108: }
109: }
110:
111: public void updateNode_HACK() {
112: setNode(original);
113: }
114:
115: /* We may want this to notify listeners of changes.*/
116: public void replaceWrappedNode(Node newNode) {
117: // pc.pageName2Node.remove(getDisplayName());
118: //pc.removePageName2Page(getDisplayName(), false);
119: setNode(newNode);
120: pc.putPageName2Page(getDisplayName(), this );
121: // pc.putPageName2Node(getDisplayName(), this);
122: }
123:
124: private boolean renaming = false;
125: {
126: }
127:
128: public boolean isRenaming() {
129: return renaming;
130: }
131:
132: @Override
133: public void setName(String s) {
134:
135: String oldDisplayName = getDisplayName();
136: try {
137: if (!pc.isPageInAnyFacesConfig(oldDisplayName)) {
138: original.setName(s);
139: } else {
140: renaming = true;
141: original.setName(s);
142: String newDisplayName = original.getDisplayName();
143: if (isDataNode()) {
144: newDisplayName = getFolderDisplayName(pc
145: .getWebFolder(), ((DataNode) original)
146: .getDataObject().getPrimaryFile());
147: }
148: pc.saveLocation(oldDisplayName, newDisplayName);
149: renaming = false;
150: pc.renamePageInModel(oldDisplayName, newDisplayName);
151: }
152: } catch (IllegalArgumentException iae) {
153:
154: // determine if "printStackTrace" and "new annotation" of this exception is needed
155: boolean needToAnnotate = Exceptions
156: .findLocalizedMessage(iae) == null;
157:
158: // annotate new localized message only if there is no localized message yet
159: if (needToAnnotate) {
160: Exceptions.attachLocalizedMessage(iae, NbBundle
161: .getMessage(Page.class, "MSG_BadFormat",
162: oldDisplayName, s));
163: }
164:
165: Exceptions.printStackTrace(iae);
166: }
167: }
168:
169: public String getDisplayName() {
170: return nodeDisplayName;
171: // return original.getDisplayName();
172: }
173:
174: @Override
175: public String getName() {
176: // Thread.dumpStack();
177: return original.getName();
178: // return nodeDisplayName;
179: }
180:
181: /**
182: *
183: * @return
184: */
185: @Override
186: public boolean canRename() {
187: return isModifiable();
188: }
189:
190: @Override
191: public boolean canDestroy() {
192: return true;
193: }
194:
195: /* Joelle: Temporarily I need not use destroy for the other purpose. I plan to fix after stabilization */
196: public void destroy2() {
197: destroyListeners();
198: if (original instanceof NonDataNode) {
199: original = null;
200: }
201: pccl = null;
202: pageContentModel = null;
203: }
204:
205: public void destroy() throws IOException {
206:
207: Object input = DialogDescriptor.NO_OPTION; //This should be the default option especially if not a DataNode.
208: boolean removePageName2NodeReference = true; //By default remove it.
209: if (isDataNode()) {
210: //Don't even ask unless DataNode.
211: DialogDescriptor dialog = new DialogDescriptor(NbBundle
212: .getMessage(Page.class, "MSG_DELETE_QUESTION",
213: getDisplayName()), NbBundle.getMessage(
214: Page.class, "MSG_DELETE_TITLE"), true,
215: DialogDescriptor.YES_NO_CANCEL_OPTION,
216: DialogDescriptor.NO_OPTION, null);
217: java.awt.Dialog d = org.openide.DialogDisplayer
218: .getDefault().createDialog(dialog);
219: d.setVisible(true);
220: input = dialog.getValue();
221: if (pc != null
222: && pc
223: .isCurrentScope(PageFlowToolbarUtilities.Scope.SCOPE_PROJECT)) {
224: removePageName2NodeReference = false; //if it is a data node and we are in project scope make sure to not remove it.
225: }
226: }
227:
228: String displayName = getDisplayName();
229: // Would you like to delete this file too?
230: if (input == DialogDescriptor.YES_OPTION) {
231: pc.removeSceneNodeEdges(this );
232: original.destroy();
233: destroyListeners();
234: } else if (input == DialogDescriptor.NO_OPTION) {
235: pc.removeSceneNodeEdges(this );
236: // if ( removePageName2NodeReference ) { //HACK Should I remove the node myself until Petr fixes this bug?
237: // // pc.removePageName2Node(displayName);
238: // destroy();
239: // }
240: // System.out.println("Only Node Removed");
241: } else if (input == DialogDescriptor.CANCEL_OPTION) {
242: // System.out.println("Cancel... Do Nothing.");
243: }
244: // destroyListeners();
245: //
246: // original.destroy();
247: // pc.pageName2Node.remove(getDisplayName());
248: }
249:
250: private static final Image ABSTRACTNODE = Utilities
251: .loadImage("org/netbeans/modules/web/jsf/navigation/graph/resources/abstract.gif"); // NOI18N
252:
253: public Image getIcon(int type) {
254: if (!isDataNode()) {
255: return ABSTRACTNODE;
256: }
257: return original.getIcon(type);
258: }
259:
260: @Override
261: public HelpCtx getHelpCtx() {
262: return original.getHelpCtx();
263: }
264:
265: public Node getNode() {
266: if (isDataNode()) {
267: return original;
268: } else {
269: return new NonDataNode(original.getName());
270: }
271: }
272:
273: public boolean isDataNode() {
274: return original instanceof DataNode;
275: }
276:
277: public void save() throws IOException {
278: // pc.getConfigDataObject().getEditorSupport().saveDocument();
279: getCookie(SaveCookie.class).save();
280: }
281:
282: // @Override
283: public <T extends Cookie> T getCookie(Class<T> type) {
284: if (type.equals(SaveCookie.class)) {
285: return pc.getConfigDataObject().getCookie(type);
286: }
287: return original.getCookie(type);
288: }
289:
290: /**
291: * Solves a fileobjects display name.
292: * @param webFolder
293: * @param fileObject
294: * @return
295: */
296: public static String getFolderDisplayName(FileObject webFolder,
297: FileObject fileObject) {
298: String folderpath = webFolder.getPath();
299: String filepath = fileObject.getPath();
300: return filepath.replaceFirst(folderpath + "/", "");
301: }
302:
303: public static String getFolderDisplayName(FileObject webFolder,
304: String path, String fileNameExt) {
305: String folderpath = webFolder.getPath();
306: return path.replaceFirst(folderpath + "/", "") + fileNameExt;
307: }
308:
309: public Collection<PageContentItem> getPageContentItems() {
310: if (pageContentModel == null) {
311: return new ArrayList<PageContentItem>();
312: }
313: return pageContentModel.getPageContentItems();
314: }
315:
316: private boolean hasPageContentModelBeenChecked = false;
317:
318: public Collection<Pin> getPinNodes() {
319: if (!hasPageContentModelBeenChecked) {
320: updateContentModel();
321: hasPageContentModelBeenChecked = true;
322: }
323: if (pageContentModel == null) {
324: return Collections.emptyList();
325: }
326: Collection<PageContentItem> pageContentItems = pageContentModel
327: .getPageContentItems();
328: Collection<Pin> pinNodes = new ArrayList<Pin>(pageContentItems
329: .size());
330: for (PageContentItem pageContentItem : pageContentItems) {
331: pinNodes.add(new Pin(this , pageContentItem));
332: }
333: return pinNodes;
334: }
335:
336: private PageContentChangeListener pccl;
337:
338: /**
339: * Before using this method, it is good to make sure all listeners
340: * are destroyed. Use destroyListeners().
341: **/
342: private void initListeners() {
343: if (pageContentModel != null && pccl == null) {
344: pccl = new PageContentChangeListener();
345: pageContentModel.addChangeListener(pccl);
346: }
347: }
348:
349: /**
350: * Removes any content model listeners
351: **/
352: private void destroyListeners() {
353: if (pccl != null && pageContentModel != null) {
354: try {
355: pageContentModel.removeChangeListener(pccl);
356: pageContentModel.destroy();
357: pageContentModel = null;
358: pccl = null;
359: } catch (IOException ex) {
360: Exceptions.printStackTrace(ex);
361: }
362: }
363: }
364:
365: private final Page getInstance() {
366: return this ;
367: }
368:
369: private class PageContentChangeListener implements ChangeListener {
370:
371: public void stateChanged(ChangeEvent arg0) {
372: if (!pc.getView().isShowing()) { //Don't do anything except let PFC know that the graph is dirty if the graph is not showing.
373: pc.setGraphDirty();
374: } else {
375: pc.updatePageItems(getInstance());
376: }
377: }
378: }
379:
380: public Action[] getActions(boolean context) {
381: if (pageContentModel != null) {
382: return pageContentModel.getActions();
383: }
384: return new SystemAction[] {};
385: // if( pageContentModel != null ){
386: // SystemAction[] pageModelActions = pageContentModel.getActions();
387: // SystemAction[] nodeActions = super.getActions();
388: //
389: // if( pageModelActions == null || pageModelActions.length == 0 ){
390: // return nodeActions;
391: // } else if ( nodeActions == null || nodeActions.length == 0 ){
392: // return pageModelActions;
393: // } else {
394: // int size = pageModelActions.length + nodeActions.length;
395: // SystemAction[] sysActions = new SystemAction[size];
396: // System.arraycopy(nodeActions, 0, sysActions, 0, nodeActions.length);
397: // System.arraycopy(pageModelActions, 0, sysActions, nodeActions.length, pageModelActions.length);
398: // return sysActions;
399: // }
400: // } else {
401: // return super.getActions();
402: // }
403: }
404:
405: public boolean equals(Object obj) {
406: return this == obj;
407: }
408:
409: @Override
410: public int hashCode() {
411: return System.identityHashCode(this );
412: }
413:
414: //
415: // public final NonDataNode createNonDataNode() {
416: // return new NonDataNode(this);
417: // }
418:
419: public final class NonDataNode extends AbstractNode {
420:
421: public NonDataNode(String pageName) {
422: super (Children.LEAF);
423: super .setName(pageName);
424: }
425:
426: @Override
427: public boolean canRename() {
428: return true;
429: }
430:
431: @Override
432: public String getName() {
433: return getInstance().getName();
434: }
435:
436: @Override
437: public void setName(String s) {
438: super.setName(s);
439: getInstance().setName(s);
440: }
441: }
442: }
|