001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: */
031:
032: package org.netbeans.modules.web.jsf.navigation;
033:
034: import java.awt.BorderLayout;
035: import java.awt.Image;
036: import java.io.IOException;
037: import java.lang.ref.WeakReference;
038: import java.util.ArrayList;
039: import java.util.Collection;
040: import java.util.HashSet;
041: import java.util.List;
042: import java.util.Set;
043: import java.util.concurrent.ThreadPoolExecutor;
044: import java.util.logging.Logger;
045: import javax.swing.Action;
046: import javax.swing.JComponent;
047: import javax.swing.JScrollPane;
048: import javax.swing.JToolBar;
049: import javax.swing.border.EmptyBorder;
050: import org.netbeans.api.project.FileOwnerQuery;
051: import org.netbeans.api.project.Project;
052: import org.netbeans.api.project.ProjectUtils;
053: import org.netbeans.api.project.SourceGroup;
054: import org.netbeans.api.project.Sources;
055: import org.netbeans.api.visual.model.StateModel;
056: import org.netbeans.api.visual.vmd.VMDConnectionWidget;
057: import org.netbeans.api.visual.vmd.VMDNodeWidget;
058: import org.netbeans.api.visual.vmd.VMDPinWidget;
059: import org.netbeans.modules.web.api.webmodule.WebModule;
060: import org.netbeans.modules.web.jsf.api.editor.JSFConfigEditorContext;
061: import org.netbeans.modules.web.jsf.navigation.JSFPageFlowMultiviewDescriptor.PageFlowElement;
062: import org.netbeans.modules.web.jsf.navigation.graph.layout.LayoutUtility;
063: import org.netbeans.modules.web.jsf.navigation.graph.PageFlowScene;
064: import org.netbeans.modules.web.jsf.navigation.graph.PageFlowSceneData;
065: import org.netbeans.modules.web.jsf.navigation.graph.PageFlowSceneElement;
066: import org.netbeans.modules.web.jsf.navigation.graph.SceneSerializer;
067: import org.netbeans.spi.palette.PaletteActions;
068: import org.netbeans.spi.palette.PaletteController;
069: import org.netbeans.spi.palette.PaletteFactory;
070: import org.openide.filesystems.FileObject;
071: import org.openide.loaders.DataFolder;
072: import org.openide.loaders.DataObject;
073: import org.openide.loaders.DataObjectNotFoundException;
074: import org.openide.nodes.FilterNode;
075: import org.openide.nodes.Node;
076: import org.openide.nodes.Node;
077: import org.openide.nodes.Node.Cookie;
078: import org.openide.util.Exceptions;
079: import org.openide.util.Lookup;
080: import org.openide.util.NbBundle;
081: import org.openide.util.lookup.Lookups;
082: import org.openide.util.lookup.ProxyLookup;
083: import org.openide.windows.TopComponent;
084:
085: /**
086: * PageFlowView is the TopComponent that setups the controller and the view. It also does
087: * the necessary setting of activated nodes, focus setting, etc.
088: * @author Joelle Lam
089: */
090: public class PageFlowView extends TopComponent implements
091: Lookup.Provider {
092:
093: private JSFConfigEditorContext context;
094: private PageFlowScene scene;
095: private PageFlowController pfc;
096: private PageFlowSceneData sceneData;
097: private ThreadPoolExecutor executor;
098: private static final Logger LOG = Logger
099: .getLogger("org.netbeans.web.jsf.navigation");
100: private static final String ACN_PAGEVIEW_TC = NbBundle.getMessage(
101: PageFlowView.class, "ACN_PageView_TC");
102: private static final String ACDS_PAGEVIEW_TC = NbBundle.getMessage(
103: PageFlowView.class, "ACDS_PageView_TC");
104:
105: PageFlowView(PageFlowElement multiview,
106: JSFConfigEditorContext context) {
107: setMultiview(multiview);
108: this .context = context;
109: initializeScene(); /* setScene is called inside this method */
110: pfc = new PageFlowController(context, this );
111: sceneData = new PageFlowSceneData(PageFlowToolbarUtilities
112: .getInstance(this ));
113:
114: deserializeNodeLocation(getStorageFile(context
115: .getFacesConfigFile()));
116: pfc.setupGraphNoSaveData(); /* I don't want to override the loaded locations with empy sceneData */
117: LOG.fine("Initializing Page Flow SetupGraph");
118:
119: setFocusable(true);
120:
121: LOG.finest("Create Executor Thread");
122:
123: getAccessibleContext().setAccessibleDescription(
124: ACDS_PAGEVIEW_TC);
125: getAccessibleContext().setAccessibleName(ACN_PAGEVIEW_TC);
126: }
127:
128: public void requestMultiViewActive() {
129: getMultiview().getMultiViewCallback().requestActive();
130: requestFocus(); //This is a hack because requestActive does not call requestFocus when it is already active (BUT IT SHOULD).
131: }
132:
133: /**
134: *
135: * @return PageFlowController
136: */
137: public PageFlowController getPageFlowController() {
138: return pfc;
139: }
140:
141: /** Weak reference to the lookup. */
142: private WeakReference<Lookup> lookupWRef = new WeakReference<Lookup>(
143: null);
144:
145: @Override
146: public Lookup getLookup() {
147: Lookup lookup = lookupWRef.get();
148: DataObject jsfConfigDataObject = null;
149:
150: if (lookup == null) {
151: Lookup super Lookup = super .getLookup();
152: try {
153: //Necessary for close project work propertly.
154: jsfConfigDataObject = DataObject.find(context
155: .getFacesConfigFile());
156: } catch (DataObjectNotFoundException ex) {
157: Exceptions.printStackTrace(ex);
158: }
159:
160: if (jsfConfigDataObject != null) {
161: lookup = new ProxyLookup(new Lookup[] {
162: super Lookup,
163: Lookups.fixed(new Object[] { getScene(),
164: jsfConfigDataObject }) });
165: } else {
166: /* Temporarily Removing Palette */
167: // PaletteController paletteController = getPaletteController();
168: // if (paletteController == null) {
169: lookup = new ProxyLookup(new Lookup[] { super Lookup,
170: Lookups.fixed(new Object[] { getScene() }) });
171: // } else {
172: // lookup = new ProxyLookup(new Lookup[] {superLookup, Lookups.fixed(new Object[] { paletteController})});
173: // }
174: }
175: lookupWRef = new WeakReference<Lookup>(lookup);
176: }
177:
178: return lookup;
179: }
180:
181: /**
182: * Unregister all the listeners. See "registerListeners()".
183: **/
184: public void unregstierListeners() {
185: if (pfc != null) {
186: pfc.unregisterListeners();
187: }
188: }
189:
190: /**
191: * Regsiter all the Page Flow Controller Listeners. Ie FileSystem, FacesModel, etc
192: **/
193: public void registerListeners() {
194: if (pfc != null) {
195: pfc.registerListeners();
196: }
197: }
198:
199: /*
200: * Initializes the Panel and the graph
201: **/
202: private PageFlowScene initializeScene() {
203: setLayout(new BorderLayout());
204:
205: setScene(new PageFlowScene(this ));
206:
207: getScene().setAccessibleContext(this .getAccessibleContext());
208:
209: JScrollPane pane = new JScrollPane(getScene().createView());
210: pane.setVisible(true);
211:
212: add(pane, BorderLayout.CENTER);
213:
214: setDefaultActivatedNode();
215:
216: return getScene();
217: }
218:
219: public void destroyScene() {
220: clearGraph();
221: getScene().destoryPageFlowScene();
222: setScene(null);
223: sceneData = null;
224: // runnables.clear();
225: context = null;
226: pfc.destroy();
227: pfc = null;
228: }
229:
230: /**
231: * Set the default actived node to faces config node. The default activated
232: * node is always teh faces config file.
233: */
234: public void setDefaultActivatedNode() {
235: try {
236: Node node = new DefaultDataNode(DataObject.find(context
237: .getFacesConfigFile()));
238: setActivatedNodes(new Node[] { node });
239: } catch (DataObjectNotFoundException donfe) {
240: Exceptions.printStackTrace(donfe);
241: /* Trying to track down #112243 */
242: LOG
243: .fine("WARNING: Unable to find the following DataObject: "
244: + context.getFacesConfigFile());
245: setActivatedNodes(new Node[] {});
246: }
247: }
248:
249: public int sceneAssgn = 0;
250:
251: public PageFlowScene getScene() {
252: return scene;
253: }
254:
255: public void setScene(PageFlowScene scene) {
256: sceneAssgn++;
257: this .scene = scene;
258: }
259:
260: /* In order to prevent modifications of tab names when a page was selected, I needed to
261: * create a DefaultDataNode (or filterNode). Basically this is used to take look like
262: * a DataNode but not be one exactly.
263: **/
264: private class DefaultDataNode extends FilterNode {
265:
266: Node srcFolderNode = null;
267:
268: public DefaultDataNode(DataObject dataObject) {
269: this (dataObject.getNodeDelegate());
270: Project p = FileOwnerQuery.getOwner(dataObject
271: .getPrimaryFile());
272: /* Let's only worry about this if it is actually part of a project.*/
273: if (p != null) {
274: //FileObject projectDirectory = p.getProjectDirectory();
275: Sources sources = ProjectUtils.getSources(p);
276: SourceGroup[] groups = sources
277: .getSourceGroups(Sources.TYPE_GENERIC);
278: FileObject srcFolder;
279:
280: try {
281: if (groups != null && groups.length > 0) {
282: srcFolder = groups[0].getRootFolder();
283: } else {
284: srcFolder = dataObject.getFolder()
285: .getPrimaryFile();
286: }
287: srcFolderNode = DataObject.find(srcFolder)
288: .getNodeDelegate();
289: } catch (DataObjectNotFoundException ex) {
290: Exceptions.printStackTrace(ex);
291: }
292: }
293: }
294:
295: public DefaultDataNode(Node node) {
296: super (node);
297: }
298:
299: @Override
300: public <T extends Cookie> T getCookie(Class<T> type) {
301: if (type.equals(DataFolder.class)) {
302: assert srcFolderNode != null;
303: return srcFolderNode.getCookie(type);
304: }
305: return super .getCookie(type);
306: }
307: }
308:
309: /**
310: * This call draws a warning in the scene saying that the faces-config can not be parsed.
311: */
312: public void warnUserMalFormedFacesConfig() {
313: // clearGraph();
314: getScene().createMalFormedWidget();
315: }
316:
317: /*
318: * Once the faces-config can be parsed again remove the warning from the scene.
319: * See "warnUserMalFormedFacesConfig()
320: **/
321: public void removeUserMalFormedFacesConfig() {
322: getScene().removeMalFormedWidget();
323: }
324:
325: // private static final Image IMAGE_LIST = Utilities.loadImage("org/netbeans/modules/web/jsf/navigation/graph/resources/list_32.png"); // NOI18N
326: /**
327: * Remove all the nodes from the graph. I especially use this when redrawing
328: * the page in a new scope or if the faces-config file can no longer be parsed.
329: **/
330: public void clearGraph() {
331: //Workaround: Temporarily Wrapping Collection because of http://www.netbeans.org/issues/show_bug.cgi?id=97496
332: Collection<Page> pages = new HashSet<Page>(getScene()
333: .getNodes());
334: for (Page page : pages) {
335: getScene().removeNodeWithEdges(page);
336: page.destroy2();
337: }
338: getScene().validate();
339: }
340:
341: /**
342: * Validating the graph is necessary to push a series of modifications to view.
343: * Please see the graph library API for details.
344: **/
345: public void validateGraph() {
346: // scene.layoutScene();
347: // System.out.println("Validating Graph: ");
348: // System.out.println("Nodes: " + scene.getNodes());
349: // System.out.println("Edges: "+ scene.getEdges());
350: // System.out.println("Pins: " + scene.getPins());
351: getScene().validate();
352: }
353:
354: /*
355: * Save the locations for all the pages currently in the scene.
356: */
357: public void saveLocations() {
358: sceneData.saveCurrentSceneData(getScene());
359: }
360:
361: /*
362: * Save the location of just the given page.
363: * This is necessary because I save locations by page name. If the page name
364: * is updated, we must save the location under the new page name.
365: */
366: public void saveLocation(String oldDisplayName,
367: String newDisplayName) {
368: sceneData.savePageWithNewName(oldDisplayName, newDisplayName);
369: }
370:
371: // private static final String ACN_PAGE = NbBundle.getMessage(PageFlowView.class, "ACN_Page");
372: // private static final String ACDS_PAGE = NbBundle.getMessage(PageFlowView.class, "ACDS_Page");
373: // private static final String ACN_PIN = NbBundle.getMessage(PageFlowView.class, "ACN_Pin");
374: // private static final String ACDS_PIN = NbBundle.getMessage(PageFlowView.class, "ACDS_Pin");
375: // private static final String ACN_EDGE = NbBundle.getMessage(PageFlowView.class, "ACN_Edge");
376: // private static final String ACDS_EDGE = NbBundle.getMessage(PageFlowView.class, "ACDS_Edge");
377: /**
378: * Creates a PageFlowScene node from a pageNode. The PageNode will generally be some type of DataObject unless
379: * there is no true file to represent it. In that case a abstractNode should be passed
380: * @param pageNode the node that represents a dataobject or empty object
381: * @param type
382: * @param glyphs
383: * @return
384: */
385: protected VMDNodeWidget createNode(final Page pageNode,
386: String type, List<Image> glyphs) {
387: String pageName = pageNode.getDisplayName();
388:
389: final VMDNodeWidget widget = (VMDNodeWidget) getScene()
390: .addNode(pageNode);
391: // widget.setNodeProperties(null /*IMAGE_LIST*/, pageName, type, glyphs);
392: widget.setNodeProperties(pageNode
393: .getIcon(java.beans.BeanInfo.ICON_COLOR_16x16),
394: pageName, type, glyphs);
395: PageFlowSceneData.PageData data = sceneData
396: .getPageData(pageName);
397: if (data != null) {
398: widget.setPreferredLocation(data.getPoint());
399: widget.setMinimized(data.isMinimized());
400: }
401: getScene().addPin(pageNode, new Pin(pageNode));
402:
403: /* Now we want to runPinSetup on demand */
404: //runPinSetup(pageNode, widget);
405: selectPageFlowSceneElement(pageNode);
406: return widget;
407: }
408:
409: public final class VMDNodeWidgetListener implements
410: StateModel.Listener {
411:
412: public void stateChanged() {
413: throw new UnsupportedOperationException(
414: "Not supported yet.");
415: }
416:
417: }
418:
419: private void selectPageFlowSceneElement(PageFlowSceneElement element) {
420: Set<PageFlowSceneElement> selectedSet = new HashSet<PageFlowSceneElement>(
421: 1);
422: selectedSet.add(element);
423: getScene().setSelectedObjects(selectedSet);
424: }
425:
426: private void setupPinsInNode(Page pageNode) {
427: Collection<Pin> pinNodes = pageNode.getPinNodes();
428: for (Pin pinNode : pinNodes) {
429: createPin(pageNode, pinNode);
430: }
431: }
432:
433: /**
434: * Creates a PageFlowScene pin from a pageNode and pin name String.
435: * In general a pin represents a NavigasbleComponent orginally designed for VWP.
436: * @param pageNode
437: * @param pinNode representing that page item.
438: * @return
439: */
440: protected final VMDPinWidget createPin(Page pageNode, Pin pinNode) {
441: VMDPinWidget widget = null;
442:
443: /* Make sure scene still has this page. */
444: if (pageNode != null && getScene().isNode(pageNode)) {
445: widget = (VMDPinWidget) getScene()
446: .addPin(pageNode, pinNode);
447: }
448: // VMDPinWidget widget = (VMDPinWidget) graphScene.addPin(page, pin);
449: // if( navComp != null ){
450: // widget.setProperties(navComp, Arrays.asList(navComp.getBufferedIcon()));
451: // }
452: return widget;
453: }
454:
455: /**
456: * Creates an Edge or Connection in the Graph Scene
457: * @param navCaseNode
458: * @param fromPageNode
459: * @param toPageNode
460: */
461: protected void createEdge(NavigationCaseEdge navCaseEdge,
462: Page fromPageNode, Page toPageNode) {
463: assert fromPageNode.getDisplayName() != null;
464: assert toPageNode.getDisplayName() != null;
465:
466: VMDConnectionWidget connectionWidget = (VMDConnectionWidget) getScene()
467: .addEdge(navCaseEdge);
468: setEdgeSourcePin(navCaseEdge, fromPageNode);
469: setEdgeTargePin(navCaseEdge, toPageNode);
470:
471: selectPageFlowSceneElement(navCaseEdge);
472: //connectionWidget.getAccessibleContext().setAccessibleName(ACN_EDGE);
473: //connectionWidget.getAccessibleContext().setAccessibleDescription(ACDS_PAGE);
474: }
475:
476: public void renameEdgeWidget(NavigationCaseEdge edge,
477: String newName, String oldName) {
478: getScene().renameEdgeWidget(edge, newName, oldName);
479: }
480:
481: /*
482: * Figure out what the source of the case is. This is necessary if we are renaming
483: * a case. It must also modify the case string for a non-default pin.
484: * @return source pin
485: */
486: public Pin getEdgeSourcePin(NavigationCaseEdge navCase) {
487: return getScene().getEdgeSource(navCase);
488: }
489:
490: /*
491: * Sets the source or "from" pin. This can either be a pages default pin (in otherwords
492: * it is simply navigable from that page) or from another pin (ie button).
493: */
494: public void setEdgeSourcePin(NavigationCaseEdge navCaseNode,
495: Page fromPageNode) {
496: Pin sourcePin = getScene().getDefaultPin(fromPageNode);
497: Collection<Pin> pinNodes = getScene().getPins();
498: for (Pin pin : pinNodes) {
499: if (pin.getFromOutcome() != null
500: && fromPageNode == pin.getPage()
501: && pin.getFromOutcome().equals(
502: navCaseNode.getFromOuctome())) {
503: sourcePin = pin;
504: /* Remove any old navigation case nodes coming from this source */
505: Collection<NavigationCaseEdge> oldNavCaseNodes = getScene()
506: .findPinEdges(sourcePin, true, false);
507: for (NavigationCaseEdge oldNavCaseNode : oldNavCaseNodes) {
508: getScene().setEdgeSource(oldNavCaseNode,
509: getScene().getDefaultPin(fromPageNode));
510: }
511: }
512: }
513:
514: getScene().setEdgeSource(navCaseNode, sourcePin);
515: }
516:
517: /*
518: * Set the target or the "to page" for a given pin
519: **/
520: private void setEdgeTargePin(NavigationCaseEdge navCaseNode,
521: Page toPageNode) {
522: Pin targetPin = getScene().getDefaultPin(toPageNode);
523: //I need to remove extension so it matches the DataNode's pins.
524: getScene().setEdgeTarget(navCaseNode, targetPin);
525: }
526:
527: private static final String PATH_TOOLBAR_FOLDER = "PageFlowEditor/Toolbars"; // NOI18N
528:
529: /**
530: * Gives the JSFPageMultiviewViewDescriptor (MultiView Component)the needed
531: * toolbar.
532: * @return the JComponent of the Toolbar
533: */
534: public JComponent getToolbarRepresentation() {
535:
536: // PageFlowUtilities pfu = PageFlowUtilities.getInstance();
537: // TODO -- Look at NbEditorToolBar in the editor - it does stuff
538: // with the UI to get better Aqua and Linux toolbar
539: JToolBar toolbar = new JToolBar();
540: toolbar.setFloatable(false);
541: toolbar.setRollover(true);
542: toolbar.setBorder(new EmptyBorder(0, 0, 0, 0));
543:
544: toolbar.addSeparator();
545: PageFlowToolbarUtilities utilities = PageFlowToolbarUtilities
546: .getInstance(this );
547: toolbar.add(utilities.createScopeComboBox());
548: toolbar.addSeparator();
549: toolbar.add(utilities.createLayoutButton());
550:
551: return toolbar;
552: }
553:
554: private static final String PATH_PALETTE_FOLDER = "PageFlowEditor/Palette"; // NOI18N
555:
556: /**
557: * Get's the Palette Controller for the related Palette. This allows for the addition
558: * of a palette.
559: * @return the Palette Controller.
560: */
561: public PaletteController getPaletteController() {
562: try {
563: return PaletteFactory.createPalette(PATH_PALETTE_FOLDER,
564: new PaletteActions() {
565:
566: public Action[] getCustomCategoryActions(
567: Lookup lookup) {
568: return new Action[0];
569: }
570:
571: public Action[] getCustomItemActions(
572: Lookup lookup) {
573: return new Action[0];
574: }
575:
576: public Action[] getCustomPaletteActions() {
577: return new Action[0];
578: }
579:
580: public Action[] getImportActions() {
581: return new Action[0];
582: }
583:
584: public Action getPreferredAction(Lookup lookup) {
585: return null; //TODO
586: }
587: });
588: } catch (IOException ex) {
589: ex.printStackTrace();
590: }
591: return null;
592: }
593:
594: @SuppressWarnings(value="deprecation")
595: @Override
596: public void requestFocus() {
597: super .requestFocus();
598: getScene().getView().requestFocus();
599: }
600:
601: @SuppressWarnings(value="deprecation")
602: @Override
603: public boolean requestFocusInWindow() {
604: super .requestFocusInWindow();
605: return getScene().getView().requestFocusInWindow();
606: }
607:
608: /**
609: * Remove the Edge from the scene.
610: * @param node
611: */
612: public void removeEdge(NavigationCaseEdge node) {
613: if (getScene().getEdges().contains(node)) {
614: getScene().removeEdge(node);
615: }
616: }
617:
618: /*
619: * Removes a node from a scene with it's edges. This is useful when a page
620: * is deleted from the faces-config file.
621: */
622: public void removeNodeWithEdges(Page node) {
623: // scene.removeNode(node);
624: if (getScene().getNodes().contains(node)) {
625: /* In some cases the node will already be deleted by a side effect of deleting another node.
626: * This is primarily in the FacesConfig view or an abstract Node in the project view.
627: */
628: getScene().removeNodeWithEdges(node);
629: }
630: }
631:
632: /*
633: * Reset a Node Widget basically redraws a page gathering the current information
634: * for a given page. This is useful when a page has been renamed. A flag is
635: * also passed if it is suspected the page content items have been modified.
636: * If this is suspected, it will then call redrawPinsAndEdges.
637: **/
638: public void resetNodeWidget(Page pageNode,
639: boolean contentItemsChanged) {
640:
641: if (pageNode == null) {
642: throw new RuntimeException(
643: "PageFlowEditor: Cannot set node to null");
644: }
645:
646: //Reset the Node Name
647: VMDNodeWidget nodeWidget = (VMDNodeWidget) getScene()
648: .findWidget(pageNode);
649:
650: //Do this because sometimes the node display name is the object display name.
651: pageNode.updateNode_HACK();
652: // nodeWidget.setNodeName(node.getDisplayName());
653: if (nodeWidget != null) {
654: nodeWidget.setNodeProperties(pageNode
655: .getIcon(java.beans.BeanInfo.ICON_COLOR_16x16),
656: pageNode.getDisplayName(), null, null);
657: if (contentItemsChanged) {
658: redrawPinsAndEdges(pageNode);
659: }
660: } else {
661: validateGraph();
662: System.err.println("PageFlowCreationStack: "
663: + pfc.PageFlowCreationStack);
664: System.err.println("PageFlowDestroyStack: "
665: + pfc.PageFlowDestroyStack);
666: pfc.PageFlowCreationStack.clear();
667: pfc.PageFlowDestroyStack.clear();
668: System.err.println("PageNode: " + pageNode);
669: // System.err.println("Node Widget is null in scene for: " + pageNode.getDisplayName());
670: System.err.println("Here are the scene nodes: "
671: + getScene().getNodes());
672: // Thread.dumpStack();
673: }
674: }
675:
676: /*
677: * If a page is updated it will general call this method to redraw both pins
678: * and edges. Although it is obvious why we would update pins if a pin a page
679: * is modified ( a pin may have been added,removed,etc), it we also need to
680: * redraw the edges.
681: * Redrawing pin edges is necessary when the case name has been modified.
682: * Generally this method is only called by "resetNodeWidget()".
683: */
684: private final void redrawPinsAndEdges(Page pageNode) {
685: /* Gather the Edges */
686: Collection<NavigationCaseEdge> redrawCaseNodes = new ArrayList<NavigationCaseEdge>();
687: Collection<Pin> pinNodes = new ArrayList<Pin>(getScene()
688: .getPins());
689: for (Pin pin : pinNodes) {
690: if (pin.getPage() == pageNode) {
691: assert pin.getPage().getDisplayName().equals(
692: pageNode.getDisplayName());
693:
694: Collection<NavigationCaseEdge> caseNodes = getScene()
695: .findPinEdges(pin, true, false);
696: redrawCaseNodes.addAll(caseNodes);
697: if (!pin.isDefault()) {
698: getScene().removePin(pin);
699: }
700: }
701: }
702:
703: if (pageNode.isDataNode()) {
704: // This is already done. pageNode.updateContentModel();
705: //This will re-add the pins.
706: setupPinsInNode(pageNode);
707: }
708:
709: for (NavigationCaseEdge caseNode : redrawCaseNodes) {
710: setEdgeSourcePin(caseNode, pageNode);
711: }
712: }
713:
714: /*
715: * Get all the edges for a given node.
716: * @returns the collection of edge objects.
717: **/
718: public Collection<NavigationCaseEdge> getNodeEdges(Page node) {
719: Collection<NavigationCaseEdge> navCases = getScene().getEdges();
720: Collection<NavigationCaseEdge> myNavCases = new HashSet<NavigationCaseEdge>();
721:
722: String fromViewId = node.getDisplayName();
723: for (NavigationCaseEdge navCaseNode : navCases) {
724: String strToViewId = navCaseNode.getToViewId();
725: String strFromViewId = navCaseNode.getFromViewId();
726: if ((strToViewId != null && strToViewId.equals(fromViewId))
727: || (strFromViewId != null && strFromViewId
728: .equals(fromViewId))) {
729: myNavCases.add(navCaseNode);
730: }
731: }
732: return myNavCases;
733: }
734:
735: /*
736: * Solve for the file in which we should store serialization information.
737: **/
738: public static final FileObject getStorageFile(FileObject configFile) {
739: // FileObject webFolder = getWebFolder(configFile);
740: Project p = FileOwnerQuery.getOwner(configFile);
741: if (p == null) {
742: LOG
743: .warning("File does not exist inside a project. Can't solve getStorageFile().");
744: System.err
745: .println("File does not exist inside a project. Can't solve getStorageFile().");
746: return null;
747: }
748: FileObject projectDirectory = p.getProjectDirectory();
749: FileObject nbprojectFolder = projectDirectory.getFileObject(
750: "nbproject", null);
751: if (nbprojectFolder == null) {
752: LOG.warning("Unable to create access the follow folder: "
753: + nbprojectFolder);
754: System.err
755: .println("Unable to create access the follow folder:"
756: + nbprojectFolder);
757: return null;
758: }
759:
760: String filename = configFile.getName() + ".NavData";
761: FileObject storageFile = nbprojectFolder
762: .getFileObject(filename);
763: if (storageFile == null) {
764: try {
765: storageFile = nbprojectFolder.createData(filename);
766: } catch (IOException ex) {
767: Exceptions.printStackTrace(ex);
768: }
769: }
770: return storageFile;
771: }
772:
773: /*
774: * Figures out the current web folder
775: * @return the project web folder.
776: */
777: public static final FileObject getWebFolder(FileObject configFile) {
778: WebModule webModule = WebModule.getWebModule(configFile);
779:
780: if (webModule == null) {
781: LOG
782: .warning("This configuration file is not part of a webModule: "
783: + configFile);
784: System.err
785: .println("This configuration file is not part of a webModule: "
786: + configFile);
787: return null;
788: }
789: FileObject webFolder = webModule.getDocumentBase();
790: return webFolder;
791: }
792:
793: /* Use to keep the node locations for the next time the Page Flow Editor is
794: * opened.
795: */
796: public void serializeNodeLocations(FileObject navDataFile) {
797: if (navDataFile != null) {
798: saveLocations();
799: SceneSerializer.serialize(sceneData, navDataFile);
800: }
801: }
802:
803: /* Takes the storage file and grabs the various locations and the last used
804: * scope. It then sets the node information.
805: */
806: public void deserializeNodeLocation(FileObject navDataFile) {
807: if (navDataFile != null && navDataFile.isValid()
808: && navDataFile.getSize() > 0) {
809: SceneSerializer.deserialize(sceneData, navDataFile);
810: }
811: }
812:
813: @Override
814: protected String preferredID() {
815: return "PageFlowEditor";
816: }
817:
818: @Override
819: public int getPersistenceType() {
820: return PERSISTENCE_NEVER;
821: }
822:
823: /* Keep the last layout used so you can toggle through them with the layout button. */
824: LayoutUtility.LayoutType lastUsedLayout = LayoutUtility.LayoutType.GRID_GRAPH;
825:
826: /*
827: * Method use to reset the layout of the various pages
828: */
829: public void layoutNodes() {
830: LayoutUtility.LayoutType useLayout = null;
831:
832: switch (lastUsedLayout) {
833: case GRID_GRAPH:
834: useLayout = LayoutUtility.LayoutType.FREE_PLACES_NODES;
835: break;
836: case FREE_PLACES_NODES:
837: // useLayout = LayoutUtility.LayoutType.TREE_GRAPH;
838: // break;
839: // case TREE_GRAPH:
840: useLayout = LayoutUtility.LayoutType.GRID_GRAPH;
841: break;
842: }
843:
844: LayoutUtility.performLayout(getScene(), useLayout);
845: lastUsedLayout = useLayout;
846: }
847:
848: /*
849: * Start the background process for loading on the inner page (pin)
850: * information.
851: */
852: // protected void startBackgroundPinAddingProcess() {
853: // executor.prestartAllCoreThreads();
854: // }
855: /*
856: * Prevent any Runners that have not completed from running. This is important
857: * when the scope is being changed and we no longer want the pages to continue
858: * loading.
859: */
860: // protected void clearBackgroundPinAddingProcess() {
861: // executor.purge();
862: // }
863: private WeakReference<PageFlowElement> multiviewRef;
864:
865: public PageFlowElement getMultiview() {
866: PageFlowElement multiview = null;
867: if (multiviewRef != null) {
868: multiview = multiviewRef.get();
869: }
870: return multiview;
871: }
872:
873: public void setMultiview(PageFlowElement multiview) {
874: this .multiviewRef = new WeakReference<PageFlowElement>(
875: multiview);
876: }
877:
878: /* To be used for unit test purposes only. */
879: static class PFVTestAccessor {
880: static PageFlowScene getPageFlowScene(PageFlowView view)
881: throws InterruptedException {
882: if (view.getScene() == null) {
883: Thread.sleep(3000);
884: }
885: return view.getScene();
886: }
887: }
888:
889: }
|