001: /*
002: The contents of this file are subject to the Common Public Attribution License
003: Version 1.0 (the "License"); you may not use this file except in compliance with
004: the License. You may obtain a copy of the License at
005: http://www.projity.com/license . The License is based on the Mozilla Public
006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
007: software over a computer network and provide for limited attribution for the
008: Original Developer. In addition, Exhibit A has been modified to be consistent
009: with Exhibit B.
010:
011: Software distributed under the License is distributed on an "AS IS" basis,
012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
013: specific language governing rights and limitations under the License. The
014: Original Code is OpenProj. The Original Developer is the Initial Developer and
015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
017:
018: Alternatively, the contents of this file may be used under the terms of the
019: Projity End-User License Agreeement (the Projity License), in which case the
020: provisions of the Projity License are applicable instead of those above. If you
021: wish to allow use of your version of this file only under the terms of the
022: Projity License and not to allow others to use your version of this file under
023: the CPAL, indicate your decision by deleting the provisions above and replace
024: them with the notice and other provisions required by the Projity License. If
025: you do not delete the provisions above, a recipient may use your version of this
026: file under either the CPAL or the Projity License.
027:
028: [NOTE: The text of this license may differ slightly from the text of the notices
029: in Exhibits A and B of the license at http://www.projity.com/license. You should
030: use the latest text at http://www.projity.com/license for your modifications.
031: You may not remove this license text from the source files.]
032:
033: Attribution Information: Attribution Copyright Notice: Copyright © 2006, 2007
034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
035: an open source solution from Projity. Attribution URL: http://www.projity.com
036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
037: alternatives listed on http://www.projity.com/logo
038:
039: Display of Attribution Information is required in Larger Works which are defined
040: in the CPAL as a work which combines Covered Code or portions thereof with code
041: not governed by the terms of the CPAL. However, in addition to the other notice
042: obligations, all copies of the Covered Code in Executable and Source Code form
043: distributed must, as a form of attribution of the original author, include on
044: each user interface screen the "OpenProj" logo visible to all users. The
045: OpenProj logo should be located horizontally aligned with the menu bar and left
046: justified on the top left of the screen adjacent to the File menu. The logo
047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
048: must direct them back to http://www.projity.com.
049: */
050: package com.projity.pm.graphic.model.cache;
051:
052: import java.util.ArrayList;
053: import java.util.Iterator;
054: import java.util.List;
055: import java.util.ListIterator;
056:
057: import javax.swing.event.EventListenerList;
058: import javax.swing.event.TreeModelEvent;
059: import javax.swing.event.TreeModelListener;
060: import javax.swing.tree.TreePath;
061:
062: import org.apache.commons.collections.Closure;
063:
064: import com.projity.association.InvalidAssociationException;
065: import com.projity.grouping.core.Node;
066: import com.projity.grouping.core.model.NodeModel;
067: import com.projity.grouping.core.model.WalkersNodeModel;
068: import com.projity.grouping.core.transform.TransformList;
069: import com.projity.grouping.core.transform.ViewTransformerEvent;
070: import com.projity.grouping.core.transform.ViewTransformerListener;
071: import com.projity.pm.graphic.model.event.CacheListener;
072: import com.projity.pm.graphic.model.event.CompositeCacheEvent;
073: import com.projity.pm.graphic.model.transform.DependencyCacheTransformer;
074: import com.projity.pm.graphic.model.transform.NodeCacheTransformer;
075:
076: /**
077: *
078: */
079: public class ViewNodeModelCache implements NodeModelCache,
080: ViewTransformerListener, CacheListener {
081: protected ReferenceNodeModelCache reference;
082: protected VisibleNodes visibleNodes;
083: protected VisibleDependencies visibleDependencies;
084: protected String viewName;
085:
086: ViewNodeModelCache(ReferenceNodeModelCache reference,
087: String viewName, Closure transformerClosure) {
088: this (reference, new VisibleNodes(viewName,
089: new NodeCacheTransformer(viewName, reference,
090: transformerClosure)), new VisibleDependencies(
091: viewName, new DependencyCacheTransformer(viewName,
092: reference)));
093: this .viewName = viewName;
094: }
095:
096: /**
097: * @param reference
098: * @param visibleNodes
099: * @param visibleDependencies
100: */
101: private ViewNodeModelCache(ReferenceNodeModelCache reference,
102: VisibleNodes visibleNodes,
103: VisibleDependencies visibleDependencies) {
104: this .reference = reference;
105: this .visibleNodes = visibleNodes;
106: this .visibleDependencies = visibleDependencies;
107: addNodeModelListener(this );
108: visibleDependencies.setVisibleNodes(visibleNodes);
109: visibleNodes.setVisibleDependencies(visibleDependencies);
110: reference.bindView(visibleNodes, visibleDependencies);
111: ((NodeCacheTransformer) visibleNodes.getTransformer())
112: .getTransformer().addViewTransformerListener(this );
113:
114: }
115:
116: public NodeModel getModel() {
117: return reference.getModel();
118: }
119:
120: public void setModel(NodeModel model) {
121: reference.setModel(model);
122: }
123:
124: public WalkersNodeModel getWalkersModel() {
125: NodeCacheTransformer transformer = (NodeCacheTransformer) visibleNodes
126: .getTransformer();
127: return transformer.getWalkersModel();
128: }
129:
130: public void setType(int type) {
131: reference.setType(type);
132: }
133:
134: public int getType() {
135: return reference.getType();
136: }
137:
138: public String getViewName() {
139: return viewName;
140: }
141:
142: public void transformerChanged(ViewTransformerEvent e) {
143: update();
144: }
145:
146: public void update() {
147: // System.out.println("ViewNodeModelCache update "+getViewName());
148: reference.updateVisibleElements(visibleNodes);
149: }
150:
151: public ReferenceNodeModelCache getReference() {
152: return reference;
153: }
154:
155: public Object getElementAt(int i) {
156: return visibleNodes.getElementAt(i);
157: }
158:
159: public ListIterator getIterator() {
160: return visibleNodes.getIterator();
161: }
162:
163: public ListIterator getIterator(int i) {
164: return visibleNodes.getIterator(i);
165: }
166:
167: public ListIterator getEdgesIterator() {
168: return visibleDependencies.getIterator();
169: }
170:
171: public ListIterator getEdgesIterator(int i) {
172: return visibleDependencies.getIterator(i);
173: }
174:
175: // public void forEach(CacheClosure c){
176: // Stack stack=new Stack();
177: // GraphicNode node=null,nextNode=null,history;
178: // if (getSize()==0) return;
179: // ListIterator i=getIterator();
180: // node=(GraphicNode)i.next();
181: // while (i.hasNext()){
182: // nextNode=(GraphicNode)i.next();
183: // if (nextNode.getLevel()>node.getLevel()){
184: // stack.push(node);
185: // }else{
186: // c.execute(node,nextNode.getLevel()-node.getLevel());
187: // while (((GraphicNode)stack.peek()).getLevel()>=nextNode.getLevel())
188: // c.execute((GraphicNode)stack.pop(),nextNode.getLevel()-node.getLevel());
189: // }
190: // node=nextNode;
191: // }
192: // if (nextNode!=null) c.execute(nextNode,nextNode.getLevel()-node.getLevel());
193: // }
194: public int getMaxLevel() {
195: int level = 0;
196: GraphicNode node;
197: for (Iterator i = getIterator(); i.hasNext();) {
198: node = (GraphicNode) i.next();
199: if (node.getLevel() > level)
200: level = node.getLevel();
201: }
202: return level;
203: }
204:
205: public List getElementsAt(int[] i) {
206: ArrayList list = new ArrayList(i.length);
207: for (int j = 0; j < i.length; j++) {
208: Object element = getElementAt(i[j]);
209: if (element != null)
210: list.add(element);
211: }
212: return list;
213: }
214:
215: public List getNodesAt(int[] i) {
216: ArrayList list = new ArrayList(i.length);
217: for (int j = 0; j < i.length; j++) {
218: Object base = ((GraphicNode) getElementAt(i[j])).getNode();
219: if (base != null)
220: list.add(base);
221: }
222: return list;
223: }
224:
225: public Object getEdgeElementAt(int i) {
226: return visibleDependencies.getElementAt(i);
227: }
228:
229: public int getSize() {
230: return visibleNodes.getSize();
231: }
232:
233: public int getEdgesSize() {
234: return visibleDependencies.getSize();
235: }
236:
237: public int getRowAt(Object node) {
238: return visibleNodes.getRow(node);
239: }
240:
241: public Object getGraphicNode(Object base) {
242: return reference.getGraphicNode(base);
243: }
244:
245: public Object getGraphicDependency(Object base) {
246: return reference.getGraphicDependency(base);
247: }
248:
249: public GraphicNode getParent(GraphicNode node) {
250: GraphicNode parent = reference.getParent(node);
251: if (visibleNodes.getElements().contains(node))
252: return parent;
253: else
254: return null;
255: }
256:
257: public List getChildren(GraphicNode node) {
258: List children = reference.getChildren(node);
259: if (children == null)
260: return null;
261: List elements = visibleNodes.getElements();
262: for (Iterator i = children.iterator(); i.hasNext();) {
263: if (!elements.contains(i.next()))
264: i.remove();
265: }
266: return children;
267: }
268:
269: public void changeCollapsedState(GraphicNode node) {
270: reference.changeCollapsedState(node);
271: }
272:
273: public void createDependency(GraphicNode startNode,
274: GraphicNode endNode) throws InvalidAssociationException {
275: reference.createDependency(startNode, endNode);
276:
277: }
278:
279: public void createHierarchyDependency(GraphicNode startNode,
280: GraphicNode endNode) throws InvalidAssociationException {
281: reference.createDependency(startNode, endNode);
282: }
283:
284: public void addNodeModelListener(CacheListener l) {
285: visibleNodes.addNodeModelListener(l);
286: }
287:
288: public void removeNodeModelListener(CacheListener l) {
289: visibleNodes.removeNodeModelListener(l);
290: }
291:
292: public CacheListener[] getNodeModelListeners() {
293: return visibleNodes.getNodeModelListeners();
294: }
295:
296: public void close() {
297: }
298:
299: public void newNode(GraphicNode gnode) {
300: Node parent = getModel().getParent(gnode.getNode());
301: int index = parent.getIndex(gnode.getNode());
302: getModel().newNode(parent, index, NodeModel.NORMAL);
303: }
304:
305: public void deleteNodes(List nodes) {
306: getModel().remove(nodes, NodeModel.NORMAL);
307: }
308:
309: public void cutNodes(List nodes) {
310: List newNodes = getModel().cut(nodes, NodeModel.NORMAL);
311: nodes.clear();
312: nodes.addAll(newNodes);
313: }
314:
315: public void copyNodes(List nodes) {
316: List newNodes = getModel().copy(nodes, NodeModel.NORMAL);
317: nodes.clear();
318: nodes.addAll(newNodes);
319: }
320:
321: public void pasteNodes(Node parent, List nodes, int position) {
322: getModel().paste(parent, nodes, position, NodeModel.NORMAL);
323: }
324:
325: public void addNodes(Node sibling, List nodes) {
326: getModel().addBefore(sibling, nodes, NodeModel.NORMAL);
327: }
328:
329: public void expandNodes(List nodes, boolean expand) {
330: if (nodes == null)
331: return;
332:
333: if (nodes.size() > 0) {
334: Iterator i = nodes.iterator();
335: while (i.hasNext()) {
336: GraphicNode gnode = (GraphicNode) i.next();
337: if (expand && !gnode.isFetched()) // for subprojects
338: gnode.fetch();
339:
340: if (gnode.isCollapsed() == expand)
341: changeCollapsedState(gnode);
342: }
343: }
344: }
345:
346: public void indentNodes(List nodes) {
347: if (nodes == null)
348: return;
349: List validNodes = TransformList.getNotVoidFilter().filterList(
350: convertToBase(nodes));
351: if (validNodes.size() > 0)
352: getModel().getHierarchy().indent(validNodes, 1, getModel(),
353: NodeModel.NORMAL);
354: }
355:
356: public void outdentNodes(List nodes) {
357: if (nodes == null)
358: return;
359: List validNodes = TransformList.getNotVoidFilter().filterList(
360: convertToBase(nodes));
361: if (validNodes.size() > 0)
362: getModel().getHierarchy().indent(validNodes, -1,
363: getModel(), NodeModel.NORMAL);
364: }
365:
366: //returns same list with converted elements
367: private List convertToBase(List gnodes) {
368: if (gnodes == null)
369: return null;
370: for (ListIterator i = gnodes.listIterator(); i.hasNext();)
371: i.set(((GraphicNode) i.next()).getNode());
372: return gnodes;
373: }
374:
375: private int getLastNormalRow() {
376: for (int i = visibleNodes.getSize() - 1; i >= 0; i--) {
377: GraphicNode current = (GraphicNode) visibleNodes
378: .getElementAt(i);
379: if (!current.isVoid())
380: return i;
381: }
382: return -1;
383: }
384:
385: // /**
386: // * Returns the parent/previous,position identification of the position
387: // * to insert a void node.
388: // * The fist normal node preceding it.
389: // * Same level if the node isn't composite and collapsed
390: // * @param row
391: // * @return
392: // */
393: // private NodeHierarchyVoidLocation getVoidNodeCreationInfoObject(GraphicNode refNode){
394: // int row=getRowAt(refNode);
395: // if (row==0){
396: // int lastRow=getLastNormalRow();
397: // if (row>lastRow) return new NodeHierarchyVoidLocation(NodeHierarchyLocation.END_LOCATION,row-lastRow);
398: // return new NodeHierarchyVoidLocation(new NodeHierarchyLocation(null,null),1);
399: // }
400: // GraphicNode node=(GraphicNode)visibleNodes.getElementAt(row-1);
401: // if (node.isVoid()){
402: // NodeHierarchyVoidLocation info=getVoidNodeInfoObject(row-1);
403: // info.setPosition(info.getPosition()+1);
404: // return info;
405: // }else{
406: // Node parent;
407: // if (node.isSummary()&&!(node.isCollapsed())){
408: // parent=node.getNode();
409: // }else{
410: // parent=getModel().getHierarchy().getParent(node.getNode());
411: // }
412: // return new NodeHierarchyVoidLocation(new NodeHierarchyLocation(parent,node.getNode()),1);
413: // }
414: // }
415: //
416: // /**
417: // * Returns the parent/previous,position identification of the void node at row
418: // * Apply this to a void node row only
419: // * @param row
420: // * @return
421: // */
422: // public NodeHierarchyVoidLocation getVoidNodeInfoObject(GraphicNode refNode){
423: // int row=getRowAt(refNode);
424: // return getVoidNodeInfoObject(row);
425: // }
426: // private NodeHierarchyVoidLocation getVoidNodeInfoObject(int row){
427: //
428: // int lastRow=getLastNormalRow();
429: // if (row>lastRow){
430: // GraphicNode gnode=(lastRow>=0)?(GraphicNode)visibleNodes.getElementAt(lastRow):null;
431: // return new NodeHierarchyVoidLocation(NodeHierarchyLocation.END_LOCATION,row-lastRow,(gnode==null)?1:gnode.getLevel());
432: // }
433: //
434: // //Find the normal node just before the series of void nodes
435: // //It must be a sibling or a parent
436: // GraphicNode gnode=null;
437: // GraphicNode node0=(GraphicNode)visibleNodes.getElementAt(row);
438: // for (int i=row-1;i>-1;i--){
439: // GraphicNode current=(GraphicNode)visibleNodes.getElementAt(i);
440: // if (!current.isVoid()&&getLevel(current)<=getLevel(node0)){
441: // gnode=current;
442: // break;
443: // }
444: // }
445: //
446: // //find the position of the void node in the series
447: // //1 is the first one
448: // int pos=1;
449: // int voidLevel=getLevel(node0);
450: // for (;pos<=row;pos++){
451: // GraphicNode current=(GraphicNode)visibleNodes.getElementAt(row-pos);
452: // if (!(current.isVoid()&&getLevel(current)==voidLevel))
453: // break;
454: // }
455: //
456: //
457: //
458: // if (gnode==null) return new NodeHierarchyVoidLocation(new NodeHierarchyLocation(null,null),pos);
459: //
460: // //find the first non void node of level>level of void node
461: // //It is gnode or the parent of gnode
462: // Node parent;
463: // if (getLevel(gnode)<getLevel(node0)){
464: // parent=gnode.getNode();
465: // }else{
466: // parent=getModel().getHierarchy().getParent(gnode.getNode());
467: // }
468: //
469: // return new NodeHierarchyVoidLocation(new NodeHierarchyLocation(parent,gnode.getNode()),pos);
470: // }
471:
472: public int getLevel(GraphicNode node) {
473: if (node.isGroup())
474: return node.getLevel();
475: NodeCacheTransformer transformer = (NodeCacheTransformer) visibleNodes
476: .getTransformer();
477: return node.getLevel() + transformer.getLevelOffset();
478: }
479:
480: public int getPertLevel(GraphicNode node) {
481: return node.getPertLevel();
482: }
483:
484: public void setPertLevel(GraphicNode node, int level) {
485: node.setPertLevel(level);
486: }
487:
488: public VisibleDependencies getVisibleDependencies() {
489: return visibleDependencies;
490: }
491:
492: public VisibleNodes getVisibleNodes() {
493: return visibleNodes;
494: }
495:
496: public boolean isReceiveEvents() {
497: return reference.isReceiveEvents();
498: }
499:
500: public void setReceiveEvents(boolean receiveEvents) {
501: reference.setReceiveEvents(receiveEvents);
502: }
503:
504: //TreeModel
505: public Object getChild(Object obj, int index) {
506: ListIterator i = getIterator();
507: GraphicNode node;
508: GraphicNode ref = null;
509: if (obj == getRoot())
510: ref = (GraphicNode) getRoot();
511: else
512: while (i.hasNext()) {
513: node = (GraphicNode) i.next();
514: if (node == obj) {
515: ref = node;
516: break;
517: }
518: }
519: if (ref == null)
520: return null;
521: int count = 0;
522: while (i.hasNext()) {
523: node = (GraphicNode) i.next();
524: if (node.getLevel() <= ref.getLevel())
525: break;
526: else if (node.getLevel() == ref.getLevel() + 1) {
527: if (count == index)
528: return node;
529: count++;
530: }
531: }
532: return null;
533: }
534:
535: public int getChildCount(Object obj) {
536: ListIterator i = getIterator();
537: GraphicNode node;
538: GraphicNode ref = null;
539: if (obj == getRoot())
540: ref = (GraphicNode) getRoot();
541: else
542: while (i.hasNext()) {
543: node = (GraphicNode) i.next();
544: if (node == obj) {
545: ref = node;
546: break;
547: }
548: }
549: int count = 0;
550: if (ref != null)
551: while (i.hasNext()) {
552: node = (GraphicNode) i.next();
553: if (node.getLevel() <= ref.getLevel())
554: break;
555: else if (node.getLevel() == ref.getLevel() + 1)
556: count++;
557: }
558: return count;
559: }
560:
561: public int getIndexOfChild(Object parent, Object child) {
562: ListIterator i = getIterator();
563: GraphicNode node;
564: GraphicNode ref = null;
565: if (parent == getRoot())
566: ref = (GraphicNode) getRoot();
567: else
568: while (i.hasNext()) {
569: node = (GraphicNode) i.next();
570: if (node == parent) {
571: ref = node;
572: break;
573: }
574: }
575: if (ref == null)
576: return -1;
577: int count = 0;
578: while (i.hasNext()) {
579: node = (GraphicNode) i.next();
580: if (node.getLevel() <= ref.getLevel())
581: break;
582: else if (node.getLevel() == ref.getLevel() + 1) {
583: if (node == child)
584: return count;
585: count++;
586: }
587: }
588: return -1;
589: }
590:
591: public Object getRoot() {
592: return reference.getRoot();
593: }
594:
595: public boolean isLeaf(Object obj) {
596: ListIterator i = getIterator();
597: GraphicNode node;
598: GraphicNode ref = null;
599: if (obj == getRoot())
600: ref = (GraphicNode) getRoot();
601: else
602: while (i.hasNext()) {
603: node = (GraphicNode) i.next();
604: if (node == obj) {
605: ref = node;
606: break;
607: }
608: }
609: if (ref == null)
610: return true;
611: if (i.hasNext()) {
612: node = (GraphicNode) i.next();
613: if (node.getLevel() > ref.getLevel())
614: return false;
615: else
616: return true;
617: }
618: return true;
619: }
620:
621: public void valueForPathChanged(TreePath path, Object obj) {
622: }
623:
624: //TreeModel events
625: protected EventListenerList treeModelListenerList = new EventListenerList();
626:
627: public void addTreeModelListener(TreeModelListener l) {
628: treeModelListenerList.add(TreeModelListener.class, l);
629: }
630:
631: public void removeTreeModelListener(TreeModelListener l) {
632: treeModelListenerList.remove(TreeModelListener.class, l);
633: }
634:
635: protected void fireTreeModelUpdate(Object source) {
636: Object[] listeners = treeModelListenerList.getListenerList();
637: TreeModelEvent e = null;
638: for (int i = listeners.length - 2; i >= 0; i -= 2) {
639: if (listeners[i] == TreeModelListener.class) {
640: if (e == null) {
641: e = new TreeModelEvent(source,
642: new Object[] { getRoot() });
643: }
644: ((TreeModelListener) listeners[i + 1])
645: .treeStructureChanged(e);
646: }
647: }
648: }
649:
650: public void graphicNodesCompositeEvent(CompositeCacheEvent e) {
651: fireTreeModelUpdate(this);
652: }
653:
654: }
|