📄 graphlayoutcache.java
字号:
/* * @(#)GraphLayoutCache.java 1.0 1/1/02 * * Copyright (c) 2001-2004, Gaudenz Alder * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of JGraph nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */package org.jgraph.graph;import java.awt.Rectangle;import java.io.Serializable;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Hashtable;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Observable;import java.util.Set;import java.util.Stack;import javax.swing.undo.AbstractUndoableEdit;import javax.swing.undo.CannotRedoException;import javax.swing.undo.CannotUndoException;import javax.swing.undo.CompoundEdit;import javax.swing.undo.UndoableEdit;import org.jgraph.event.GraphModelEvent;/** * An object that defines the view of a graphmodel. This object * maps between model cells and views and provides a set of methods * to change these views. * The view may also contain its own set of attributes and is therefore * an extension of an Observable, which may be observed by the GraphUI. * It uses the model to send its changes to the command history. * * @version 1.0 1/1/02 * @author Gaudenz Alder */public class GraphLayoutCache extends Observable implements CellMapper, Serializable { /* Boolean indicating whether new or changed edges should be made visible if * their source and target vertices are visible. * This setting has no effect in non-partial views. */ public boolean showAllEdgesForVisibleVertices = true; /* Boolean indicating whether edges should be made visible if * their connected vertices become visible. This does cause new edges to * be displayed automatically. * This setting has no effect in non-partial views. */ public boolean showEdgesOnShow = true; /* Boolean indicating whether attached edges should be made invisible * if their source or target port is hidden. * This setting has no effect in non-partial views. */ public boolean hideEdgesOnHide = true; /* Boolean indicating whether edges should be made invisible if * their connected vertices become invisible (for example when removed). * This setting has no effect in non-partial views. */ public boolean hideEdgesOnBecomeInvisible = true; /* Boolean indicating whether cellviews should be remembered once visible * in this GraphLayoutCache. */ public boolean rememberCellViews = true; /* Reference to the graphModel */ protected GraphModel graphModel; /* Maps cells to views. */ protected Map mapping = new Hashtable(); /* Reference to the cell mapper, typically this. */ protected CellMapper mapper; /* Factory to create the views. */ protected CellViewFactory factory = null; /* The set of visible cells. */ protected Set visibleSet = new HashSet(); /* Ordered list of roots for the view. */ protected List roots = new ArrayList(); /* Cached array of all ports for the view. */ protected PortView[] ports; /** * Remebered cell views. */ protected transient Map hiddenSet = new Hashtable(); /* View overrides model layering. */ protected boolean ordered = false; /* Only portions of the model are visible. */ protected boolean partial = false; /** * Constructs a view for the specified model that uses * <code>factory</code> to create its views. * * @param model the model that constitues the data source */ public GraphLayoutCache(GraphModel model, CellViewFactory factory) { this(model, factory, false, false); } /** * Constructs a view for the specified model that uses * <code>factory</code> to create its views. * * @param model the model that constitues the data source */ public GraphLayoutCache( GraphModel model, CellViewFactory factory, boolean ordered, boolean partial) { this(model, factory, ordered, partial, true, true, true, true, true); } /** * Constructs a view for the specified model that uses * <code>factory</code> to create its views. * * @param model the model that constitues the data source */ public GraphLayoutCache( GraphModel model, CellViewFactory factory, boolean ordered, boolean partial, boolean rememberCellViews, boolean showAllEdgesForVisibleVertices, boolean showEdgesOnShow, boolean hideEdgesOnHide, boolean hideEdgesOnBecomeInvisible) { this.factory = factory; this.ordered = ordered; this.partial = partial; this.rememberCellViews = rememberCellViews; this.showAllEdgesForVisibleVertices = showAllEdgesForVisibleVertices; this.showEdgesOnShow = showEdgesOnShow; this.hideEdgesOnHide = hideEdgesOnHide; this.hideEdgesOnBecomeInvisible = hideEdgesOnBecomeInvisible; setModel(model); } // // Accessors // /** * Sets the factory that creates the cell views. */ public void setFactory(CellViewFactory factory) { this.factory = factory; } /** * Returns the factory that was passed to the constructor. */ public CellViewFactory getFactory() { return factory; } /** * Sets the current model. */ public void setModel(GraphModel model) { roots.clear(); mapping.clear(); hiddenSet.clear(); visibleSet.clear(); graphModel = model; Object[] cells = DefaultGraphModel.getRoots(model); if (!isPartial()) insertRoots(getMapping(cells, true)); // AutoSize for Existing Cells if (cells != null) for (int i = 0; i < cells.length; i++) factory.updateAutoSize(getMapping(cells[i], false)); // Update PortView Cache updatePorts(); } // Remaps all existing views using the CellViewFactory // and replaces the respective root views. public synchronized void reload() { List newRoots = new ArrayList(); Map oldMapping = new Hashtable(mapping); mapping.clear(); Iterator it = oldMapping.keySet().iterator(); while (it.hasNext()) { Object cell = it.next(); CellView oldView = (CellView) oldMapping.get(cell); CellView newView = getMapping(cell, true); newView.setAttributes(oldView.getAttributes()); if (roots.contains(oldView)) newRoots.add(newView); } // replace hidden hiddenSet.clear(); roots = newRoots; } /** * Returns the current model. */ public GraphModel getModel() { return graphModel; } /** * Returns the roots of the view. */ public CellView[] getRoots() { CellView[] views = new CellView[roots.size()]; roots.toArray(views); return views; } /** * Return all cells that intersect the given rectangle. */ public CellView[] getRoots(Rectangle clip) { java.util.List result = new ArrayList(); CellView[] views = getRoots(); for (int i = 0; i < views.length; i++) if (views[i].getBounds().intersects(clip)) result.add(views[i]); views = new CellView[result.size()]; result.toArray(views); return views; } /** * Returns the ports of the view. */ public PortView[] getPorts() { return ports; } /** * Updates the cached array of ports. */ protected void updatePorts() { Object[] roots = DefaultGraphModel.getRoots(graphModel); Set set = DefaultGraphModel.getDescendants(graphModel, roots); if (set != null) { Object[] all = set.toArray(); //order(set.toArray()); ArrayList result = new ArrayList(); for (int i = 0; i < all.length; i++) { if (graphModel.isPort(all[i])) { CellView portView = getMapping(all[i], false); if (portView != null) { result.add(portView); portView.refresh(false); } } } ports = new PortView[result.size()]; result.toArray(ports); } } public void refresh(CellView[] views, boolean create) { if (views != null) for (int i = 0; i < views.length; i++) refresh(views[i], create); } public void refresh(CellView view, boolean create) { if (view != null) { view.refresh(create); CellView[] children = view.getChildViews(); for (int i = 0; i < children.length; i++) refresh(children[i], create); } } public void update(CellView[] views) { if (views != null) for (int i = 0; i < views.length; i++) update(views[i]); } public void update(CellView view) { if (view != null) { view.update(); CellView[] children = view.getChildViews(); for (int i = 0; i < children.length; i++) update(children[i]); } } // // Update View based on Model Change // /** * Called from BasicGraphUI.ModelHandler to update the view * based on the specified GraphModelEvent. */ public void graphChanged(GraphModelEvent.GraphModelChange change) { // Get Old Attributes From GraphModelChange (Undo) -- used to remap removed cells CellView[] views = change.getViews(this); if (views != null) { // Only ex-visible views are piggybacked for (int i = 0; i < views.length; i++) if (views[i] != null) { // Do not use putMapping because cells are invisible mapping.put(views[i].getCell(), views[i]); } // Ensure visible state setVisibleImpl(getCells(views), true); } // Fetch View Order Of Changed Cells (Before any changes) Object[] changed = order(change.getChanged()); // change.getChanged(); ? // Fetch Views to Insert before Removal (Special case: two step process, see setModel) CellView[] insertViews = getMapping(change.getInserted(), true); // Remove and Hide Roots views = removeRoots(change.getRemoved()); // Store Removed Attributes In GraphModelChange (Undo) change.putViews(this, views); // Insert New Roots insertRoots(insertViews); // Hide edges with invisible source or target if (isPartial()) { // Then show showCellsForChange(change); // First hide hideCellsForChange(change); } // Refresh Changed Cells if (changed != null && changed.length > 0) { // Restore All Cells in Model Order (Replace Roots) if (!isOrdered()) { roots.clear(); Object[] rootCells = DefaultGraphModel.getRoots(graphModel); CellView[] rootViews = getMapping(rootCells, false); for (int i = 0; i < rootViews.length; i++) { if (rootViews[i] != null) { // && isVisible(rootViews[i].getCell())) { roots.add(rootViews[i]); rootViews[i].refresh(true); factory.updateAutoSize(rootViews[i]); } } } for (int i = 0; i < changed.length; i++) { CellView view = getMapping(changed[i], false); if (view != null) { // && isVisible(view.getCell())) { view.refresh(true); // Update child edges in groups (routing) update(view); factory.updateAutoSize(view); if (isOrdered()) { CellView parentView = view.getParentView(); Object par = (parentView != null) ? parentView.getCell() : null; boolean isRoot = roots.contains(view); // Adopt Orphans if (par == null && !isRoot) roots.add(view); // Root Lost else if (par != null && isRoot) roots.remove(view); } } } } // Refresh inserted cells Object[] inserted = change.getInserted(); if (inserted != null && inserted.length > 0) { for (int i = 0; i < inserted.length; i++) factory.updateAutoSize(getMapping(inserted[i], false)); } // Refresh Context of Changed Cells (=Connected Edges) refresh(getMapping(change.getContext(), false), false); // Update Cached Ports If Necessary Object[] removed = change.getRemoved(); if ((removed != null && removed.length > 0) || (inserted != null && inserted.length > 0) || !isOrdered()) updatePorts(); } protected void hideCellsForChange( GraphModelEvent.GraphModelChange change) { // Hide visible edges between invisible vertices // 1. Remove attached edges of removed cells // 2. Remove edges who's source or target has changed to // invisible. Object[] tmp = change.getRemoved(); Set removed = new HashSet(); if (tmp != null) for (int i = 0; i < tmp.length; i++) removed.add(tmp[i]); if (hideEdgesOnBecomeInvisible) { Object[] changed = change.getChanged(); for (int i = 0; i < changed.length; i++) { CellView view = getMapping(changed[i], false); if (view instanceof EdgeView) { EdgeView edge = (EdgeView) view; Object oldSource = (edge.getSource() == null) ? null : edge.getSource().getCell(); Object oldTarget = (edge.getTarget() == null) ? null : edge.getTarget().getCell(); Object newSource = graphModel.getSource(changed[i]); Object newTarget = graphModel.getTarget(changed[i]); if ((removed.contains(oldSource) || removed.contains(oldTarget)) /*1*/ || ((newSource != null && !isVisible(newSource)) || (newTarget != null && !isVisible(newTarget)))) /*2*/ { //System.out.println("hiding: " + edge); setVisibleImpl(new Object[] { changed[i] }, false); } } } } } protected void showCellsForChange( GraphModelEvent.GraphModelChange change) { // Show new edges between visible vertices if (showAllEdgesForVisibleVertices) { Object[] inserted = change.getInserted(); if (inserted != null) { for (int i = 0; i < inserted.length; i++) { if (!isVisible(inserted[i])) { if (showAllEdgesForVisibleVertices) { Object source = graphModel.getSource(inserted[i]); Object target = graphModel.getTarget(inserted[i]); if ((source != null || target != null) && (isVisible(source) && isVisible(target))) setVisible(inserted[i], true); } } } } Object[] changed = change.getChanged();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -