protected void schemaCheck() { if (inSchema) { m_nsch.lockSchema(); m_esch.lockSchema(); m_nodes = m_nsch.instantiate(); m_edges = m_esch.instantiate(); inSchema = false; } }
/** * A prefuse-based implementation of Fisheye Menus, showcasing the use of visual distortion to * provide access to a large number of data items without scrolling. * * <p>This implementation is inspired by the Fisheye Menu research conducted by Ben Bederson at the * University of Maryland. See the <a href="http://www.cs.umd.edu/hcil/fisheyemenu/">Fisheye Menu * project web site</a> for more details. * * @author <a href="http://jheer.org">jeffrey heer</a> */ public class FisheyeMenu extends Display { /** The data group name of menu items. */ public static final String ITEMS = "items"; /** The label data field for menu items. */ public static final String LABEL = "label"; /** The action data field for menu items. */ public static final String ACTION = "action"; /** This schema holds the data representation for internal storage of menu items. */ protected static final Schema ITEM_SCHEMA = new Schema(); static { ITEM_SCHEMA.addColumn(LABEL, String.class); ITEM_SCHEMA.addColumn(ACTION, ActionListener.class); } private Table m_items = ITEM_SCHEMA.instantiate(); // table of menu items private double m_maxHeight = 500; // maximum menu height in pixels private double m_scale = 7; // scale parameter for fisheye distortion /** * Create a new, empty FisheyeMenu. * * @see #addMenuItem(String, javax.swing.Action) */ public FisheyeMenu() { super(new Visualization()); m_vis.addTable(ITEMS, m_items); // set up the renderer to use LabelRenderer renderer = new LabelRenderer(LABEL); renderer.setHorizontalPadding(0); renderer.setVerticalPadding(1); renderer.setHorizontalAlignment(Constants.LEFT); m_vis.setRendererFactory(new DefaultRendererFactory(renderer)); // set up this display setSize(100, 470); setHighQuality(true); setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 5)); addControlListener( new ControlAdapter() { // dispatch an action event to the menu item public void itemClicked(VisualItem item, MouseEvent e) { ActionListener al = (ActionListener) item.get(ACTION); al.actionPerformed( new ActionEvent(item, e.getID(), "click", e.getWhen(), e.getModifiers())); } }); // text color function // items with the mouse over printed in red, otherwise black ColorAction colors = new ColorAction(ITEMS, VisualItem.TEXTCOLOR); colors.setDefaultColor(ColorLib.gray(0)); colors.add("hover()", ColorLib.rgb(255, 0, 0)); // initial layout and coloring ActionList init = new ActionList(); init.add(new VerticalLineLayout(m_maxHeight)); init.add(colors); init.add(new RepaintAction()); m_vis.putAction("init", init); // fisheye distortion based on the current anchor location ActionList distort = new ActionList(); Distortion feye = new FisheyeDistortion(0, m_scale); distort.add(feye); distort.add(colors); distort.add(new RepaintAction()); m_vis.putAction("distort", distort); // update the distortion anchor position to be the current // location of the mouse pointer addControlListener(new AnchorUpdateControl(feye, "distort")); } /** * Adds a menu item to the fisheye menu. * * @param name the menu label to use * @param action the ActionListener to notify when the item is clicked The prefuse VisualItem * corresponding to this menu item will be returned by the ActionEvent's getSource() method. */ public void addMenuItem(String name, ActionListener listener) { int row = m_items.addRow(); m_items.set(row, LABEL, name); m_items.set(row, ACTION, listener); } /** Run a demonstration of the FisheyeMenu */ public static final void main(String[] argv) { // only log warnings Logger.getLogger("prefuse").setLevel(Level.WARNING); FisheyeMenu fm = demo(); // create and display application window JFrame f = new JFrame("p r e f u s e | f i s h e y e"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().add(fm); f.pack(); f.setVisible(true); } public static FisheyeMenu demo() { // create a new fisheye menu and populate it FisheyeMenu fm = new FisheyeMenu(); for (int i = 1; i <= 72; ++i) { // add menu items that simply print their label when clicked fm.addMenuItem( String.valueOf(i), new AbstractAction() { public void actionPerformed(ActionEvent e) { System.out.println("clicked item: " + ((VisualItem) e.getSource()).get(LABEL)); System.out.flush(); } }); } fm.getVisualization().run("init"); return fm; } /** * Lines up all VisualItems vertically. Also scales the size such that all items fit within the * maximum layout size, and updates the Display to the final computed size. */ public class VerticalLineLayout extends Layout { private double m_maxHeight = 600; public VerticalLineLayout(double maxHeight) { m_maxHeight = maxHeight; } public void run(double frac) { // first pass double w = 0, h = 0; Iterator iter = m_vis.items(); while (iter.hasNext()) { VisualItem item = (VisualItem) iter.next(); item.setSize(1.0); h += item.getBounds().getHeight(); } double scale = h > m_maxHeight ? m_maxHeight / h : 1.0; Display d = m_vis.getDisplay(0); Insets ins = d.getInsets(); // second pass h = ins.top; double ih, y = 0, x = ins.left; iter = m_vis.items(); while (iter.hasNext()) { VisualItem item = (VisualItem) iter.next(); item.setSize(scale); item.setEndSize(scale); Rectangle2D b = item.getBounds(); w = Math.max(w, b.getWidth()); ih = b.getHeight(); y = h + (ih / 2); setX(item, null, x); setY(item, null, y); h += ih; } // set the display size to fit text setSize( d, (int) Math.round(2 * m_scale * w + ins.left + ins.right), (int) Math.round(h + ins.bottom)); } private void setSize(final Display d, final int width, final int height) { SwingUtilities.invokeLater( new Runnable() { public void run() { d.setSize(width, height); } }); } } // end of inner class VerticalLineLayout } // end of class FisheyeMenu