/* * @(#)JGraphLayoutAlgorithm.java 1.0 18-MAY-2004 * * 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.layout; import java.awt.BorderLayout; import java.awt.Component; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Rectangle2D; import java.util.HashSet; import java.util.Hashtable; import java.util.Map; import java.util.Set; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import org.jgraph.JGraph; import org.jgraph.graph.CellView; import org.jgraph.graph.GraphConstants; import org.jgraph.graph.GraphLayoutCache; import org.jgraph.graph.VertexView; /** * */ public abstract class JGraphLayoutAlgorithm { /** * @return */ protected static Set LAYOUT_ATTRIBUTES = new HashSet(); /** * @return */ static { LAYOUT_ATTRIBUTES.add(GraphConstants.BOUNDS); LAYOUT_ATTRIBUTES.add(GraphConstants.POINTS); LAYOUT_ATTRIBUTES.add(GraphConstants.LABELPOSITION); LAYOUT_ATTRIBUTES.add(GraphConstants.ROUTING); } /** * Set to false if the algorithm should terminate immediately */ boolean isAllowedToRun = true; /** * Set to non zero if you want to indicate progress */ int progress = 0, maximumProgress = 0; /** * Subclassers may return a new JComponent that * allows to configure the layout. The default * implementation returns null.
* Note: Settings creation may be expensive so * the UI should cache the values returned by * this method. */ public JGraphLayoutSettings createSettings() { return null; } /** * Get a human readable hint for using this layout. */ public String getHint() { return ""; } /** * Executes the layout algorithm with the given cells to be moved * @param graph JGraph to be altered by layout * @param cells Array of cells to be moved by the layout */ public void run(JGraph graph, Object[] cells) { run(graph, cells, null); } /** * Executes the layout algorithm specifying which cells are to remain * in place after the layout is applied. * @param jgraph JGraph to be altered by layout * @param dynamic_cells Cells that are to be moved by the layout * @param static_cells Cells that are not to be moved, but allowed for by the layout */ public abstract void run( JGraph jgraph, Object[] dynamic_cells, Object[] static_cells); /** * @return Returns the isAllowedToRun. */ public boolean isAllowedToRun() { return isAllowedToRun; } /** * @param isAllowedToRun The isAllowedToRun to set. */ public void setAllowedToRun(boolean isAllowedToRun) { this.isAllowedToRun = isAllowedToRun; } /** * Returns the maximum progress */ public int getMaximumProgress() { return maximumProgress; } /** * Sets the maximum progress. */ public void setMaximumProgress(int maximumProgress) { this.maximumProgress = maximumProgress; } /** * Returns the current progress */ public int getProgress() { return progress; } /** * @param progress The progress complete amount */ public void setProgress(int progress) { this.progress = progress; } /** * A utility method to create a simple dialog with * close and apply button. * @param settings Layout settings instance * @param parent Parent JFrame * @param title Title of dialog box * @param close Text for cancel button * @param apply Text for apply button * @return JDialog dialog to be displayed */ public static JDialog createDialog(final JGraphLayoutSettings settings, JFrame parent, String title, String close, String apply) { if (settings instanceof Component) return populateDialog(settings, new JDialog(parent, title, true), close, apply); return null; } /** * A utility method to create a simple dialog with * close and apply button. * @param settings Layout settings instance * @param parent Parent JDialog * @param title Title of dialog box * @param close Text for cancel button * @param apply Text for apply button * @return JDialog dialog to be displayed */ public static JDialog createDialog(final JGraphLayoutSettings settings, JDialog parent, String title, String close, String apply) { if (settings instanceof Component) return populateDialog(settings, new JDialog(parent, title, true), close, apply); return null; } /** * A utility method to create a simple dialog with * close and apply button. * @param settings Layout settings instance * @param dialog JDialog to be used * @param close Text for cancel button * @param apply Text for apply button * @return JDialog showing the settings for the layout */ public static JDialog populateDialog(final JGraphLayoutSettings settings, final JDialog dialog, String close, String apply) { if (dialog != null && settings instanceof Component) { dialog.getContentPane().setLayout(new BorderLayout()); dialog.getContentPane().add((Component) settings, BorderLayout.CENTER); JButton cancelButton = new JButton(close); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dialog.dispose(); } }); JButton applyButton = new JButton(apply); applyButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { settings.apply(); dialog.dispose(); } }); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); buttonPanel.add(applyButton); buttonPanel.add(cancelButton); dialog.getContentPane().add(buttonPanel, BorderLayout.SOUTH); dialog.getRootPane().setDefaultButton(applyButton); return dialog; } return dialog; } /** * Calls applyLayout() with null static_cells * @param sourceGraph The JGraph to have the layout applied * @param layout The layout algorithm to be applied * @param cells Cells that are to be moved by the layout */ public static void applyLayout( JGraph sourceGraph, JGraphLayoutAlgorithm layout, Object[] cells ) { JGraphLayoutAlgorithm.applyLayout(sourceGraph, layout, cells, null); } /** * Takes a local clone of the JGraph and calls the run() method on the * specified layout algorithm on the local JGraph. After the layout has * been applied, the changed attributes on the local JGraph are extracted * and applied to the JGraph instance passed in, creating one undoable edit. * @param sourceGraph The JGraph to have the layout applied * @param layout The layout algorithm to be applied * @param dynamic_cells Cells that are to be moved by the layout * @param static_cells Cells that are not to be moved, but allowed for by the layout */ public static void applyLayout( JGraph sourceGraph, JGraphLayoutAlgorithm layout, Object[] dynamic_cells, Object[] static_cells ) { JGraph localGraph = new JGraph(sourceGraph.getModel()); localGraph.setBounds(sourceGraph.getBounds()); GraphLayoutCache cache = localGraph.getGraphLayoutCache(); cache.setLocalAttributes(LAYOUT_ATTRIBUTES); layout.run(localGraph, dynamic_cells, static_cells); if (layout.isAllowedToRun()) { // fetch attributes from cellview and write to source Graph Map nested = new Hashtable(); CellView[] cellViews = cache.getAllDescendants(cache.getRoots()); for (int i = 0; i < cellViews.length; i++) { Map attrs = cellViews[i].getAttributes(); Rectangle2D bounds = GraphConstants.getBounds(attrs); if (cellViews[i] instanceof VertexView && bounds == null) { GraphConstants.setBounds(attrs, cellViews[i].getBounds()); } if (!attrs.isEmpty()) nested.put(cellViews[i].getCell(), attrs); } if (!nested.isEmpty()) sourceGraph.getGraphLayoutCache().edit(nested, null, null, null); } } }