Source Code Cross Referenced for GraphLayoutCache.java in  » Graphic-Library » jgraph » org » jgraph » graph » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Graphic Library » jgraph » org.jgraph.graph 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * @(#)GraphLayoutCache.java 1.0 03-JUL-04
0003:         * 
0004:         * Copyright (c) 2001-2004 Gaudenz Alder
0005:         *  
0006:         */
0007:        package org.jgraph.graph;
0008:
0009:        import java.awt.geom.Rectangle2D;
0010:        import java.io.IOException;
0011:        import java.io.ObjectInputStream;
0012:        import java.io.ObjectOutputStream;
0013:        import java.io.Serializable;
0014:        import java.util.ArrayList;
0015:        import java.util.Collection;
0016:        import java.util.HashSet;
0017:        import java.util.Hashtable;
0018:        import java.util.Iterator;
0019:        import java.util.LinkedList;
0020:        import java.util.List;
0021:        import java.util.Map;
0022:        import java.util.Set;
0023:        import java.util.Stack;
0024:        import java.util.WeakHashMap;
0025:
0026:        import javax.swing.event.EventListenerList;
0027:        import javax.swing.undo.CannotRedoException;
0028:        import javax.swing.undo.CannotUndoException;
0029:        import javax.swing.undo.CompoundEdit;
0030:        import javax.swing.undo.UndoableEdit;
0031:
0032:        import org.jgraph.event.GraphLayoutCacheEvent;
0033:        import org.jgraph.event.GraphLayoutCacheListener;
0034:        import org.jgraph.event.GraphModelEvent;
0035:
0036:        /**
0037:         * An object that defines the view of a graphmodel. This object maps between
0038:         * model cells and views and provides a set of methods to change these views.
0039:         * The view may also contain its own set of attributes and is therefore an
0040:         * extension of an Observable, which may be observed by the GraphUI. It uses the
0041:         * model to send its changes to the command history.
0042:         * 
0043:         * @version 1.0 1/1/02
0044:         * @author Gaudenz Alder
0045:         */
0046:        public class GraphLayoutCache implements  CellMapper, Serializable {
0047:
0048:            /**
0049:             * True if the cells should be auto-sized when their values change. Default
0050:             * is false.
0051:             */
0052:            protected boolean autoSizeOnValueChange = false;
0053:
0054:            /**
0055:             * Boolean indicating whether existing connections should me made visible if
0056:             * their sources or targets are made visible, given the opposite end of the
0057:             * edge is already visible or made visible, too. Default is true.
0058:             */
0059:            protected boolean showsExistingConnections = true;
0060:
0061:            /**
0062:             * Boolean indicating whether connections should be made visible when
0063:             * reconnected and their source and target port is visible. Default is true.
0064:             */
0065:            protected boolean showsChangedConnections = true;
0066:
0067:            /**
0068:             * Boolean indicating whether edited cells should be made visible if they
0069:             * are changed via
0070:             * {@link #edit(Map, ConnectionSet, ParentMap, UndoableEdit[])}. Default is
0071:             * true.
0072:             */
0073:            protected boolean showsInvisibleEditedCells = true;
0074:
0075:            /**
0076:             * Boolean indicating whether inserted should be made visible if they are
0077:             * inserted via
0078:             * {@link #insert(Object[], Map, ConnectionSet, ParentMap, UndoableEdit[])}.
0079:             * Default is true.
0080:             */
0081:            protected boolean showsInsertedCells = true;
0082:
0083:            /**
0084:             * Boolean indicating whether inserted edges should me made visible if their
0085:             * sources or targets are already visible. Default is true.
0086:             */
0087:            protected boolean showsInsertedConnections = true;
0088:
0089:            /**
0090:             * Boolean indicating whether existing connections should be hidden if their
0091:             * source or target and no parent of the ports is visible, either by hiding
0092:             * the cell or by changing the source or target of the edge to a hidden
0093:             * cell. Default is true.
0094:             */
0095:            protected boolean hidesExistingConnections = true;
0096:
0097:            /**
0098:             * Boolean indicating whether existing connections should be hidden if their
0099:             * source or target port is removed from the model. Default is false.
0100:             */
0101:            protected boolean hidesDanglingConnections = false;
0102:
0103:            /**
0104:             * Boolean indicating whether cellviews should be remembered once visible in
0105:             * this GraphLayoutCache. Default is true.
0106:             */
0107:            protected boolean remembersCellViews = true;
0108:
0109:            /**
0110:             * Boolean indicating whether inserted cells should automatically be
0111:             * selected. Default is true. This is ignored if the cache is partial. Note:
0112:             * Despite the name of this field the implementation is located in the
0113:             * BasicGraphUI.GraphModelHandler.graphChanged method.
0114:             */
0115:            protected boolean selectsAllInsertedCells = false;
0116:
0117:            /**
0118:             * Boolean indicating whether cells that are inserted using the local insert
0119:             * method should automatically be selected. Default is true. This is ignored
0120:             * if the cache is not partial and selectsAllInsertedCells is true, in which
0121:             * case the cells will be selected through another mechanism. Note: Despite
0122:             * the name of this field the implementation is located in the
0123:             * BasicGraphUI.GraphLayoutCacheObserver.changed method.
0124:             */
0125:            protected boolean selectsLocalInsertedCells = false;
0126:
0127:            /**
0128:             * Boolean indicating whether children should be moved to the parent group's
0129:             * origin on expand. Default is true.
0130:             */
0131:            protected boolean movesChildrenOnExpand = true;
0132:
0133:            /**
0134:             * Boolean indicating whether parents should be moved to the child area
0135:             * origin on collapse. Default is true.
0136:             */
0137:            protected boolean movesParentsOnCollapse = true;
0138:
0139:            /**
0140:             * Boolean indicating whether parents should always be resized to the child
0141:             * area on collapse. If false the size is only initially updated if it has
0142:             * not yet been assigned. Default is false.
0143:             */
0144:            protected boolean resizesParentsOnCollapse = false;
0145:
0146:            /**
0147:             * Specified the initial x- and y-scaling factor for initial collapsed group
0148:             * bounds. Default is 1.0, ie. no scaling.
0149:             */
0150:            protected double collapseXScale = 1.0, collapseYScale = 1.0;
0151:
0152:            /**
0153:             * Boolean indicating whether edges should be reconneted to visible parents
0154:             * on collapse/expand. Default is false.
0155:             * 
0156:             * @deprecated edges are moved to parent view and back automatically
0157:             */
0158:            protected boolean reconnectsEdgesToVisibleParent = false;
0159:
0160:            /**
0161:             * The list of listeners that listen to the model.
0162:             */
0163:            protected EventListenerList listenerList = new EventListenerList();
0164:
0165:            /**
0166:             * Reference to the graphModel
0167:             */
0168:            protected GraphModel graphModel;
0169:
0170:            /**
0171:             * Maps cells to views.
0172:             */
0173:            protected Map mapping = new Hashtable();
0174:
0175:            /**
0176:             * Maps cells to views. The hidden mapping is used to remembed cell views
0177:             * that are hidden, based on the remembersCellViews setting. hiddenMapping
0178:             * must use weak keys for the cells since when cells are removed
0179:             * hiddenMapping is not updated.
0180:             */
0181:            protected transient Map hiddenMapping = new WeakHashMap();
0182:
0183:            /**
0184:             * Factory to create the views.
0185:             */
0186:            protected CellViewFactory factory = null;
0187:
0188:            /**
0189:             * The set of visible cells.
0190:             */
0191:            protected Set visibleSet = new HashSet();
0192:
0193:            /**
0194:             * Ordered list of roots for the view.
0195:             */
0196:            protected List roots = new ArrayList();
0197:
0198:            /**
0199:             * Cached array of all ports for the view.
0200:             */
0201:            protected PortView[] ports;
0202:
0203:            /**
0204:             * Only portions of the model are visible.
0205:             */
0206:            protected boolean partial = false;
0207:
0208:            /**
0209:             * Controls if all attributes are local. If this is false then the
0210:             * createLocalEdit will check the localAttributes set to see if a specific
0211:             * attribute is local, otherwise it will assume that all attributes are
0212:             * local. This allows to make all attributes local without actually knowing
0213:             * them. Default is false.
0214:             */
0215:            protected boolean allAttributesLocal = false;
0216:
0217:            /**
0218:             * A set containing all attribute keys that are stored in the cell views, in
0219:             * other words, the view-local attributes.
0220:             */
0221:            protected Set localAttributes = new HashSet();
0222:
0223:            /**
0224:             * Constructs a graph layout cache.
0225:             */
0226:            public GraphLayoutCache() {
0227:                this (new DefaultGraphModel(), new DefaultCellViewFactory());
0228:            }
0229:
0230:            /**
0231:             * Constructs a view for the specified model that uses <code>factory</code>
0232:             * to create its views.
0233:             * 
0234:             * @param model
0235:             *            the model that constitues the data source
0236:             */
0237:            public GraphLayoutCache(GraphModel model, CellViewFactory factory) {
0238:                this (model, factory, false);
0239:            }
0240:
0241:            /**
0242:             * Constructs a view for the specified model that uses <code>factory</code>
0243:             * to create its views.
0244:             * 
0245:             * @param model
0246:             *            the model that constitues the data source
0247:             */
0248:            public GraphLayoutCache(GraphModel model, CellViewFactory factory,
0249:                    boolean partial) {
0250:                this (model, factory, null, null, partial);
0251:            }
0252:
0253:            /**
0254:             * Constructs a view for the specified model that uses <code>factory</code>
0255:             * to create its views.
0256:             * 
0257:             * @param model
0258:             *            the model that constitues the data source
0259:             */
0260:            public GraphLayoutCache(GraphModel model, CellViewFactory factory,
0261:                    CellView[] cellViews, CellView[] hiddenCellViews,
0262:                    boolean partial) {
0263:                this .factory = factory;
0264:                this .partial = partial;
0265:                if (cellViews != null) {
0266:                    graphModel = model;
0267:                    for (int i = 0; i < cellViews.length; i++) {
0268:                        if (cellViews[i] != null) {
0269:                            putMapping(cellViews[i].getCell(), cellViews[i]);
0270:                            if (partial)
0271:                                visibleSet.add(cellViews[i].getCell());
0272:                        }
0273:                    }
0274:                    insertViews(cellViews);
0275:                    // Notify observers for autosizing?
0276:                } else {
0277:                    setModel(model);
0278:                }
0279:                if (hiddenCellViews != null) {
0280:                    for (int i = 0; i < hiddenCellViews.length; i++)
0281:                        hiddenMapping.put(hiddenCellViews[i].getCell(),
0282:                                hiddenCellViews[i]);
0283:                }
0284:            }
0285:
0286:            //
0287:            // GraphLayoutCacheListeners
0288:            //
0289:
0290:            /**
0291:             * Adds a listener for the GraphLayoutCacheEvent posted after the graph
0292:             * layout cache changes.
0293:             * 
0294:             * @see #removeGraphLayoutCacheListener
0295:             * @param l
0296:             *            the listener to add
0297:             */
0298:            public void addGraphLayoutCacheListener(GraphLayoutCacheListener l) {
0299:                listenerList.add(GraphLayoutCacheListener.class, l);
0300:            }
0301:
0302:            /**
0303:             * Removes a listener previously added with <B>addGraphLayoutCacheListener()
0304:             * </B>.
0305:             * 
0306:             * @see #addGraphLayoutCacheListener
0307:             * @param l
0308:             *            the listener to remove
0309:             */
0310:            public void removeGraphLayoutCacheListener(
0311:                    GraphLayoutCacheListener l) {
0312:                listenerList.remove(GraphLayoutCacheListener.class, l);
0313:            }
0314:
0315:            /**
0316:             * Invoke this method after you've changed how the cells are to be
0317:             * represented in the graph.
0318:             */
0319:            public void cellViewsChanged(final CellView[] cellViews) {
0320:                if (cellViews != null) {
0321:                    fireGraphLayoutCacheChanged(this ,
0322:                            new GraphLayoutCacheEvent.GraphLayoutCacheChange() {
0323:
0324:                                public Object[] getInserted() {
0325:                                    return null;
0326:                                }
0327:
0328:                                public Object[] getRemoved() {
0329:                                    return null;
0330:                                }
0331:
0332:                                public Map getPreviousAttributes() {
0333:                                    return null;
0334:                                }
0335:
0336:                                public Object getSource() {
0337:                                    return this ;
0338:                                }
0339:
0340:                                public Object[] getChanged() {
0341:                                    return cellViews;
0342:                                }
0343:
0344:                                public Map getAttributes() {
0345:                                    return null;
0346:                                }
0347:
0348:                                public Object[] getContext() {
0349:                                    return null;
0350:                                }
0351:
0352:                            });
0353:                }
0354:            }
0355:
0356:            /*
0357:             * Notify all listeners that have registered interest for notification on
0358:             * this event type. The event instance is lazily created using the
0359:             * parameters passed into the fire method.
0360:             * 
0361:             * @see EventListenerList
0362:             */
0363:            protected void fireGraphLayoutCacheChanged(Object source,
0364:                    GraphLayoutCacheEvent.GraphLayoutCacheChange edit) {
0365:                // Guaranteed to return a non-null array
0366:                Object[] listeners = listenerList.getListenerList();
0367:                GraphLayoutCacheEvent e = null;
0368:                // Process the listeners last to first, notifying
0369:                // those that are interested in this event
0370:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
0371:                    if (listeners[i] == GraphLayoutCacheListener.class) {
0372:                        // Lazily create the event:
0373:                        if (e == null)
0374:                            e = new GraphLayoutCacheEvent(source, edit);
0375:                        ((GraphLayoutCacheListener) listeners[i + 1])
0376:                                .graphLayoutCacheChanged(e);
0377:                    }
0378:                }
0379:            }
0380:
0381:            /**
0382:             * Return an array of all GraphLayoutCacheListener that were added to this
0383:             * model.
0384:             */
0385:            public GraphLayoutCacheListener[] getGraphLayoutCacheListeners() {
0386:                return (GraphLayoutCacheListener[]) listenerList
0387:                        .getListeners(GraphLayoutCacheListener.class);
0388:            }
0389:
0390:            //
0391:            // Accessors
0392:            //
0393:
0394:            /**
0395:             * Sets the factory that creates the cell views.
0396:             */
0397:            public void setFactory(CellViewFactory factory) {
0398:                this .factory = factory;
0399:            }
0400:
0401:            /**
0402:             * Returns the factory that was passed to the constructor.
0403:             */
0404:            public CellViewFactory getFactory() {
0405:                return factory;
0406:            }
0407:
0408:            /**
0409:             * Sets the current model.
0410:             */
0411:            public void setModel(GraphModel model) {
0412:                roots.clear();
0413:                mapping.clear();
0414:                hiddenMapping.clear();
0415:                visibleSet.clear();
0416:                graphModel = model;
0417:                if (!isPartial()) {
0418:                    Object[] cells = DefaultGraphModel.getRoots(getModel());
0419:                    CellView[] cellViews = getMapping(cells, true);
0420:                    insertViews(cellViews);
0421:                }
0422:                // Update PortView Cache and Notify Observers
0423:                updatePorts();
0424:                cellViewsChanged(getRoots());
0425:            }
0426:
0427:            /**
0428:             * @return Returns an unordered array of all visible cellviews.
0429:             */
0430:            public CellView[] getCellViews() {
0431:                Collection coll = mapping.values();
0432:                CellView[] result = new CellView[coll.size()];
0433:                coll.toArray(result);
0434:                return result;
0435:            }
0436:
0437:            /**
0438:             * Returns the bounding box for the specified cell views.
0439:             */
0440:            public static Rectangle2D getBounds(CellView[] views) {
0441:                if (views != null && views.length > 0) {
0442:                    Rectangle2D r = views[0].getBounds();
0443:                    Rectangle2D ret = (r != null) ? (Rectangle2D) r.clone()
0444:                            : null;
0445:                    for (int i = 1; i < views.length; i++) {
0446:                        r = views[i].getBounds();
0447:                        if (r != null) {
0448:                            if (ret == null)
0449:                                ret = (r != null) ? (Rectangle2D) r.clone()
0450:                                        : null;
0451:                            else
0452:                                Rectangle2D.union(ret, r, ret);
0453:                        }
0454:                    }
0455:                    return ret;
0456:                }
0457:                return null;
0458:            }
0459:
0460:            /**
0461:             * A helper method to return various arrays of cells that are visible in
0462:             * this cache. For example, to get all selected vertices in a graph, do
0463:             * <code>graph.getSelectionCells(graph.getGraphLayoutCache().getCells(false, true,
0464:             false, false));</code>
0465:             */
0466:            public Object[] getCells(boolean groups, boolean vertices,
0467:                    boolean ports, boolean edges) {
0468:                CellView[] views = getCellViews();
0469:                List result = new ArrayList(views.length);
0470:                GraphModel model = getModel();
0471:                for (int i = 0; i < views.length; i++) {
0472:                    Object cell = views[i].getCell();
0473:                    boolean isEdge = model.isEdge(cell);
0474:                    if ((ports || !model.isPort(cell))) {
0475:                        if (((((ports || vertices) && !isEdge) || (edges && isEdge)) && views[i]
0476:                                .isLeaf())
0477:                                || (groups && !views[i].isLeaf()))
0478:                            result.add(views[i].getCell());
0479:
0480:                    }
0481:                }
0482:                return result.toArray();
0483:            }
0484:
0485:            /**
0486:             * Returns a nested map of (cell, map) pairs that represent all attributes
0487:             * of all cell views in this view.
0488:             * 
0489:             * @see #getCellViews
0490:             */
0491:            public Map createNestedMap() {
0492:                CellView[] cellViews = getCellViews();
0493:                Map nested = new Hashtable();
0494:                for (int i = 0; i < cellViews.length; i++) {
0495:                    nested.put(cellViews[i].getCell(), new Hashtable(
0496:                            (Map) cellViews[i].getAllAttributes().clone()));
0497:                }
0498:                return nested;
0499:            }
0500:
0501:            /**
0502:             * @return Returns an unordered array of all hidden cellviews.
0503:             */
0504:            public CellView[] getHiddenCellViews() {
0505:                Collection coll = hiddenMapping.values();
0506:                CellView[] result = new CellView[coll.size()];
0507:                coll.toArray(result);
0508:                return result;
0509:            }
0510:
0511:            /**
0512:             * Remaps all existing views using the CellViewFactory
0513:             * and replaces the respective root views.
0514:             */
0515:            public synchronized void reload() {
0516:                List newRoots = new ArrayList();
0517:                Map oldMapping = new Hashtable(mapping);
0518:                mapping.clear();
0519:                Iterator it = oldMapping.keySet().iterator();
0520:                Set rootsSet = new HashSet(roots);
0521:                while (it.hasNext()) {
0522:                    Object cell = it.next();
0523:                    CellView oldView = (CellView) oldMapping.get(cell);
0524:                    CellView newView = getMapping(cell, true);
0525:                    newView.changeAttributes(this , oldView.getAttributes());
0526:                    // newView.refresh(getModel(), this, false);
0527:                    if (rootsSet.contains(oldView))
0528:                        newRoots.add(newView);
0529:                }
0530:                // replace hidden
0531:                hiddenMapping.clear();
0532:                roots = newRoots;
0533:            }
0534:
0535:            /**
0536:             * Returns the current model.
0537:             */
0538:            public GraphModel getModel() {
0539:                return graphModel;
0540:            }
0541:
0542:            /**
0543:             * Returns the roots of the view.
0544:             */
0545:            public CellView[] getRoots() {
0546:                CellView[] views = new CellView[roots.size()];
0547:                roots.toArray(views);
0548:                return views;
0549:            }
0550:
0551:            /**
0552:             * Return all root cells that intersect the given rectangle.
0553:             */
0554:            public CellView[] getRoots(Rectangle2D clip) {
0555:                java.util.List result = new ArrayList();
0556:                CellView[] views = getRoots();
0557:                for (int i = 0; i < views.length; i++)
0558:                    if (views[i].getBounds().intersects(clip))
0559:                        result.add(views[i]);
0560:                views = new CellView[result.size()];
0561:                result.toArray(views);
0562:                return views;
0563:            }
0564:
0565:            /**
0566:             * Returns a an array with the visible cells in <code>cells</code>.
0567:             */
0568:            public Object[] getVisibleCells(Object[] cells) {
0569:                if (cells != null) {
0570:                    List result = new ArrayList(cells.length);
0571:                    for (int i = 0; i < cells.length; i++)
0572:                        if (isVisible(cells[i]))
0573:                            result.add(cells[i]);
0574:                    return result.toArray();
0575:                }
0576:                return null;
0577:            }
0578:
0579:            /**
0580:             * Returns the ports of the view.
0581:             */
0582:            public PortView[] getPorts() {
0583:                return ports;
0584:            }
0585:
0586:            /**
0587:             * Updates the cached array of ports.
0588:             */
0589:            protected void updatePorts() {
0590:                Object[] roots = DefaultGraphModel.getRoots(graphModel);
0591:                List list = DefaultGraphModel.getDescendants(graphModel, roots);
0592:                if (list != null) {
0593:                    ArrayList result = new ArrayList();
0594:                    Iterator it = list.iterator();
0595:                    while (it.hasNext()) {
0596:                        Object cell = it.next();
0597:                        if (graphModel.isPort(cell)) {
0598:                            CellView portView = getMapping(cell, false);
0599:                            if (portView != null) {
0600:                                result.add(portView);
0601:                                portView.refresh(this , this , false);
0602:                            }
0603:                        }
0604:                    }
0605:                    ports = new PortView[result.size()];
0606:                    result.toArray(ports);
0607:                }
0608:            }
0609:
0610:            public void refresh(CellView[] views, boolean create) {
0611:                if (views != null)
0612:                    for (int i = 0; i < views.length; i++)
0613:                        refresh(views[i], create);
0614:            }
0615:
0616:            public void refresh(CellView view, boolean create) {
0617:                if (view != null) {
0618:                    view.refresh(this , this , create);
0619:                    CellView[] children = view.getChildViews();
0620:                    for (int i = 0; i < children.length; i++)
0621:                        refresh(children[i], create);
0622:                }
0623:            }
0624:
0625:            public void update(CellView[] views) {
0626:                if (views != null)
0627:                    for (int i = 0; i < views.length; i++)
0628:                        update(views[i]);
0629:            }
0630:
0631:            public void update(CellView view) {
0632:                if (view != null) {
0633:                    view.update(this );
0634:                    CellView[] children = view.getChildViews();
0635:                    for (int i = 0; i < children.length; i++)
0636:                        update(children[i]);
0637:                }
0638:            }
0639:
0640:            //
0641:            // Update View based on Model Change
0642:            //
0643:            /**
0644:             * Called from BasicGraphUI.ModelHandler to update the view based on the
0645:             * specified GraphModelEvent.
0646:             */
0647:            public void graphChanged(GraphModelEvent.GraphModelChange change) {
0648:                // Get Old Attributes From GraphModelChange (Undo) -- used to remap
0649:                // removed cells
0650:                CellView[] views = change.getViews(this );
0651:                if (views != null) {
0652:                    // Only ex-visible views are piggybacked
0653:                    for (int i = 0; i < views.length; i++)
0654:                        if (views[i] != null) {
0655:                            // Do not use putMapping because cells are invisible
0656:                            mapping.put(views[i].getCell(), views[i]);
0657:                        }
0658:                    // Ensure visible state
0659:                    setVisibleImpl(getCells(views), true);
0660:                }
0661:                // Fetch View Order Of Changed Cells (Before any changes)
0662:                Object[] changed = change.getChanged();
0663:                // Fetch Views to Insert before Removal (Special case: two step process,
0664:                // see setModel)
0665:                getMapping(change.getInserted(), true);
0666:                // Remove and Hide Roots
0667:                views = removeCells(change.getRemoved());
0668:                // Store Removed Attributes In GraphModelChange (Undo)
0669:                change.putViews(this , views);
0670:                // Insert New Roots
0671:                // insertViews(insertViews);
0672:                // Hide edges with invisible source or target
0673:                if (isPartial()) {
0674:                    // Then show
0675:                    showCellsForChange(change);
0676:                    // First hide
0677:                    hideCellsForChange(change);
0678:                }
0679:                // Refresh Changed Cells
0680:                if (changed != null && changed.length > 0) {
0681:                    // Restore All Cells in Model Order (Replace Roots)
0682:                    for (int i = 0; i < changed.length; i++) {
0683:                        CellView view = getMapping(changed[i], false);
0684:                        if (view != null) {
0685:                            view.refresh(this , this , true);
0686:                            // Update child edges in groups (routing)
0687:                            update(view);
0688:                        }
0689:                    }
0690:                }
0691:                reloadRoots();
0692:                // Refresh Context of Changed Cells (=Connected Edges)
0693:                refresh(getMapping(getContext(change), false), false);
0694:                updatePorts();
0695:            }
0696:
0697:            /**
0698:             * Completely reloads all roots from the model in the order returned by
0699:             * DefaultGraphModel.getAll. This uses the current visibleSet and mapping to
0700:             * fetch the cell views for the cells.
0701:             */
0702:            protected void reloadRoots() {
0703:                // Reorder roots
0704:                Object[] orderedCells = DefaultGraphModel.getAll(graphModel);
0705:                List newRoots = new ArrayList();
0706:                for (int i = 0; i < orderedCells.length; i++) {
0707:                    CellView view = getMapping(orderedCells[i], false);
0708:                    if (view != null) {
0709:                        view.refresh(this , this , true);
0710:                        if (view.getParentView() == null) {
0711:                            newRoots.add(view);
0712:                        }
0713:                    }
0714:                }
0715:                roots = newRoots;
0716:            }
0717:
0718:            /**
0719:             * Hook for subclassers to augment the context for a graphChange. This means
0720:             * you can add additional cells that should be refreshed on a special change
0721:             * event. eg. parallel edges when one is removed or added.
0722:             */
0723:            protected Object[] getContext(
0724:                    GraphModelEvent.GraphModelChange change) {
0725:                return change.getContext();
0726:            }
0727:
0728:            protected void hideCellsForChange(
0729:                    GraphModelEvent.GraphModelChange change) {
0730:                // Hide visible edges between invisible vertices
0731:                // 1. Remove attached edges of removed cells
0732:                // 2. Remove edges who's source or target has changed to
0733:                // invisible.
0734:                Object[] tmp = change.getRemoved();
0735:                Set removed = new HashSet();
0736:                if (tmp != null)
0737:                    for (int i = 0; i < tmp.length; i++)
0738:                        removed.add(tmp[i]);
0739:                if (hidesDanglingConnections || hidesExistingConnections) {
0740:                    Object[] changed = change.getChanged();
0741:                    for (int i = 0; i < changed.length; i++) {
0742:                        CellView view = getMapping(changed[i], false);
0743:                        if (view instanceof  EdgeView) {
0744:                            EdgeView edge = (EdgeView) view;
0745:                            Object oldSource = (edge.getSource() == null) ? null
0746:                                    : edge.getSource().getCell();
0747:                            Object oldTarget = (edge.getTarget() == null) ? null
0748:                                    : edge.getTarget().getCell();
0749:                            Object newSource = graphModel.getSource(changed[i]);
0750:                            Object newTarget = graphModel.getTarget(changed[i]);
0751:                            boolean hideExisting = (hidesExistingConnections && ((newSource != null && !hasVisibleParent(
0752:                                    newSource, null)) || (newTarget != null && !hasVisibleParent(
0753:                                    newTarget, null))));
0754:                            if ((hidesDanglingConnections && (removed
0755:                                    .contains(oldSource) || removed
0756:                                    .contains(oldTarget)))
0757:                                    || hideExisting) {
0758:                                setVisibleImpl(new Object[] { changed[i] },
0759:                                        false);
0760:                            }
0761:                        }
0762:                    }
0763:                }
0764:            }
0765:
0766:            /**
0767:             * Checks if the port or one of its parents is visible.
0768:             */
0769:            protected boolean hasVisibleParent(Object cell, Set invisible) {
0770:                boolean isVisible = false;
0771:                do {
0772:                    isVisible = (invisible == null || !invisible.contains(cell)) ? isVisible(cell)
0773:                            : false;
0774:                    cell = getModel().getParent(cell);
0775:                } while (cell != null && !isVisible);
0776:                return isVisible;
0777:            }
0778:
0779:            protected void showCellsForChange(
0780:                    GraphModelEvent.GraphModelChange change) {
0781:                Object[] inserted = change.getInserted();
0782:                if (inserted != null && showsInsertedConnections) {
0783:                    for (int i = 0; i < inserted.length; i++) {
0784:                        if (!isVisible(inserted[i])) {
0785:                            Object source = graphModel.getSource(inserted[i]);
0786:                            Object target = graphModel.getTarget(inserted[i]);
0787:                            if ((source != null || target != null)
0788:                                    && (isVisible(source) && isVisible(target)))
0789:                                setVisibleImpl(new Object[] { inserted[i] },
0790:                                        true);
0791:                        }
0792:                    }
0793:                }
0794:                if (change.getConnectionSet() != null) {
0795:                    Set changedSet = change.getConnectionSet()
0796:                            .getChangedEdges();
0797:                    if (changedSet != null && showsChangedConnections) {
0798:                        Object[] changed = changedSet.toArray();
0799:                        for (int i = 0; i < changed.length; i++) {
0800:                            if (!isVisible(changed[i])) {
0801:                                Object source = graphModel
0802:                                        .getSource(changed[i]);
0803:                                Object target = graphModel
0804:                                        .getTarget(changed[i]);
0805:                                if ((source != null || target != null)
0806:                                        && (isVisible(source) && isVisible(target))
0807:                                        && !isVisible(changed[i]))
0808:                                    setVisibleImpl(new Object[] { changed[i] },
0809:                                            true);
0810:                            }
0811:                        }
0812:                    }
0813:                }
0814:            }
0815:
0816:            /**
0817:             * Adds the specified model root cells to the view. Do not add a view that
0818:             * is already in roots.
0819:             */
0820:            public void insertViews(CellView[] views) {
0821:                if (views != null) {
0822:                    refresh(views, true);
0823:                    for (int i = 0; i < views.length; i++) {
0824:                        if (views[i] != null
0825:                                && getMapping(views[i].getCell(), false) != null) {
0826:                            CellView parentView = views[i].getParentView();
0827:                            Object parent = (parentView != null) ? parentView
0828:                                    .getCell() : null;
0829:                            if (!graphModel.isPort(views[i].getCell())
0830:                                    && parent == null) {
0831:                                roots.add(views[i]);
0832:                            }
0833:                        }
0834:                    }
0835:                }
0836:            }
0837:
0838:            /**
0839:             * Removes the specified model root cells from the view by removing the
0840:             * mapping between the cell and its view and makes the cells invisible.
0841:             */
0842:            public CellView[] removeCells(Object[] cells) {
0843:                if (cells != null && cells.length > 0) {
0844:                    CellView[] views = new CellView[cells.length];
0845:                    // Store views to be removed from roots in an intermediate
0846:                    // set for performance reasons
0847:                    Set removedRoots = null;
0848:                    for (int i = 0; i < cells.length; i++) {
0849:                        views[i] = removeMapping(cells[i]);
0850:                        if (views[i] != null) {
0851:                            views[i].removeFromParent();
0852:                            if (removedRoots == null) {
0853:                                removedRoots = new HashSet();
0854:                            }
0855:                            removedRoots.add(views[i]);
0856:                            visibleSet.remove(views[i].getCell());
0857:                        }
0858:                    }
0859:                    if (removedRoots != null && removedRoots.size() > 0) {
0860:                        // If any roots have been removed, reform the roots
0861:                        // lists appropriately, keeping the order the same
0862:                        int newRootsSize = roots.size() - removedRoots.size();
0863:                        if (newRootsSize < 8) {
0864:                            newRootsSize = 8;
0865:                        }
0866:                        List newRoots = new ArrayList(newRootsSize);
0867:                        Iterator iter = roots.iterator();
0868:                        while (iter.hasNext()) {
0869:                            Object cell = iter.next();
0870:                            if (!removedRoots.contains(cell)) {
0871:                                newRoots.add(cell);
0872:                            }
0873:                        }
0874:                        roots = newRoots;
0875:                    }
0876:                    return views;
0877:                }
0878:                return null;
0879:            }
0880:
0881:            //
0882:            // Cell Mapping
0883:            //
0884:            /**
0885:             * Takes an array of views and returns the array of the corresponding cells
0886:             * by using <code>getCell</code> for each view.
0887:             */
0888:            public Object[] getCells(CellView[] views) {
0889:                if (views != null) {
0890:                    Object[] cells = new Object[views.length];
0891:                    for (int i = 0; i < views.length; i++)
0892:                        if (views[i] != null)
0893:                            cells[i] = views[i].getCell();
0894:                    return cells;
0895:                }
0896:                return null;
0897:            }
0898:
0899:            /**
0900:             * Returns the view for the specified cell. If create is true and no view is
0901:             * found then a view is created using createView(Object).
0902:             */
0903:            public CellView getMapping(Object cell, boolean create) {
0904:                if (cell == null)
0905:                    return null;
0906:                CellView view = (CellView) mapping.get(cell);
0907:                if (view == null && create && isVisible(cell)) {
0908:                    view = (CellView) hiddenMapping.get(cell);
0909:                    if (view != null) {
0910:                        putMapping(cell, view);
0911:                        hiddenMapping.remove(cell);
0912:                    } else {
0913:                        view = factory.createView(graphModel, cell);
0914:                        putMapping(cell, view);
0915:                        view.refresh(this , this , true); // Create Dependent
0916:                        // Views
0917:                        view.update(this );
0918:                    }
0919:                }
0920:                return view;
0921:            }
0922:
0923:            /**
0924:             * Returns the views for the specified array of cells without creating these
0925:             * views on the fly.
0926:             */
0927:            public CellView[] getMapping(Object[] cells) {
0928:                return getMapping(cells, false);
0929:            }
0930:
0931:            /**
0932:             * Returns the views for the specified array of cells. Returned array may
0933:             * contain null pointers if the respective cell is not mapped in this view
0934:             * and <code>create</code> is <code>false</code>.
0935:             */
0936:            public CellView[] getMapping(Object[] cells, boolean create) {
0937:                if (cells != null) {
0938:                    CellView[] result = new CellView[cells.length];
0939:                    for (int i = 0; i < cells.length; i++)
0940:                        result[i] = getMapping(cells[i], create);
0941:                    return result;
0942:                }
0943:                return null;
0944:            }
0945:
0946:            /**
0947:             * Associates the specified model cell with the specified view.
0948:             */
0949:            public void putMapping(Object cell, CellView view) {
0950:                if (cell != null && view != null)
0951:                    mapping.put(cell, view);
0952:            }
0953:
0954:            /**
0955:             * Removes the associaten for the specified model cell and returns the view
0956:             * that was previously associated with the cell. Updates the portlist if
0957:             * necessary.
0958:             */
0959:            public CellView removeMapping(Object cell) {
0960:                if (cell != null) {
0961:                    CellView view = (CellView) mapping.remove(cell);
0962:                    return view;
0963:                }
0964:                return null;
0965:            }
0966:
0967:            //
0968:            // Partial View
0969:            //
0970:            // Null is always visible!
0971:            public boolean isVisible(Object cell) {
0972:                return !isPartial() || visibleSet.contains(cell)
0973:                        || cell == null;
0974:            }
0975:
0976:            public Set getVisibleSet() {
0977:                return new HashSet(visibleSet);
0978:            }
0979:
0980:            public void setVisibleSet(Set visible) {
0981:                visibleSet = visible;
0982:            }
0983:
0984:            /**
0985:             * Makes the specified cell visible or invisible depending on the flag
0986:             * passed in. Note the cell really is a cell, not a cell view.
0987:             * 
0988:             * @param cell
0989:             *            the cell whose visibility is to be changed
0990:             * @param visible
0991:             *            <code>true</code> if cell is to be made visible
0992:             */
0993:            public void setVisible(Object cell, boolean visible) {
0994:                setVisible(new Object[] { cell }, visible);
0995:            }
0996:
0997:            /**
0998:             * Makes the specified cells visible or invisible depending on the flag
0999:             * passed in. Note the cells really are cells, not cell views.
1000:             * 
1001:             * @param cells
1002:             *            the cells whose visibility is to be changed
1003:             * @param visible
1004:             *            <code>true</code> if the cells are to be made visible
1005:             */
1006:            public void setVisible(Object[] cells, boolean visible) {
1007:                if (visible)
1008:                    setVisible(cells, null);
1009:                else
1010:                    setVisible(null, cells);
1011:            }
1012:
1013:            /**
1014:             * Changes the visibility state of the cells passed in. Note that the arrays
1015:             * must contain cells, not cell views.
1016:             * 
1017:             * @param visible
1018:             *            cells to be made visible
1019:             * @param invisible
1020:             *            cells to be made invisible
1021:             */
1022:            public void setVisible(Object[] visible, Object[] invisible) {
1023:                setVisible(visible, invisible, null);
1024:            }
1025:
1026:            /**
1027:             * Changes the visibility state of the cells passed in. Note that the arrays
1028:             * must contain cells, not cell views.
1029:             * 
1030:             * @param visible
1031:             *            cells to be made visible
1032:             * @param invisible
1033:             *            cells to be made invisible
1034:             * @param cs
1035:             *            a <code>ConnectionSet</code> describing the new state of
1036:             *            edge connections in the graph
1037:             */
1038:            public void setVisible(Object[] visible, Object[] invisible,
1039:                    ConnectionSet cs) {
1040:                GraphLayoutCacheEdit edit = new GraphLayoutCacheEdit(null,
1041:                        null, visible, invisible);
1042:                edit.end();
1043:                graphModel.edit(null, cs, null, new UndoableEdit[] { edit });
1044:            }
1045:
1046:            // This is used to augment the array passed to the setVisible method.
1047:            protected Object[] addVisibleDependencies(Object[] cells,
1048:                    boolean visible) {
1049:                if (cells != null) {
1050:                    if (visible) {
1051:                        // Make ports and source and target vertex visible
1052:                        Set all = new HashSet();
1053:                        for (int i = 0; i < cells.length; i++) {
1054:                            all.add(cells[i]);
1055:                            // Add ports
1056:                            all.addAll(getPorts(cells[i]));
1057:                            // Add source vertex and ports
1058:                            Collection coll = getParentPorts(graphModel
1059:                                    .getSource(cells[i]));
1060:                            if (coll != null)
1061:                                all.addAll(coll);
1062:                            // Add target vertex and ports
1063:                            coll = getParentPorts(graphModel
1064:                                    .getTarget(cells[i]));
1065:                            if (coll != null)
1066:                                all.addAll(coll);
1067:                        }
1068:                        if (showsExistingConnections) {
1069:                            Set tmp = DefaultGraphModel.getEdges(getModel(),
1070:                                    cells);
1071:                            Iterator it = tmp.iterator();
1072:                            while (it.hasNext()) {
1073:                                Object obj = it.next();
1074:                                Object source = graphModel.getSource(obj);
1075:                                Object target = graphModel.getTarget(obj);
1076:                                if ((isVisible(source) || all.contains(source))
1077:                                        && (isVisible(target) || all
1078:                                                .contains(target)))
1079:                                    all.add(obj);
1080:                            }
1081:                        }
1082:                        all.removeAll(visibleSet);
1083:                        all.remove(null);
1084:                        return all.toArray();
1085:                    } else {
1086:                        if (hidesExistingConnections) {
1087:                            Set all = new HashSet();
1088:                            for (int i = 0; i < cells.length; i++) {
1089:                                all.addAll(getPorts(cells[i]));
1090:                                all.add(cells[i]);
1091:                            }
1092:                            Iterator it = DefaultGraphModel.getEdges(
1093:                                    graphModel, cells).iterator();
1094:                            while (it.hasNext()) {
1095:                                Object edge = it.next();
1096:                                Object newSource = graphModel.getSource(edge);
1097:                                Object newTarget = graphModel.getTarget(edge);
1098:                                // Note: At this time the cells are not yet hidden
1099:                                if ((newSource != null && !hasVisibleParent(
1100:                                        newSource, all))
1101:                                        || (newTarget != null && !hasVisibleParent(
1102:                                                newTarget, all))) {
1103:                                    all.add(edge);
1104:                                }
1105:                            }
1106:                            all.remove(null);
1107:                            return all.toArray();
1108:                        }
1109:                    }
1110:                }
1111:                return cells;
1112:            }
1113:
1114:            /**
1115:             * The actual implementation of changing cells' visibility state. This
1116:             * method does not deal with creating the undo or updating the
1117:             * GraphLayoutCache correctly. The <code>setVisible</code> methods in this
1118:             * class are intended to be the main public way to change visiblilty.
1119:             * However, if you do not require the undo to be formed, this method is much
1120:             * quicker, just note that you must call <code>updatePorts</code> if this
1121:             * method returns true.
1122:             * 
1123:             * @param cells
1124:             * @param visible
1125:             * @return whether or not the ports needed updating in the calling method
1126:             */
1127:            public boolean setVisibleImpl(Object[] cells, boolean visible) {
1128:                cells = addVisibleDependencies(cells, visible);
1129:                if (cells != null && isPartial()) {
1130:                    boolean updatePorts = false;
1131:                    // Update Visible Set
1132:                    CellView[] views = new CellView[cells.length];
1133:                    if (!visible) {
1134:                        views = removeCells(cells);
1135:                    }
1136:                    // Set used for model roots contains call for performance
1137:                    Set modelRoots = null;
1138:                    for (int i = 0; i < cells.length; i++) {
1139:                        if (cells[i] != null) {
1140:                            if (visible) {
1141:                                visibleSet.add(cells[i]);
1142:                                views[i] = getMapping(cells[i], true);
1143:                            } else {
1144:                                if (views[i] != null) {
1145:                                    if (modelRoots == null) {
1146:                                        modelRoots = new HashSet(
1147:                                                DefaultGraphModel
1148:                                                        .getRootsAsCollection(getModel()));
1149:                                    }
1150:                                    if (modelRoots.contains(views[i].getCell())
1151:                                            && remembersCellViews) {
1152:                                        hiddenMapping.put(views[i].getCell(),
1153:                                                views[i]);
1154:                                    }
1155:                                    updatePorts = true;
1156:                                }
1157:                            }
1158:                        }
1159:                    }
1160:                    // Make Cell Views Visible (if not already in place)
1161:                    if (visible) {
1162:                        Set parentSet = new HashSet();
1163:                        Set removedRoots = null;
1164:                        for (int i = 0; i < views.length; i++) {
1165:                            if (views[i] != null) {
1166:                                CellView view = views[i];
1167:                                // Remove all children from roots
1168:                                CellView[] children = AbstractCellView
1169:                                        .getDescendantViews(new CellView[] { view });
1170:                                for (int j = 0; j < children.length; j++) {
1171:                                    if (removedRoots == null) {
1172:                                        removedRoots = new HashSet();
1173:                                    }
1174:                                    removedRoots.add(children[j]);
1175:                                }
1176:                                view.refresh(this , this , false);
1177:                                // Link cellView into graphLayoutCache
1178:                                CellView parentView = view.getParentView();
1179:                                if (parentView != null)
1180:                                    parentSet.add(parentView);
1181:                                updatePorts = true;
1182:                            }
1183:                        }
1184:                        if (removedRoots != null && removedRoots.size() > 0) {
1185:                            // If any roots have been removed, reform the roots
1186:                            // lists appropriately, keeping the order the same
1187:                            List newRoots = new ArrayList();
1188:                            Iterator iter = roots.iterator();
1189:                            while (iter.hasNext()) {
1190:                                Object cell = iter.next();
1191:                                if (!removedRoots.contains(cell)) {
1192:                                    newRoots.add(cell);
1193:                                }
1194:                            }
1195:                            roots = newRoots;
1196:                        }
1197:
1198:                        CellView[] parentViews = new CellView[parentSet.size()];
1199:                        parentSet.toArray(parentViews);
1200:                        refresh(parentViews, true);
1201:                    }
1202:                    return updatePorts;
1203:                }
1204:                return false;
1205:            }
1206:
1207:            protected Collection getParentPorts(Object cell) {
1208:                // does nothing if a parent is already visible
1209:                Object parent = graphModel.getParent(cell);
1210:                while (parent != null) {
1211:                    if (isVisible(parent))
1212:                        return null;
1213:                    parent = graphModel.getParent(parent);
1214:                }
1215:
1216:                // Else returns the parent and all ports
1217:                parent = graphModel.getParent(cell);
1218:                Collection collection = getPorts(parent);
1219:                collection.add(parent);
1220:                return collection;
1221:            }
1222:
1223:            protected Collection getPorts(Object cell) {
1224:                LinkedList list = new LinkedList();
1225:                for (int i = 0; i < graphModel.getChildCount(cell); i++) {
1226:                    Object child = graphModel.getChild(cell, i);
1227:                    if (graphModel.isPort(child))
1228:                        list.add(child);
1229:                }
1230:                return list;
1231:            }
1232:
1233:            //
1234:            // Change Support
1235:            //
1236:            public boolean isPartial() {
1237:                return partial;
1238:            }
1239:
1240:            /**
1241:             * Required for XML persistence
1242:             * 
1243:             * @return whether or not the cache is partial
1244:             */
1245:            public boolean getPartial() {
1246:                return isPartial();
1247:            }
1248:
1249:            /**
1250:             * Messaged when the user has altered the value for the item identified by
1251:             * cell to newValue. If newValue signifies a truly new value the model
1252:             * should post a graphCellsChanged event. This calls
1253:             * augmentNestedMapForValueChange.
1254:             */
1255:            public void valueForCellChanged(Object cell, Object newValue) {
1256:                Map nested = null;
1257:                if (isAutoSizeOnValueChange()) {
1258:                    CellView view = getMapping(cell, false);
1259:                    if (view != null) {
1260:                        AttributeMap attrs = view.getAllAttributes();
1261:                        Rectangle2D bounds = GraphConstants.getBounds(attrs);
1262:                        Rectangle2D dummyBounds = null;
1263:                        // Force the model to store the old bounds
1264:                        if (bounds != null) {
1265:                            dummyBounds = attrs.createRect(bounds.getX(),
1266:                                    bounds.getY(), 0, 0);
1267:                        } else {
1268:                            dummyBounds = attrs.createRect(0, 0, 0, 0);
1269:                        }
1270:                        nested = GraphConstants.createAttributes(
1271:                                new Object[] { cell }, new Object[] {
1272:                                        GraphConstants.RESIZE,
1273:                                        GraphConstants.BOUNDS }, new Object[] {
1274:                                        Boolean.TRUE, dummyBounds });
1275:                    }
1276:                } else {
1277:                    nested = new Hashtable();
1278:                    nested.put(cell, new Hashtable());
1279:                }
1280:                augmentNestedMapForValueChange(nested, cell, newValue);
1281:                edit(nested, null, null, null);
1282:            }
1283:
1284:            /**
1285:             * Hook for subclassers to add more stuff for value changes. Currently this
1286:             * adds the new value to the change.
1287:             */
1288:            protected void augmentNestedMapForValueChange(Map nested,
1289:                    Object cell, Object newValue) {
1290:                Map attrs = (Map) nested.get(cell);
1291:                if (attrs != null)
1292:                    GraphConstants.setValue(attrs, newValue);
1293:            }
1294:
1295:            /**
1296:             * Inserts the <code>cells</code> and connections into the model, and
1297:             * absorbs the local attributes. This implementation sets the inserted cells
1298:             * visible and selects the new roots depending on graph.selectNewCells.
1299:             */
1300:            public void insert(Object[] roots, Map attributes,
1301:                    ConnectionSet cs, ParentMap pm, UndoableEdit[] e) {
1302:                Object[] visible = null;
1303:                if (isPartial() && showsInsertedCells) {
1304:                    List tmp = DefaultGraphModel.getDescendants(graphModel,
1305:                            roots);
1306:                    tmp.removeAll(visibleSet);
1307:                    if (!tmp.isEmpty())
1308:                        visible = tmp.toArray();
1309:                }
1310:                // Absorb local attributes
1311:                GraphLayoutCacheEdit edit = createLocalEdit(roots, attributes,
1312:                        visible, null);
1313:                if (edit != null)
1314:                    e = augment(e, edit);
1315:                graphModel.insert(roots, attributes, cs, pm, e);
1316:            }
1317:
1318:            /**
1319:             * Inserts the cloned cells from the clone map and clones the passed-in
1320:             * arguments according to the clone map before insertion and returns the
1321:             * clones in order of the cells. This example shows how to clone the current
1322:             * selection and get a reference to the clones:
1323:             * 
1324:             * <pre>
1325:             * Object[] cells = graph.getDescendants(graph.order(graph.getSelectionCells()));
1326:             * ConnectionSet cs = ConnectionSet.create(graphModel, cells, false);
1327:             * ParentMap pm = ParentMap.create(graphModel, cells, false, true);
1328:             * cells = graphLayoutCache.insertClones(cells, graph.cloneCells(cells),
1329:             * 		attributes, cs, pm, 0, 0);
1330:             * </pre>
1331:             */
1332:            public Object[] insertClones(Object[] cells, Map clones,
1333:                    Map nested, ConnectionSet cs, ParentMap pm, double dx,
1334:                    double dy) {
1335:                if (cells != null) {
1336:                    if (cs != null)
1337:                        cs = cs.clone(clones);
1338:                    if (pm != null)
1339:                        pm = pm.clone(clones);
1340:                    if (nested != null) {
1341:                        nested = GraphConstants.replaceKeys(clones, nested);
1342:                        AttributeMap.translate(nested.values(), dx, dy);
1343:                    }
1344:                    // Replace cells in order
1345:                    Object[] newCells = new Object[cells.length];
1346:                    for (int i = 0; i < cells.length; i++)
1347:                        newCells[i] = clones.get(cells[i]);
1348:                    // Insert into cache/model
1349:                    insert(newCells, nested, cs, pm, null);
1350:                    return newCells;
1351:                }
1352:                return null;
1353:            }
1354:
1355:            /**
1356:             * Inserts the specified vertex into the graph model. This method does in
1357:             * fact nothing, it calls insert edge with the vertex and the source and
1358:             * target port set to null. This example shows how to add a vertex with a
1359:             * port and a black border:
1360:             * 
1361:             * <pre>
1362:             * DefaultGraphCell vertex = new DefaultGraphCell(&quot;Hello, world!&quot;);
1363:             * Map attrs = vertex.getAttributes();
1364:             * GraphConstants.setOpaque(attrs, false);
1365:             * GraphConstants.setBorderColor(attrs, Color.black);
1366:             * DefaultPort port = new DefaultPort();
1367:             * vertex.add(port);
1368:             * port.setParent(vertex);
1369:             * graph.getGraphLayoutCache().insert(vertex);
1370:             * </pre>
1371:             * 
1372:             * @param cell
1373:             *            inserts the specified cell in the cache
1374:             */
1375:            public void insert(Object cell) {
1376:                insert(new Object[] { cell });
1377:            }
1378:
1379:            /**
1380:             * Inserts the specified edge into the graph model. This method does in fact
1381:             * nothing, it calls insert with a default connection set.
1382:             * 
1383:             * @param edge
1384:             *            the edge to be inserted
1385:             * @param source
1386:             *            the source port this edge is connected to
1387:             * @param target
1388:             *            the target port this edge is connected to
1389:             */
1390:            public void insertEdge(Object edge, Object source, Object target) {
1391:                insert(new Object[] { edge }, new Hashtable(),
1392:                        new ConnectionSet(edge, source, target),
1393:                        new ParentMap());
1394:            }
1395:
1396:            /**
1397:             * Inserts the specified cells into the graph model. This method is a
1398:             * general implementation of cell insertion. If the source and target port
1399:             * are null, then no connection set is created. The method uses the
1400:             * attributes from the specified edge and the egdge's children to construct
1401:             * the insert call. This example shows how to insert an edge with a special
1402:             * arrow between two known vertices:
1403:             * 
1404:             * <pre>
1405:             * Object source = graph.getDefaultPortForCell(sourceVertex).getCell();
1406:             * Object target = graph.getDefaultPortForCell(targetVertex).getCell();
1407:             * DefaultEdge edge = new DefaultEdge(&quot;Hello, world!&quot;);
1408:             * edge.setSource(source);
1409:             * edge.setTarget(target);
1410:             * Map attrs = edge.getAttributes();
1411:             * GraphConstants.setLineEnd(attrs, GraphConstants.ARROW_TECHNICAL);
1412:             * graph.getGraphLayoutCache().insert(edge);
1413:             * </pre>
1414:             */
1415:            public void insert(Object[] cells) {
1416:                insert(cells, new Hashtable(), new ConnectionSet(),
1417:                        new ParentMap());
1418:            }
1419:
1420:            /**
1421:             * Variant of the insert method that allows to pass a default connection set
1422:             * and parent map and nested map.
1423:             */
1424:            public void insert(Object[] cells, Map nested, ConnectionSet cs,
1425:                    ParentMap pm) {
1426:                if (cells != null) {
1427:                    if (nested == null)
1428:                        nested = new Hashtable();
1429:                    if (cs == null)
1430:                        cs = new ConnectionSet();
1431:                    if (pm == null)
1432:                        pm = new ParentMap();
1433:                    for (int i = 0; i < cells.length; i++) {
1434:                        // Using the children of the vertex we construct the parent map.
1435:                        int childCount = getModel().getChildCount(cells[i]);
1436:                        for (int j = 0; j < childCount; j++) {
1437:                            Object child = getModel().getChild(cells[i], j);
1438:                            pm.addEntry(child, cells[i]);
1439:
1440:                            // And add their attributes to the nested map
1441:                            AttributeMap attrs = getModel()
1442:                                    .getAttributes(child);
1443:                            if (attrs != null)
1444:                                nested.put(child, attrs);
1445:                        }
1446:
1447:                        // A nested map with the vertex as key
1448:                        // and its attributes as the value
1449:                        // is required for the model.
1450:                        Map attrsTmp = (Map) nested.get(cells[i]);
1451:                        Map attrs = getModel().getAttributes(cells[i]);
1452:                        if (attrsTmp != null)
1453:                            attrs.putAll(attrsTmp);
1454:                        nested.put(cells[i], attrs);
1455:
1456:                        // Check if we have parameters for a connection set.
1457:                        Object sourcePort = getModel().getSource(cells[i]);
1458:                        if (sourcePort != null)
1459:                            cs.connect(cells[i], sourcePort, true);
1460:
1461:                        Object targetPort = getModel().getTarget(cells[i]);
1462:                        if (targetPort != null)
1463:                            cs.connect(cells[i], targetPort, false);
1464:                    }
1465:                    // Create an array with the parent and its children.
1466:                    cells = DefaultGraphModel.getDescendants(getModel(), cells)
1467:                            .toArray();
1468:
1469:                    // Finally call the insert method on the parent class.
1470:                    insert(cells, nested, cs, pm, null);
1471:                }
1472:            }
1473:
1474:            /**
1475:             * Inserts the specified cell as a parent of children. Note: All cells that
1476:             * are not yet in the model will be inserted. This example shows how to
1477:             * group the current selection and pass the group default bounds in case it
1478:             * is later collapsed:
1479:             * 
1480:             * <pre>
1481:             * DefaultGraphCell group = new DefaultGraphCell(&quot;Hello, world!&quot;);
1482:             * Object[] cells = DefaultGraphModel.order(graph.getModel(), graph
1483:             * 		.getSelectionCells());
1484:             * Rectangle2D bounds = graph.getCellBounds(cells);
1485:             * if (bounds != null) {
1486:             * 	bounds = new Rectangle2D.Double(bounds.getX() + bounds.getWidth() / 4,
1487:             * 			bounds.getY() + bounds.getHeight() / 4, bounds.getWidth() / 2,
1488:             * 			bounds.getHeight() / 2);
1489:             * 	GraphConstants.setBounds(group.getAttributes(), bounds);
1490:             * }
1491:             * graph.getGraphLayoutCache().insertGroup(group, cells);
1492:             * </pre>
1493:             */
1494:            public void insertGroup(Object group, Object[] children) {
1495:                if (group != null && children != null && children.length > 0) {
1496:                    Map nested = new Hashtable();
1497:
1498:                    // List to store all children that are not in the model
1499:                    List newCells = new ArrayList(children.length + 1);
1500:
1501:                    // Plus the group cell at pos 0
1502:                    if (!getModel().contains(group)) {
1503:                        newCells.add(group);
1504:                    }
1505:
1506:                    // Create a parent map for the group and the children, and
1507:                    // store the children's attributes in the nested map.
1508:                    // Note: This implementation assumes that the children have
1509:                    // not yet been added to the group object. Therefore,
1510:                    // the insert method will only collect the group
1511:                    // attributes, but will ignore the child attributes.
1512:                    ParentMap pm = new ParentMap();
1513:                    for (int i = 0; i < children.length; i++) {
1514:                        pm.addEntry(children[i], group);
1515:                        if (!getModel().contains(children[i])) {
1516:                            newCells.add(children[i]);
1517:                            AttributeMap attrs = getModel().getAttributes(
1518:                                    children[i]);
1519:                            if (attrs != null)
1520:                                nested.put(children[i], attrs);
1521:                        }
1522:                    }
1523:                    if (newCells.isEmpty())
1524:                        edit(nested, null, pm, null);
1525:                    else
1526:                        insert(newCells.toArray(), nested, null, pm);
1527:                }
1528:            }
1529:
1530:            /**
1531:             * Removes <code>cells</code> from the model.
1532:             */
1533:            public void remove(Object[] cells) {
1534:                graphModel.remove(cells);
1535:            }
1536:
1537:            /**
1538:             * Removes cells from the model, including all children and connected edges
1539:             * if <code>children</code> or <code>edges</code> is true, respectively.
1540:             * 
1541:             * @param cells
1542:             *            The cells to remove.
1543:             * @param descendants
1544:             *            Whether to remove all descendants as well.
1545:             * @param edges
1546:             *            Whether to remove all connected edges as well.
1547:             */
1548:            public void remove(Object[] cells, boolean descendants,
1549:                    boolean edges) {
1550:                if (cells != null && cells.length > 0) {
1551:                    if (edges) {
1552:                        Object[] tmp = DefaultGraphModel.getEdges(getModel(),
1553:                                cells).toArray();
1554:                        Object[] newCells = new Object[cells.length
1555:                                + tmp.length];
1556:                        System.arraycopy(cells, 0, newCells, 0, cells.length);
1557:                        System.arraycopy(tmp, 0, newCells, cells.length,
1558:                                tmp.length);
1559:                        cells = newCells;
1560:                    }
1561:                    if (descendants)
1562:                        cells = DefaultGraphModel.getDescendants(getModel(),
1563:                                cells).toArray();
1564:                    remove(cells);
1565:                }
1566:            }
1567:
1568:            /**
1569:             * Hides the specified cells with all children if <code>descandants</code>
1570:             * is true.
1571:             */
1572:            public void hideCells(Object[] cells, boolean descandants) {
1573:                if (cells != null && cells.length > 0) {
1574:                    if (descandants)
1575:                        cells = DefaultGraphModel.getDescendants(getModel(),
1576:                                cells).toArray();
1577:                    setVisible(cells, false);
1578:                }
1579:            }
1580:
1581:            /**
1582:             * Shows the specified cells with all children if <code>descandants</code>
1583:             * is true.
1584:             */
1585:            public void showCells(Object[] cells, boolean descandants) {
1586:                if (cells != null && cells.length > 0) {
1587:                    if (descandants)
1588:                        cells = DefaultGraphModel.getDescendants(getModel(),
1589:                                cells).toArray();
1590:                    setVisible(cells, true);
1591:                }
1592:            }
1593:
1594:            /**
1595:             * Ungroups all groups in cells and returns the children that are not ports.
1596:             * Note: This replaces the parents with their group cells in the group
1597:             * structure.
1598:             */
1599:            public Object[] ungroup(Object[] cells) {
1600:                if (cells != null && cells.length > 0) {
1601:                    ArrayList toRemove = new ArrayList();
1602:                    ArrayList children = new ArrayList();
1603:                    boolean groupExists = false;
1604:                    for (int i = 0; i < cells.length; i++) {
1605:                        boolean childExists = false;
1606:                        ArrayList tempPortList = new ArrayList();
1607:                        for (int j = 0; j < getModel().getChildCount(cells[i]); j++) {
1608:                            Object child = getModel().getChild(cells[i], j);
1609:                            if (!getModel().isPort(child)) {
1610:                                children.add(child);
1611:                                childExists = true;
1612:                            } else {
1613:                                tempPortList.add(child);
1614:                            }
1615:                        }
1616:                        if (childExists) {
1617:                            toRemove.addAll(tempPortList);
1618:                            toRemove.add(cells[i]);
1619:                            groupExists = true;
1620:                        }
1621:                    }
1622:                    if (groupExists)
1623:                        remove(toRemove.toArray());
1624:                    return children.toArray();
1625:                }
1626:                return null;
1627:            }
1628:
1629:            /**
1630:             * Toggles the collapsed state of the specified cells.
1631:             * 
1632:             * @param cells
1633:             *            The cells to toggle the collapsed state for.
1634:             * @param collapseOnly
1635:             *            Whether cells should only be collapsed.
1636:             * @param expandOnly
1637:             *            Whether cells should only be expanded.
1638:             * 
1639:             */
1640:            public void toggleCollapsedState(Object[] cells,
1641:                    boolean collapseOnly, boolean expandOnly) {
1642:                List toExpand = new ArrayList();
1643:                List toCollapse = new ArrayList();
1644:                for (int i = 0; i < cells.length; i++) {
1645:                    Object cell = cells[i];
1646:                    CellView view = getMapping(cell, false);
1647:                    if (view != null) {
1648:
1649:                        // Adds to list of expansion cells if it is a leaf in the layout
1650:                        // cache and we do not only want to collapse.
1651:                        if (view.isLeaf() && !collapseOnly)
1652:                            toExpand.add(view.getCell());
1653:
1654:                        // Else adds to list of to-be-collapsed cells if it is not a
1655:                        // leaf in the layout cache we do not only want to expand.
1656:                        else if (!view.isLeaf() && !expandOnly)
1657:                            toCollapse.add(view.getCell());
1658:                    }
1659:                }
1660:                if (!toCollapse.isEmpty() || !toExpand.isEmpty())
1661:                    setCollapsedState(toCollapse.toArray(), toExpand.toArray());
1662:            }
1663:
1664:            /**
1665:             * Collapses all groups by hiding all their descendants.
1666:             * 
1667:             * @param groups
1668:             */
1669:            public void collapse(Object[] groups) {
1670:                setCollapsedState(groups, null);
1671:            }
1672:
1673:            /**
1674:             * Expands all groups by showing all children. (Note: This does not show all
1675:             * descandants, but only the first generation of children.)
1676:             */
1677:            public void expand(Object[] cells) {
1678:                setCollapsedState(null, cells);
1679:            }
1680:
1681:            /**
1682:             * Collapses and/or expands the specified cell(s)
1683:             * 
1684:             * @param collapse
1685:             *            the cells to be collapsed
1686:             * @param expand
1687:             *            the cells to be expanded
1688:             */
1689:            public void setCollapsedState(Object[] collapse, Object[] expand) {
1690:                // Get all descandants for the groups
1691:                ConnectionSet cs = new ConnectionSet();
1692:
1693:                // Collapse cells
1694:                List toHide = DefaultGraphModel.getDescendants(getModel(),
1695:                        collapse);
1696:                if (collapse != null) {
1697:                    // Remove the groups themselfes
1698:                    for (int i = 0; i < collapse.length; i++) {
1699:                        toHide.remove(collapse[i]);
1700:                        cellWillCollapse(collapse[i]);
1701:                    }
1702:                    // Remove the ports (will be hidden automatically)
1703:                    for (int i = 0; i < collapse.length; i++) {
1704:                        int childCount = getModel().getChildCount(collapse[i]);
1705:                        if (childCount > 0) {
1706:                            for (int j = 0; j < childCount; j++) {
1707:                                Object child = getModel().getChild(collapse[i],
1708:                                        j);
1709:                                if (getModel().isPort(child)) {
1710:                                    toHide.remove(child);
1711:                                }
1712:                            }
1713:                        }
1714:                    }
1715:                }
1716:
1717:                // Expand cells
1718:                Set toShow = new HashSet();
1719:                if (expand != null) {
1720:                    for (int i = 0; i < expand.length; i++) {
1721:                        int childCount = getModel().getChildCount(expand[i]);
1722:                        for (int j = 0; j < childCount; j++) {
1723:                            toShow.add(getModel().getChild(expand[i], j));
1724:                        }
1725:                    }
1726:                }
1727:                setVisible(toShow.toArray(), (toHide != null) ? toHide
1728:                        .toArray() : null, cs);
1729:            }
1730:
1731:            /**
1732:             * Hook for subclassers to return the first or last visible port to replace
1733:             * the current source or target port of the edge. This is called when groups
1734:             * are collapsed for the edges that cross the group, ie. go from a child
1735:             * cell to a cell which is outside the group. This implementation returns
1736:             * the first port of the parent group if source is true, otherwise it
1737:             * returns the last port of the parent group.
1738:             */
1739:            protected Object getParentPort(Object edge, boolean source) {
1740:                // Contains the parent of the parent vertex, eg. the group
1741:                Object parent = getModel().getParent(
1742:                        (source) ? DefaultGraphModel.getSourceVertex(
1743:                                getModel(), edge) : DefaultGraphModel
1744:                                .getTargetVertex(getModel(), edge));
1745:                // Finds a port in the group
1746:                int c = getModel().getChildCount(parent);
1747:                for (int i = (source) ? c - 1 : 0; i < getModel()
1748:                        .getChildCount(parent)
1749:                        && i >= 0; i += (source) ? -1 : +1) {
1750:                    Object child = getModel().getChild(parent, i);
1751:                    if (getModel().isPort(child)) {
1752:                        return child;
1753:                    }
1754:                }
1755:                return null;
1756:            }
1757:
1758:            /**
1759:             * Hook for subclassers to return the port to be used for edges that have
1760:             * been connected to the group. This is called from expand. This returns the
1761:             * first port of the first or last vertex depending on <code>source</code>.
1762:             */
1763:            protected Object getChildPort(Object edge, boolean source) {
1764:                GraphModel model = getModel();
1765:                // Contains the parent of the port, eg. the group
1766:                Object parent = (source) ? DefaultGraphModel.getSourceVertex(
1767:                        model, edge) : DefaultGraphModel.getTargetVertex(model,
1768:                        edge);
1769:                // Finds a vertex in the group
1770:                int c = model.getChildCount(parent);
1771:                for (int i = (source) ? c - 1 : 0; i < c && i >= 0; i += (source) ? -1
1772:                        : +1) {
1773:                    Object child = model.getChild(parent, i);
1774:                    if (!model.isEdge(child) && !model.isPort(child)) {
1775:                        // Finds a port in the vertex
1776:                        for (int j = 0; j < model.getChildCount(child); j++) {
1777:                            Object port = model.getChild(child, j);
1778:                            if (model.isPort(port)) {
1779:                                return port;
1780:                            }
1781:                        }
1782:                    }
1783:                }
1784:                return null;
1785:            }
1786:
1787:            /**
1788:             * Applies the <code>propertyMap</code> and the connection changes to the
1789:             * model. The initial <code>edits</code> that triggered the call are
1790:             * considered to be part of this transaction. Notifies the model- and undo
1791:             * listeners of the change. Note: The passed in attributes may contain
1792:             * PortViews.
1793:             */
1794:            public void edit(Map attributes, ConnectionSet cs, ParentMap pm,
1795:                    UndoableEdit[] e) {
1796:                if (attributes != null || cs != null || pm != null || e != null) {
1797:                    Object[] visible = null;
1798:                    if (isPartial() && showsInvisibleEditedCells) {
1799:                        Set tmp = new HashSet();
1800:                        if (attributes != null)
1801:                            tmp.addAll(attributes.keySet());
1802:                        if (cs != null)
1803:                            tmp.addAll(cs.getChangedEdges());
1804:                        if (pm != null)
1805:                            tmp.addAll(pm.getChangedNodes());
1806:                        tmp.removeAll(visibleSet);
1807:                        if (!tmp.isEmpty())
1808:                            visible = tmp.toArray();
1809:                    }
1810:                    GraphLayoutCacheEdit edit = createLocalEdit(null,
1811:                            attributes, visible, null);
1812:                    if (edit != null)
1813:                        e = augment(e, edit);
1814:                    // Pass to model
1815:                    graphModel.edit(attributes, cs, pm, e);
1816:                }
1817:            }
1818:
1819:            /**
1820:             * A shortcut method that takes a nested map and passes it to the edit
1821:             * method.
1822:             */
1823:            public void edit(Map attributes) {
1824:                edit(attributes, null, null, null);
1825:            }
1826:
1827:            /**
1828:             * Applies the <code>attributes</code> to all <code>cells</code> by
1829:             * creating a map that contains the attributes for each cell and passing it
1830:             * to edit on this layout cache. Example:
1831:             * 
1832:             * <pre>
1833:             * Map attrs = new java.util.Hashtable();
1834:             * GraphConstants.setBackground(attrs, Color.RED);
1835:             * graph.getGraphLayoutCache().edit(graph.getSelectionCells(), attrs);
1836:             * </pre>
1837:             */
1838:            public void edit(Object[] cells, Map attributes) {
1839:                if (attributes != null && cells != null && cells.length > 0) {
1840:                    Map nested = new Hashtable();
1841:                    for (int i = 0; i < cells.length; i++)
1842:                        nested.put(cells[i], attributes);
1843:                    edit(nested, null, null, null);
1844:                }
1845:            }
1846:
1847:            /**
1848:             * Applies the <code>attributes</code> to a single <code>cell</code> by
1849:             * creating a map that contains the attributes for this cell and passing it
1850:             * to edit on this layout cache. Example:
1851:             * 
1852:             * <pre>
1853:             * Map attrs = new java.util.Hashtable();
1854:             * GraphConstants.setBackground(attrs, Color.RED);
1855:             * graph.getGraphLayoutCache().editCell(graph.getSelectionCell(), attrs);
1856:             * </pre>
1857:             */
1858:            public void editCell(Object cell, Map attributes) {
1859:                if (attributes != null && cell != null) {
1860:                    edit(new Object[] { cell }, attributes);
1861:                }
1862:            }
1863:
1864:            protected UndoableEdit[] augment(UndoableEdit[] e, UndoableEdit edit) {
1865:                if (edit != null) {
1866:                    int size = (e != null) ? e.length + 1 : 1;
1867:                    UndoableEdit[] result = new UndoableEdit[size];
1868:                    if (e != null)
1869:                        System.arraycopy(e, 0, result, 0, size - 2);
1870:                    result[size - 1] = edit;
1871:                    return result;
1872:                }
1873:                return e;
1874:            }
1875:
1876:            /**
1877:             * Sends <code>cells</code> to back. Note: This expects an array of cells!
1878:             */
1879:            public void toBack(Object[] cells) {
1880:                if (cells != null && cells.length > 0) {
1881:                    graphModel.toBack(cells);
1882:                }
1883:            }
1884:
1885:            /**
1886:             * Brings <code>cells</code> to front. Note: This expects an array of
1887:             * cells!
1888:             */
1889:            public void toFront(Object[] cells) {
1890:                if (cells != null && cells.length > 0) {
1891:                    graphModel.toFront(cells);
1892:                }
1893:            }
1894:
1895:            /**
1896:             * Creates a local edit for the specified change. A local operation contains
1897:             * all visibility changes, as well as all changes to attributes that are
1898:             * local, and all control attributes. <br>
1899:             * Note: You must use cells as keys for the nested map, not cell views.
1900:             */
1901:            protected GraphLayoutCacheEdit createLocalEdit(Object[] inserted,
1902:                    Map nested, Object[] visible, Object[] invisible) {
1903:                // Create an edit if there are any view-local attributes set
1904:                if ((nested != null && !nested.isEmpty())
1905:                        && (!localAttributes.isEmpty() || isAllAttributesLocal())) {
1906:                    // Move or Copy Local Attributes to Local View
1907:                    Map globalMap = new Hashtable();
1908:                    Map localMap = new Hashtable();
1909:                    Map localAttr;
1910:                    Iterator it = nested.entrySet().iterator();
1911:                    while (it.hasNext()) {
1912:                        localAttr = new Hashtable();
1913:                        Map.Entry entry = (Map.Entry) it.next();
1914:                        // (cell, Hashtable)
1915:                        Object cell = entry.getKey();
1916:                        Map attr = (Map) entry.getValue();
1917:                        // Create Difference of Existing and New Attributes
1918:                        CellView tmpView = getMapping(cell, false);
1919:                        if (tmpView != null)
1920:                            attr = tmpView.getAllAttributes().diff(attr);
1921:                        // End of Diff
1922:                        Iterator it2 = attr.entrySet().iterator();
1923:                        while (it2.hasNext()) {
1924:                            Map.Entry entry2 = (Map.Entry) it2.next();
1925:                            // (key, value)
1926:                            Object key = entry2.getKey();
1927:                            Object value = entry2.getValue();
1928:                            boolean isControlAttribute = isControlAttribute(
1929:                                    cell, key, value);
1930:                            if (isAllAttributesLocal() || isControlAttribute
1931:                                    || isLocalAttribute(cell, key, value)) {
1932:                                localAttr.put(key, value);
1933:                                if (!isControlAttribute)
1934:                                    it2.remove();
1935:                            }
1936:                        }
1937:                        if (!localAttr.isEmpty())
1938:                            localMap.put(cell, localAttr);
1939:                        if (!attr.isEmpty())
1940:                            globalMap.put(cell, attr);
1941:                    }
1942:                    nested.clear();
1943:                    nested.putAll(globalMap);
1944:                    if (visible != null || invisible != null
1945:                            || !localMap.isEmpty()) {
1946:                        GraphLayoutCacheEdit edit = new GraphLayoutCacheEdit(
1947:                                inserted, new Hashtable(localMap), visible,
1948:                                invisible);
1949:                        edit.end();
1950:                        return edit;
1951:                    }
1952:                } else if (visible != null || invisible != null) {
1953:                    GraphLayoutCacheEdit edit = new GraphLayoutCacheEdit(
1954:                            inserted, null, visible, invisible);
1955:                    edit.end();
1956:                    return edit;
1957:                }
1958:                return null;
1959:            }
1960:
1961:            /**
1962:             * Returns true if the set of local attributes contains <code>key</code>
1963:             */
1964:            protected boolean isLocalAttribute(Object cell, Object key,
1965:                    Object value) {
1966:                return localAttributes.contains(key);
1967:            }
1968:
1969:            /**
1970:             * Returns true if <code>key</code> is a control attribute
1971:             */
1972:            protected boolean isControlAttribute(Object cell, Object key,
1973:                    Object value) {
1974:                return GraphConstants.REMOVEALL.equals(key)
1975:                        || GraphConstants.REMOVEATTRIBUTES.equals(key);
1976:            }
1977:
1978:            /**
1979:             * Handles the removal of view local attributes. Since these attributes are
1980:             * only being stored in the view, the option is provided to copy the values
1981:             * for that key into the model. Without this, those values are lost.
1982:             * 
1983:             * @param key
1984:             *            the key of the view local attribute
1985:             * @param addToModel
1986:             *            whether or not to move the attribute values to the graph model
1987:             * @param override
1988:             *            whether or not to override the key's value in the model cell's
1989:             *            attribute map if it exists
1990:             * @return whether or not the operation completed sucessfully
1991:             */
1992:            public boolean removeViewLocalAttribute(Object key,
1993:                    boolean addToModel, boolean override) {
1994:                if (localAttributes.contains(key)) {
1995:                    if (addToModel) {
1996:                        // Iterate through all views copying this attribute to the
1997:                        // cell.
1998:                        copyRemovedViewValue(key, addToModel, override, mapping
1999:                                .values());
2000:                        copyRemovedViewValue(key, addToModel, override,
2001:                                hiddenMapping.values());
2002:                    }
2003:                    localAttributes.remove(key);
2004:                    return true;
2005:                }
2006:                return false;
2007:            }
2008:
2009:            /**
2010:             * Helper method to copy removed view local attributes to model cell's
2011:             * 
2012:             * @param key
2013:             *            the key of the view local attribute
2014:             * @param addToModel
2015:             *            whether or not to move the attribute values to the graph model
2016:             * @param override
2017:             *            whether or not to override the key's value in the model cell's
2018:             *            attribute map if it exists
2019:             * @param coll
2020:             *            the current collection being analysed
2021:             */
2022:            private void copyRemovedViewValue(Object key, boolean addToModel,
2023:                    boolean override, Collection coll) {
2024:                Iterator iter = coll.iterator();
2025:                while (iter.hasNext()) {
2026:                    CellView cellView = (CellView) iter.next();
2027:                    Map attributes = cellView.getAttributes();
2028:                    if (attributes.containsKey(key)) {
2029:                        if (addToModel) {
2030:                            Object cell = cellView.getCell();
2031:                            Map cellAttributes = graphModel.getAttributes(cell);
2032:                            if (cellAttributes != null) {
2033:                                boolean cellContainsKey = cellAttributes
2034:                                        .containsKey(key);
2035:                                // Write the model cell's attribute map key
2036:                                // if overriding is enabled or if key doesn't
2037:                                // exist
2038:                                if (!override || !cellContainsKey) {
2039:                                    Object value = attributes.get(key);
2040:                                    cellAttributes.put(key, value);
2041:                                }
2042:                            }
2043:                        }
2044:                        attributes.remove(key);
2045:                    }
2046:                }
2047:            }
2048:
2049:            /**
2050:             * An implementation of GraphViewChange.
2051:             */
2052:            public class GraphLayoutCacheEdit extends CompoundEdit implements 
2053:                    GraphLayoutCacheEvent.GraphLayoutCacheChange {
2054:
2055:                protected Object[] cells, previousCells = null;
2056:
2057:                protected CellView[] context, hidden;
2058:
2059:                protected Map attributes, previousAttributes;
2060:
2061:                protected Object[] visible, invisible;
2062:
2063:                // Remember which cells have changed for finding their context
2064:                protected Set changedCells = new HashSet();
2065:
2066:                /**
2067:                 * Constructs a GraphViewEdit. This modifies the attributes of the
2068:                 * specified views and may be used to notify UndoListeners.
2069:                 * 
2070:                 * @param nested
2071:                 *            the map that defines the new attributes
2072:                 */
2073:                public GraphLayoutCacheEdit(Map nested) {
2074:                    this (null, nested, null, null);
2075:                    attributes = nested;
2076:                }
2077:
2078:                /**
2079:                 * Constructs a GraphViewEdit. This modifies the attributes of the
2080:                 * specified views and may be used to notify UndoListeners. This should
2081:                 * also take an array of removed cell views, but it is not possible to
2082:                 * add further UndoableEdits to an already executed CompoundEdit, such
2083:                 * as a GraphModel change. Thus, to handle implicit changes -- rather
2084:                 * than piggybacking on the model's event -- the CompoundEdit's addEdit
2085:                 * method should be extended to accept and instantly execute sub-
2086:                 * sequent edits (implicit changes to the view, such as removing a
2087:                 * mapping, hiding a view or the like).
2088:                 * 
2089:                 * @param inserted
2090:                 *            an array of inserted cells
2091:                 * @param attributes
2092:                 *            the map that defines the new attributes
2093:                 * @param visible
2094:                 *            an array defining which cells are visible
2095:                 * @param invisible
2096:                 *            an array defining which cells are invisible
2097:                 */
2098:                public GraphLayoutCacheEdit(Object[] inserted, Map attributes,
2099:                        Object[] visible, Object[] invisible) {
2100:                    super ();
2101:                    this .attributes = attributes;
2102:                    this .previousAttributes = attributes;
2103:                    this .cells = inserted;
2104:                    this .visible = visible;
2105:                    this .invisible = invisible;
2106:                }
2107:
2108:                public Object getSource() {
2109:                    return GraphLayoutCache.this ;
2110:                }
2111:
2112:                public boolean isSignificant() {
2113:                    return true;
2114:                }
2115:
2116:                /**
2117:                 * Returns the cell views that have changed.
2118:                 */
2119:                public Object[] getChanged() {
2120:                    return changedCells.toArray();
2121:                }
2122:
2123:                /**
2124:                 * Returns the cells that habe been made visible.
2125:                 */
2126:                public Object[] getInserted() {
2127:                    return invisible;
2128:                }
2129:
2130:                /**
2131:                 * Returns the cells that have changed.
2132:                 */
2133:                public Object[] getRemoved() {
2134:                    return visible;
2135:                }
2136:
2137:                /**
2138:                 * Returns the views that have not changed explicitly, but implicitly
2139:                 * because one of their dependent cells has changed.
2140:                 */
2141:                public Object[] getContext() {
2142:                    return context;
2143:                }
2144:
2145:                /**
2146:                 * Returns a map of (cell view, attribute) pairs.
2147:                 */
2148:                public Map getAttributes() {
2149:                    return attributes;
2150:                }
2151:
2152:                /**
2153:                 * Returns a map of (cell view, attribute) pairs.
2154:                 */
2155:                public Map getPreviousAttributes() {
2156:                    return previousAttributes;
2157:                }
2158:
2159:                /**
2160:                 * Redoes a change.
2161:                 * 
2162:                 * @exception CannotRedoException
2163:                 *                if the change cannot be redone
2164:                 */
2165:                public void redo() throws CannotRedoException {
2166:                    super .redo();
2167:                    execute();
2168:                }
2169:
2170:                /**
2171:                 * Undoes a change.
2172:                 * 
2173:                 * @exception CannotUndoException
2174:                 *                if the change cannot be undone
2175:                 */
2176:                public void undo() throws CannotUndoException {
2177:                    super .undo();
2178:                    execute();
2179:                }
2180:
2181:                /**
2182:                 * Execute this edit such that the next invocation to this method will
2183:                 * invert the last execution.
2184:                 */
2185:                public void execute() {
2186:                    GraphModel model = getModel();
2187:                    changedCells.clear();
2188:                    // Remember or restore hidden cells
2189:                    if (hidden != null)
2190:                        for (int i = 0; i < hidden.length; i++)
2191:                            if (hidden[i] != null)
2192:                                mapping.put(hidden[i].getCell(), hidden[i]);
2193:                    if (!remembersCellViews) // already remembered
2194:                        hidden = getMapping(invisible);
2195:                    // Handle visibility
2196:                    boolean updatePorts = setVisibleImpl(visible, true)
2197:                            | setVisibleImpl(invisible, false);
2198:                    if (visible != null) {
2199:                        for (int i = 0; i < visible.length; i++) {
2200:                            changedCells.add(visible[i]);
2201:
2202:                            // Only calls if not inserted
2203:                            if (cells == null)
2204:                                cellExpanded(visible[i]);
2205:                        }
2206:                    }
2207:                    if (invisible != null)
2208:                        for (int i = 0; i < invisible.length; i++)
2209:                            changedCells.add(invisible[i]);
2210:                    // Swap arrays
2211:                    Object[] tmp = visible;
2212:                    visible = invisible;
2213:                    invisible = tmp;
2214:                    // Handle attributes
2215:                    if (attributes != null) {
2216:                        previousAttributes = attributes;
2217:                        changedCells.addAll(attributes.keySet());
2218:                        attributes = handleAttributes(attributes);
2219:                    }
2220:                    if (updatePorts)
2221:                        updatePorts();
2222:                    // Add ancestor cells to changed cells
2223:                    Set parentSet = new HashSet();
2224:                    Iterator it = changedCells.iterator();
2225:                    while (it.hasNext()) {
2226:                        Object parent = model.getParent(it.next());
2227:                        while (parent != null) {
2228:                            parentSet.add(parent);
2229:                            parent = model.getParent(parent);
2230:                        }
2231:                    }
2232:                    changedCells.addAll(parentSet);
2233:                    // Refresh all changed cells
2234:                    refresh(getMapping(changedCells.toArray(), false), false);
2235:                    // Updates the connected edges. Make sure that changedCells
2236:                    // contains no edges, as these will be removed from the result.
2237:                    Set ctx = DefaultGraphModel.getEdges(getModel(),
2238:                            changedCells.toArray());
2239:                    context = getMapping(ctx.toArray());
2240:                    refresh(context, false);
2241:                    tmp = cells;
2242:                    cells = previousCells;
2243:                    previousCells = tmp;
2244:                    reloadRoots();
2245:                    fireGraphLayoutCacheChanged(GraphLayoutCache.this , this );
2246:                }
2247:            }
2248:
2249:            /**
2250:             * Called when a child has been made visible by expanding its parent. This
2251:             * implementation translates the child so that it reflects the offset of the
2252:             * parent group since the child was last visible (see
2253:             * {@link #movesChildrenOnExpand}).
2254:             */
2255:            protected void cellExpanded(Object cell) {
2256:                GraphModel model = getModel();
2257:                // Moves the child to the group origin if it is not a port
2258:                if (movesChildrenOnExpand && !model.isPort(cell)) {
2259:                    CellView view = getMapping(cell, false);
2260:
2261:                    if (view != null) {
2262:                        CellView parent = getMapping(model.getParent(cell),
2263:                                false);
2264:                        if (parent != null) {
2265:                            if (DefaultGraphModel.isVertex(model, parent)) {
2266:                                // Computes the offset of the parent group
2267:                                Rectangle2D src = GraphConstants
2268:                                        .getBounds(parent.getAllAttributes());
2269:                                Rectangle2D rect = parent.getBounds();
2270:                                double dx = src.getX() - rect.getX();
2271:                                double dy = src.getY() - rect.getY();
2272:
2273:                                // Gets the attributes from the cell view or
2274:                                // cell and translates the bounds or points
2275:                                AttributeMap attrs = view.getAttributes();
2276:                                if (!attrs.contains(GraphConstants.BOUNDS))
2277:                                    attrs = model.getAttributes(view.getCell());
2278:                                attrs.translate(dx, dy);
2279:                            }
2280:                        }
2281:                    }
2282:                }
2283:            }
2284:
2285:            protected void cellWillCollapse(Object cell) {
2286:                GraphModel model = getModel();
2287:                if (movesParentsOnCollapse) {
2288:                    CellView view = getMapping(cell, false);
2289:                    if (view != null && !view.isLeaf()) {
2290:                        // Uses view-local attribute if available
2291:                        AttributeMap attrs = view.getAttributes();
2292:                        if (!attrs.contains(GraphConstants.BOUNDS)
2293:                                && !localAttributes
2294:                                        .contains(GraphConstants.BOUNDS))
2295:                            attrs = model.getAttributes(cell);
2296:
2297:                        // Moves the group to the origin of the children
2298:                        Rectangle2D src = GraphConstants.getBounds(attrs);
2299:                        Rectangle2D b = view.getBounds();
2300:                        // FIXME: What if the group is exactly at "defaultBounds"?
2301:                        if (resizesParentsOnCollapse || src == null
2302:                                || src.equals(VertexView.defaultBounds)) {
2303:                            src = attrs.createRect(b.getX(), b.getY(), b
2304:                                    .getWidth()
2305:                                    * collapseXScale, b.getHeight()
2306:                                    * collapseYScale);
2307:                            attrs.applyValue(GraphConstants.BOUNDS, src);
2308:                        } else {
2309:                            src.setFrame(b.getX(), b.getY(), src.getWidth(),
2310:                                    src.getHeight());
2311:                        }
2312:                    }
2313:                }
2314:            }
2315:
2316:            /**
2317:             * Attention: Undo will not work for routing-change if ROUTING and POINTS
2318:             * are stored in different locations. This happens if the model holds the
2319:             * routing attribute and the routing changes from unrouted to routed. In
2320:             * this case the points in the view are already routed according to the new
2321:             * scheme when written to the command history (-> no undo).
2322:             */
2323:            protected Map handleAttributes(Map attributes) {
2324:                Map undo = new Hashtable();
2325:                CellView[] views = new CellView[attributes.size()];
2326:                Iterator it = attributes.entrySet().iterator();
2327:                int i = 0;
2328:                while (it.hasNext()) {
2329:                    Map.Entry entry = (Map.Entry) it.next();
2330:                    CellView cv = getMapping(entry.getKey(), false);
2331:                    views[i] = cv;
2332:                    i += 1;
2333:                    if (cv != null && cv.getAttributes() != null) {
2334:                        Map deltaNew = (Map) entry.getValue();
2335:                        // System.out.println("state=" + cv.getAttributes());
2336:                        // System.out.println("change=" + deltaNew);
2337:                        Map deltaOld = cv.getAttributes().applyMap(deltaNew);
2338:                        cv.refresh(this , this , false);
2339:                        // System.out.println("state'=" + cv.getAttributes());
2340:                        // System.out.println("change'=" + deltaOld);
2341:                        undo.put(cv.getCell(), deltaOld);
2342:                    }
2343:                }
2344:                // Re-route all child edges
2345:                update(views);
2346:                return undo;
2347:            }
2348:
2349:            //
2350:            // Static Methods
2351:            //
2352:            /**
2353:             * Translates the specified views by the given amount.
2354:             * 
2355:             * @param views
2356:             *            an array of cell view to each be translated
2357:             * @param dx
2358:             *            the amount to translate the views in the x-axis
2359:             * @param dy
2360:             *            the amount to translate the views in the x-axis
2361:             */
2362:            public static void translateViews(CellView[] views, double dx,
2363:                    double dy) {
2364:                for (int i = 0; i < views.length; i++) {
2365:                    if (views[i] instanceof  AbstractCellView) {
2366:                        ((AbstractCellView) views[i]).translate(dx, dy);
2367:                    }
2368:                }
2369:            }
2370:
2371:            /**
2372:             * Returns a collection of cells that are connected to the specified cell by
2373:             * edges. Any cells specified in the exclude set will be ignored.
2374:             * 
2375:             * @param cell
2376:             *            The cell from which the neighbours will be determined
2377:             * @param exclude
2378:             *            The set of cells to ignore when searching
2379:             * @param directed
2380:             *            whether or not direction of edges should be taken into account
2381:             * @param visibleCells
2382:             *            whether or not to only consider visible cells
2383:             * @return Returns the list of neighbours for <code>cell</code>
2384:             */
2385:            public List getNeighbours(Object cell, Set exclude,
2386:                    boolean directed, boolean visibleCells) {
2387:                // Traverse Graph
2388:                GraphModel model = getModel();
2389:                Object[] fanout = (directed) ? DefaultGraphModel
2390:                        .getOutgoingEdges(model, cell) : DefaultGraphModel
2391:                        .getEdges(model, new Object[] { cell }).toArray();
2392:                List neighbours = new ArrayList(fanout.length);
2393:                Set localExclude = new HashSet(fanout.length + 8, (float) 0.75);
2394:                for (int i = 0; i < fanout.length; i++) {
2395:                    // if only visible cells are being processed, check that this
2396:                    // edge is visible before looking for neighbours with it
2397:                    if (!visibleCells || isVisible(fanout[i])) {
2398:                        Object neighbour = DefaultGraphModel.getOpposite(model,
2399:                                fanout[i], cell);
2400:                        if (neighbour != null
2401:                                && (exclude == null || !exclude
2402:                                        .contains(neighbour))
2403:                                && !localExclude.contains(neighbour)
2404:                                && (!visibleCells || isVisible(neighbour))) {
2405:                            localExclude.add(neighbour);
2406:                            neighbours.add(neighbour);
2407:                        }
2408:                    }
2409:                }
2410:                return neighbours;
2411:            }
2412:
2413:            /**
2414:             * Returns the outgoing edges for cell. Cell should be a port or a vertex.
2415:             * 
2416:             * @param cell
2417:             *            The cell from which the outgoing edges will be determined
2418:             * @param exclude
2419:             *            The set of edges to ignore when searching
2420:             * @param visibleCells
2421:             *            whether or not only visible cells should be processed
2422:             * @param selfLoops
2423:             *            whether or not to include self loops in the returned list
2424:             * @return Returns the list of outgoing edges for <code>cell</code>
2425:             */
2426:            public List getOutgoingEdges(Object cell, Set exclude,
2427:                    boolean visibleCells, boolean selfLoops) {
2428:                return getEdges(cell, exclude, visibleCells, selfLoops, false);
2429:            }
2430:
2431:            /**
2432:             * Returns the incoming edges for cell. Cell should be a port or a vertex.
2433:             * 
2434:             * @param cell
2435:             *            The cell from which the incoming edges will be determined
2436:             * @param exclude
2437:             *            The set of edges to ignore when searching
2438:             * @param visibleCells
2439:             *            whether or not only visible cells should be processed
2440:             * @param selfLoops
2441:             *            whether or not to include self loops in the returned list
2442:             * @return Returns the list of incoming edges for <code>cell</code>
2443:             */
2444:            public List getIncomingEdges(Object cell, Set exclude,
2445:                    boolean visibleCells, boolean selfLoops) {
2446:                return getEdges(cell, exclude, visibleCells, selfLoops, true);
2447:            }
2448:
2449:            /**
2450:             * Returns the incoming or outgoing edges for cell. Cell should be a port or
2451:             * a vertex.
2452:             * 
2453:             * @param cell
2454:             *            The cell from which the edges will be determined
2455:             * @param exclude
2456:             *            The set of edges to ignore when searching
2457:             * @param visibleCells
2458:             *            whether or not only visible cells should be processed
2459:             * @param selfLoops
2460:             *            whether or not to include self loops in the returned list
2461:             * @param incoming
2462:             *            <code>true</code> if incoming edges are to be obtained,
2463:             *            <code>false</code> if outgoing edges are to be obtained
2464:             * @return Returns the list of incoming or outgoing edges for
2465:             *         <code>cell</code>
2466:             */
2467:            protected List getEdges(Object cell, Set exclude,
2468:                    boolean visibleCells, boolean selfLoops, boolean incoming) {
2469:                GraphModel model = getModel();
2470:                Object[] edges = DefaultGraphModel.getEdges(model, cell,
2471:                        incoming);
2472:
2473:                List edgeList = new ArrayList(edges.length);
2474:                Set localExclude = new HashSet(edges.length);
2475:                for (int i = 0; i < edges.length; i++) {
2476:                    // Check that the edge is neiter in the passed in exclude set or
2477:                    // the local exclude set. Also, if visibleCells is true check
2478:                    // the edge is visible in the cache.
2479:                    if ((exclude == null || !exclude.contains(edges[i]))
2480:                            && !localExclude.contains(edges[i])
2481:                            && (!visibleCells || isVisible(edges[i]))) {
2482:                        // Add the edge to the list if all edges, including self loops
2483:                        // are allowed. If self loops are not allowed, ensure the
2484:                        // source and target of the edge are different
2485:                        if (selfLoops == true
2486:                                || model.getSource(edges[i]) != model
2487:                                        .getTarget(edges[i])) {
2488:                            edgeList.add(edges[i]);
2489:                        }
2490:                        localExclude.add(edges[i]);
2491:                    }
2492:                }
2493:                return edgeList;
2494:            }
2495:
2496:            /**
2497:             * Returns all views, shortcut to getAllDescendants(getRoots())
2498:             */
2499:            public CellView[] getAllViews() {
2500:                return getAllDescendants(getRoots());
2501:            }
2502:
2503:            /**
2504:             * Returns all views, including descendants that have a parent in
2505:             * <code>views</code>, especially the PortViews. Note: Iterative
2506:             * Implementation using model.getChild and getMapping on this cell mapper.
2507:             */
2508:            public CellView[] getAllDescendants(CellView[] views) {
2509:                Stack stack = new Stack();
2510:                for (int i = 0; i < views.length; i++)
2511:                    if (views[i] != null)
2512:                        stack.add(views[i]);
2513:                ArrayList result = new ArrayList();
2514:                while (!stack.isEmpty()) {
2515:                    CellView tmp = (CellView) stack.pop();
2516:                    Object[] children = tmp.getChildViews();
2517:                    for (int i = 0; i < children.length; i++)
2518:                        stack.add(children[i]);
2519:                    result.add(tmp);
2520:                    // Add Port Views
2521:                    for (int i = 0; i < graphModel.getChildCount(tmp.getCell()); i++) {
2522:                        Object child = graphModel.getChild(tmp.getCell(), i);
2523:                        if (graphModel.isPort(child)) {
2524:                            CellView view = getMapping(child, false);
2525:                            if (view != null)
2526:                                stack.add(view);
2527:                        }
2528:                    }
2529:                }
2530:                CellView[] ret = new CellView[result.size()];
2531:                result.toArray(ret);
2532:                return ret;
2533:            }
2534:
2535:            /**
2536:             * Returns the hiddenMapping.
2537:             * 
2538:             * @return Map
2539:             */
2540:            public Map getHiddenMapping() {
2541:                return hiddenMapping;
2542:            }
2543:
2544:            /**
2545:             * Sets the showsExistingConnections
2546:             * 
2547:             * @param showsExistingConnections
2548:             */
2549:            public void setShowsExistingConnections(
2550:                    boolean showsExistingConnections) {
2551:                this .showsExistingConnections = showsExistingConnections;
2552:            }
2553:
2554:            /**
2555:             * Returns the showsExistingConnections.
2556:             * 
2557:             * @return boolean
2558:             */
2559:            public boolean isShowsExistingConnections() {
2560:                return showsExistingConnections;
2561:            }
2562:
2563:            /**
2564:             * Sets the showsInsertedConnections
2565:             * 
2566:             * @param showsInsertedConnections
2567:             */
2568:            public void setShowsInsertedConnections(
2569:                    boolean showsInsertedConnections) {
2570:                this .showsInsertedConnections = showsInsertedConnections;
2571:            }
2572:
2573:            /**
2574:             * Returns the showsInsertedConnections.
2575:             * 
2576:             * @return boolean
2577:             */
2578:            public boolean isShowsInsertedConnections() {
2579:                return showsInsertedConnections;
2580:            }
2581:
2582:            /**
2583:             * Sets the hidesExistingConnections
2584:             * 
2585:             * @param hidesExistingConnections
2586:             */
2587:            public void setHidesExistingConnections(
2588:                    boolean hidesExistingConnections) {
2589:                this .hidesExistingConnections = hidesExistingConnections;
2590:            }
2591:
2592:            /**
2593:             * Returns the hidesExistingConnections.
2594:             * 
2595:             * @return boolean
2596:             */
2597:            public boolean isHidesExistingConnections() {
2598:                return hidesExistingConnections;
2599:            }
2600:
2601:            /**
2602:             * Sets the hidesDanglingConnections
2603:             * 
2604:             * @param hidesDanglingConnections
2605:             */
2606:            public void setHidesDanglingConnections(
2607:                    boolean hidesDanglingConnections) {
2608:                this .hidesDanglingConnections = hidesDanglingConnections;
2609:            }
2610:
2611:            /**
2612:             * Returns the hidesDanglingConnections.
2613:             * 
2614:             * @return boolean
2615:             */
2616:            public boolean isHidesDanglingConnections() {
2617:                return hidesDanglingConnections;
2618:            }
2619:
2620:            /**
2621:             * Sets the rememberCellViews.
2622:             * 
2623:             * @param rememberCellViews
2624:             *            The rememberCellViews to set
2625:             */
2626:            public void setRemembersCellViews(boolean rememberCellViews) {
2627:                this .remembersCellViews = rememberCellViews;
2628:            }
2629:
2630:            /**
2631:             * Returns the remembersCellViews.
2632:             * 
2633:             * @return boolean
2634:             */
2635:            public boolean isRemembersCellViews() {
2636:                return remembersCellViews;
2637:            }
2638:
2639:            /**
2640:             * Sets the hiddenSet.
2641:             * 
2642:             * @param hiddenSet
2643:             *            The hiddenSet to set
2644:             */
2645:            public void setHiddenSet(Map hiddenSet) {
2646:                this .hiddenMapping = hiddenSet;
2647:            }
2648:
2649:            /**
2650:             * @return Returns the localAttributes.
2651:             */
2652:            public Set getLocalAttributes() {
2653:                return localAttributes;
2654:            }
2655:
2656:            /**
2657:             * @param localAttributes
2658:             *            The localAttributes to set.
2659:             */
2660:            public void setLocalAttributes(Set localAttributes) {
2661:                this .localAttributes = localAttributes;
2662:            }
2663:
2664:            /**
2665:             * @return Returns the askLocalAttribute.
2666:             */
2667:            public boolean isAllAttributesLocal() {
2668:                return allAttributesLocal;
2669:            }
2670:
2671:            /**
2672:             * @param allAttributesLocal
2673:             *            The allAttributesLocal to set.
2674:             */
2675:            public void setAllAttributesLocal(boolean allAttributesLocal) {
2676:                this .allAttributesLocal = allAttributesLocal;
2677:            }
2678:
2679:            /**
2680:             * Returns true if cells should be auto-sized when their values change
2681:             * 
2682:             * @return true if cells should be auto-sized when their values change
2683:             */
2684:            public boolean isAutoSizeOnValueChange() {
2685:                return autoSizeOnValueChange;
2686:            }
2687:
2688:            /**
2689:             * Determines whether cells should be auto-sized when their values change.
2690:             * Fires a property change event if the new setting is different from the
2691:             * existing setting.
2692:             * 
2693:             * @param flag
2694:             *            a boolean value, true if cells should be auto-sized when their
2695:             *            values change
2696:             */
2697:            public void setAutoSizeOnValueChange(boolean flag) {
2698:                this .autoSizeOnValueChange = flag;
2699:            }
2700:
2701:            /**
2702:             * @return Returns the selectsAllInsertedCells.
2703:             */
2704:            public boolean isSelectsAllInsertedCells() {
2705:                return selectsAllInsertedCells;
2706:            }
2707:
2708:            /**
2709:             * @param selectsAllInsertedCells
2710:             *            The selectsAllInsertedCells to set.
2711:             */
2712:            public void setSelectsAllInsertedCells(
2713:                    boolean selectsAllInsertedCells) {
2714:                this .selectsAllInsertedCells = selectsAllInsertedCells;
2715:            }
2716:
2717:            /**
2718:             * @return Returns the selectsLocalInsertedCells.
2719:             */
2720:            public boolean isSelectsLocalInsertedCells() {
2721:                return selectsLocalInsertedCells;
2722:            }
2723:
2724:            /**
2725:             * @param selectsLocalInsertedCells
2726:             *            The selectsLocalInsertedCells to set.
2727:             */
2728:            public void setSelectsLocalInsertedCells(
2729:                    boolean selectsLocalInsertedCells) {
2730:                this .selectsLocalInsertedCells = selectsLocalInsertedCells;
2731:            }
2732:
2733:            /**
2734:             * @return Returns the reconnectsEdgesToVisibleParent.
2735:             * @deprecated edges are moved to parent view and back automatically
2736:             */
2737:            public boolean isReconnectsEdgesToVisibleParent() {
2738:                return reconnectsEdgesToVisibleParent;
2739:            }
2740:
2741:            /**
2742:             * @param reconnectsEdgesToVisibleParent
2743:             *            The reconnectsEdgesToVisibleParent to set.
2744:             * @deprecated edges are moved to parent view and back automatically
2745:             */
2746:            public void setReconnectsEdgesToVisibleParent(
2747:                    boolean reconnectsEdgesToVisibleParent) {
2748:                this .reconnectsEdgesToVisibleParent = reconnectsEdgesToVisibleParent;
2749:            }
2750:
2751:            /**
2752:             * @return Returns the showsChangedConnections.
2753:             */
2754:            public boolean isShowsChangedConnections() {
2755:                return showsChangedConnections;
2756:            }
2757:
2758:            /**
2759:             * @param showsChangedConnections
2760:             *            The showsChangedConnections to set.
2761:             */
2762:            public void setShowsChangedConnections(
2763:                    boolean showsChangedConnections) {
2764:                this .showsChangedConnections = showsChangedConnections;
2765:            }
2766:
2767:            /**
2768:             * @return Returns the moveChildrenOnExpand.
2769:             */
2770:            public boolean isMovesChildrenOnExpand() {
2771:                return movesChildrenOnExpand;
2772:            }
2773:
2774:            /**
2775:             * @param moveChildrenOnExpand
2776:             *            The moveChildrenOnExpand to set.
2777:             */
2778:            public void setMovesChildrenOnExpand(boolean moveChildrenOnExpand) {
2779:                this .movesChildrenOnExpand = moveChildrenOnExpand;
2780:            }
2781:
2782:            /**
2783:             * @return Returns the collapseXScale.
2784:             */
2785:            public double getCollapseXScale() {
2786:                return collapseXScale;
2787:            }
2788:
2789:            /**
2790:             * @param collapseXScale
2791:             *            The collapseXScale to set.
2792:             */
2793:            public void setCollapseXScale(double collapseXScale) {
2794:                this .collapseXScale = collapseXScale;
2795:            }
2796:
2797:            /**
2798:             * @return Returns the collapseYScale.
2799:             */
2800:            public double getCollapseYScale() {
2801:                return collapseYScale;
2802:            }
2803:
2804:            /**
2805:             * @param collapseYScale
2806:             *            The collapseYScale to set.
2807:             */
2808:            public void setCollapseYScale(double collapseYScale) {
2809:                this .collapseYScale = collapseYScale;
2810:            }
2811:
2812:            /**
2813:             * @return Returns the movesParentsOnCollapse.
2814:             */
2815:            public boolean isMovesParentsOnCollapse() {
2816:                return movesParentsOnCollapse;
2817:            }
2818:
2819:            /**
2820:             * @param movesParentsOnCollapse
2821:             *            The movesParentsOnCollapse to set.
2822:             */
2823:            public void setMovesParentsOnCollapse(boolean movesParentsOnCollapse) {
2824:                this .movesParentsOnCollapse = movesParentsOnCollapse;
2825:            }
2826:
2827:            /**
2828:             * @return Returns the resizesParentsOnCollapse.
2829:             */
2830:            public boolean isResizesParentsOnCollapse() {
2831:                return resizesParentsOnCollapse;
2832:            }
2833:
2834:            /**
2835:             * @param resizesParentsOnCollapse
2836:             *            The resizesParentsOnCollapse to set.
2837:             */
2838:            public void setResizesParentsOnCollapse(
2839:                    boolean resizesParentsOnCollapse) {
2840:                this .resizesParentsOnCollapse = resizesParentsOnCollapse;
2841:            }
2842:
2843:            /**
2844:             * Serialization support.
2845:             */
2846:            private void writeObject(ObjectOutputStream s) throws IOException {
2847:                s.defaultWriteObject();
2848:                // Write out the hidden mapping
2849:                Map map = new Hashtable(hiddenMapping);
2850:                s.writeObject(map);
2851:            }
2852:
2853:            /**
2854:             * Serialization support.
2855:             */
2856:            private void readObject(ObjectInputStream s) throws IOException,
2857:                    ClassNotFoundException {
2858:                s.defaultReadObject();
2859:                // Read the hidden mapping
2860:                Map map = (Map) s.readObject();
2861:                hiddenMapping = new WeakHashMap(map);
2862:            }
2863:
2864:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.