// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/omGraphics/EditableOMGraphic.java,v $ // $RCSfile: EditableOMGraphic.java,v $ // $Revision: 1.11 $ // $Date: 2005/12/09 21:09:04 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.omGraphics; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import java.util.MissingResourceException; import javax.swing.JComponent; import javax.swing.JToolBar; import com.bbn.openmap.Environment; import com.bbn.openmap.I18n; import com.bbn.openmap.MapBean; import com.bbn.openmap.event.MapMouseAdapter; import com.bbn.openmap.event.MapMouseEvent; import com.bbn.openmap.event.UndoEvent; import com.bbn.openmap.event.UndoStack; import com.bbn.openmap.gui.GridBagToolBar; import com.bbn.openmap.omGraphics.editable.EOMGStateMachine; import com.bbn.openmap.omGraphics.event.EOMGEvent; import com.bbn.openmap.omGraphics.event.EOMGListener; import com.bbn.openmap.omGraphics.event.EOMGListenerSupport; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.util.ComponentFactory; import com.bbn.openmap.util.Debug; /** * The EditableOMGraphic is a shell that controls actions to edit or create a graphic. This class contains a state * machine that defines how mouse events will be interpreted to modify the OMGraphic contained within. Any class that * extends this one is responsible for assigning the appropriate state machine and OMGraphic to itself. Also, an * EditableOMGraphic has a notion of a list of GrabPoints, which can be used as handles to the OMGraphic to provide * controlled modifications. */ public abstract class EditableOMGraphic extends MapMouseAdapter { /** * If the grab points should be rendered differently than the default, the DrawingAttributes should be stored in the * edited OMGraphic under this attribute key. */ public final static String GRAB_POINT_DRAWING_ATTRIBUTES_ATTRIBUTE = "gpdaa"; /** * If the EditableOMGraphic supports the notion of a selected GrabPoint (to highlight a node), and that selection * should change the appearance of a GrabPoint, the DrawingAttributes for that selection appearance should be stored * in the edited OMGraphic attributes under this attribute key. */ public final static String SELECTED_GRAB_POINT_DRAWING_ATTRIBUTES_ATTRIBUTE = "sgpdaa"; /** * The state machine that interprets the mouse events (and other events) and modifies the OMGraphics accordingly. * * @see com.bbn.openmap.util.stateMachine.StateMachine */ protected EOMGStateMachine stateMachine; /** * This is here for the MapMouseListener interface. This may not be important, depending on what is funneling mouse * events to the graphic. */ protected String[] mouseModeServiceList; /** * The array of GrabPoints. */ protected GrabPoint[] gPoints; /** * The projection of the map. This can be retrieved from the mouse events, provided that the mouse events source is * the MapBean. */ protected Projection projection; /** * This GrabPoint is one that has been grabbed by the mouse, and is being moved. */ protected GrabPoint movingPoint = null; protected EOMGListenerSupport listeners = null; /** * Flag to indicate whether a GUI for this EOMG should be presented to allow edits to it's attributes. */ protected boolean showGUI = true; /** * Flag to let states know if the edges of the graphic can be grabbed directly, for movement or manipulation, as * opposed to just allowing those actions through the grab points. */ protected boolean canGrabGraphic = true; /** * The component to notify for changes made to the OMGraphic, so they can be undone if desired. */ protected UndoStack undoStack; protected I18n i18n = Environment.getI18n(); /** * A little flag to let the EOMG that a popup menu is up on the map. If the menu is up, and the menu is not clicked * on, we don't really want to deactivate the drawing tool right then - let a free click go by first, which will * dismiss the menu. */ protected boolean popupIsUp = false; /** * Action mask for this graphic. Used as a holder for modifying objects to let this EditableOMGraphic know what is * being done to it. */ protected int actionMask = 0; protected boolean DEBUG = false; protected boolean DEBUG_DETAIL = false; protected boolean xorRendering = true; protected EditableOMGraphic() { DEBUG = Debug.debugging("eomg"); DEBUG_DETAIL = Debug.debugging("eomgdetail"); } /** * Set the StateMachine for this EditableOMGraphic. * * @param sm StateMachine. * @see com.bbn.openmap.util.stateMachine.StateMachine */ public void setStateMachine(EOMGStateMachine sm) { stateMachine = sm; } /** * Get the state machine for this EditableOMGraphic. */ public EOMGStateMachine getStateMachine() { return stateMachine; } /** * Set the list of MouseMode names that this EditableOMGraphic will respond to, if it is dealing directly with a * MouseDelegator. */ public void setMouseModeServiceList(String[] list) { mouseModeServiceList = list; } /** * Get the list of MouseMode names that this EditableOMGraphic will respond to, if it is dealing directly with a * MouseDelegator. */ public String[] getMouseModeServiceList() { return mouseModeServiceList; } /** * Set whether this EOMG should provide a user interface to have the attributes modified. * * @param set true if the GUI should be shown. */ public void setShowGUI(boolean set) { showGUI = set; OMGraphic graphic = getGraphic(); if (graphic != null) { graphic.setShowEditablePalette(set); } } public boolean getShowGUI() { if (getGraphic() != null) { return getGraphic().getShowEditablePalette(); } else { return showGUI; } } /** * Set whether a graphic can be manipulated by its edges, rather than just by its grab points. Used internally. */ public void setCanGrabGraphic(boolean set) { canGrabGraphic = set; } /** * Get whether a graphic can be manipulated by its edges, rather than just by its grab points. */ public boolean getCanGrabGraphic() { return canGrabGraphic; } /** * Set the OMGraphic that is being modified by the EditableOMGraphic. The type of OMGraphic needs to match what the * EditableOMGraphic is expecting. Assume that if the graphic passed in is null, that a proper graphic will be * created. * * @param graphic OMGraphic. */ public abstract void setGraphic(OMGraphic graphic); /** * Create the OMGraphic that is to be modified by the EditableOMGraphic. * * @param ga GraphicAttributes, describing the graphic to be created. */ public abstract void createGraphic(GraphicAttributes ga); /** * Get the OMGraphic that is being created/modified by the EditableOMGraphic. */ public abstract OMGraphic getGraphic(); /** * Remove all changes and put graphic as it was before modifications. If the graphic is being created, start over. */ public void reset() { Debug.output("EditableOMGraphic.reset(): not yet supported"); } /** * Set the grab point objects within the EditableOMGraphic array. The size and layout of the points in the array are * carefully determined by the EditableOMGraphic, so this method merely replaces objects within the array, not * replacing the array itself, so that you cannot reset the number of grab points an EditableOMGraphic uses for a * particular OMGraphic. * * @param points a GrabPoint[] * @return true if the grab point array was exactly what the EditableOMGraphic was expecting, in terms of length of * the GrabPoint array length. The method copies the array values that fit into the resident array. */ public boolean setGrabPoints(GrabPoint[] points) { if (points == null || gPoints == null) { return false; } System.arraycopy(points, 0, gPoints, 0, Math.min(points.length, gPoints.length)); return (points.length == gPoints.length); } /** * Method to allow objects to set OMAction masks on this editable graphic. */ public void setActionMask(int mask) { actionMask = mask; } /** * Get the OMAction mask for this graphic. */ public int getActionMask() { return actionMask; } /** * Tells the EditableOMGraphic that the locations of the grab points have been modified, and that the parameters of * the OMGraphic need to be modified accordingly. */ public abstract void setGrabPoints(); /** * Get the array of grab points used for the EditableOMGraphic. Given a mouse event, you can see if one of these is * affected, and move it accordingly. Call setGrabPoints() when modifications are done, so that the OMGraphic is * modified. */ public GrabPoint[] getGrabPoints() { return gPoints; } /** * Set the GrabPoint at a particule index of the array. This can be used to tie two different grab points together. * * @param gb GrabPoint to assign within array. * @param index the index of the array to put the GrabPoint. The EditableOMGraphic should be able to provide the * description of the proper placement indexes. * @return If the grab point or array is null, or if the index is outside the range of the array, false is returned. * If everything goes OK, then true is returned. */ public boolean setGrabPoint(GrabPoint gb, int index) { if (gPoints != null && gb != null && index >= 0 && index < gPoints.length) { gPoints[index] = gb; return true; } else { return false; } } /** * Return a particular GrabPoint at a particular point in the array. The EditableOMGraphic should describe which * indexes refer to which grab points in the EOMG GrabPoint array. If the index is outside the range of the array, * null is returned. */ public GrabPoint getGrabPoint(int index) { if (gPoints != null && index >= 0 && index < gPoints.length) { return gPoints[index]; } else { return null; } } /** * Attach to the Moving OffsetGrabPoint so if it moves, it will move this EditableOMGraphic with it. * EditableOMGraphic version doesn't do anything, each subclass has to decide which of its OffsetGrabPoints should be * attached to it. */ public void attachToMovingGrabPoint(OffsetGrabPoint gp) { } /** * Detach from a Moving OffsetGrabPoint. The EditableOMGraphic version doesn't do anything, each subclass should * remove whatever GrabPoint it would have attached to an OffsetGrabPoint. */ public void detachFromMovingGrabPoint(OffsetGrabPoint gp) { } /** * Set the GrabPoint that is in the middle of being modified, as a result of a mouseDragged event, or other * selection. */ public void setMovingPoint(GrabPoint gp) { movingPoint = gp; } /** * Get the GrabPoint that is being moved. If it's null, then there isn't one. */ public GrabPoint getMovingPoint() { return movingPoint; } /** * Notification that a MouseEvent was used to trigger creation or edit of this EditableOMGraphic, and this is the * first MouseEvent received. If the EditableOMGraphic can handle it, it should. Otherwise, it should put itself in * the right state to let the user know it's active. */ public void handleInitialMouseEvent(MouseEvent e) { getStateMachine().setEdit(); if (e != null) { GrabPoint gp = getMovingPoint(e); if (gp == null) { move(e); } else { getStateMachine().setSelected(); } } else { getStateMachine().setSelected(); } } /** * Given a MouseEvent, find a GrabPoint that it is touching, and set the moving point to that GrabPoint. Called when * a MouseEvent happens like a mousePressed or mouseReleased, and you want to find out if a GrabPoint should be used * to make modifications to the graphic or its position. This method should only be called to establish a moving * point. getMovingPoint() should be called to check to see if one has been established, and then redraw(MouseEvent) * would be called to move that moving point. * * @param e MouseEvent * @return GrabPoint that is touched by the MouseEvent, null if none are. */ public GrabPoint getMovingPoint(MouseEvent e) { return _getMovingPoint(e); } /** * Given a MouseEvent, find a GrabPoint that it is touching, and set the moving point to that GrabPoint. A version * for grandchild classes. * * @param e MouseEvent that the GrabPoint should attach to. * @see #getMovingPoint(MouseEvent) */ public GrabPoint _getMovingPoint(MouseEvent e) { movingPoint = null; GrabPoint[] gb = getGrabPoints(); Point2D pnt = getProjectionPoint(e); double x = pnt.getX(); double y = pnt.getY(); for (int i = gb.length - 1; i >= 0; i--) { if (gb[i] != null && gb[i].distance(x, y) == 0) { setMovingPoint(gb[i]); // in case the points are on top of each other, the // last point in the array will take precedence. return gb[i]; } } setMovingPoint(null); return null; } /** * Called to set the OffsetGrabPoint to the current mouse location, and update the OffsetGrabPoint with all the other * GrabPoint locations, so everything can shift smoothly. Should also set the OffsetGrabPoint to the movingPoint. */ public abstract void move(MouseEvent e); /** * Clean the surface all the painting is taking place over. */ public void cleanMap(MouseEvent e) { Object obj = e.getSource(); if (!(obj instanceof MapBean)) { return; } // Could call repaint(), but I think we should paint in this // thread... MapBean map = (MapBean) obj; // Gets the buffer cleaned out. map.setBufferDirty(true); map.paintChildren(map.getGraphics(true)); } /** * Same as redraw(e, false) */ public void redraw(MouseEvent e) { redraw(e, false); } public void redraw(MouseEvent e, boolean firmPaint) { redraw(e, firmPaint, true); } /** * A DrawingAttributes object used to hold OMGraphic settings while it is being moved. When an OMGraphic is being * moved, basic (DEFAULT) settings are put on the OMGraphic to make it as light and uncomplicated as possible. */ protected DrawingAttributes holder = new DrawingAttributes(); /** * Given a MouseEvent, check the source, and if it's a MapBean, then grab the projection and java.awt.Graphics from * it to use for generation and rendering of the EditableOMGraphic objects. * * @param e MouseEvent * @param firmPaint true if the graphic is being rendered at rest, with fill colors and true colors, with the grab * point if the state allows it. If false, then the fill color will not be used, and just the graphic will be drawn. * Use false for graphics that are moving. */ public void redraw(MouseEvent e, boolean firmPaint, boolean drawXOR) { if (DEBUG) { Debug.output("EditableOMGraphic.redraw(" + (firmPaint ? "firmPaint)" : ")")); } drawXOR = drawXOR && isXorRendering(); if (e == null) { if (lastMouseEvent == null) { return; } e = lastMouseEvent; } Object obj = e.getSource(); if (!(obj instanceof MapBean)) { return; } MapBean map = (MapBean) obj; Graphics g = map.getGraphics(true); OMGraphic graphic = getGraphic(); // Seeing if we can make for a better rendering look by repainting the // mapBean all the time. With tiling, it works. if (!isXorRendering()) { map.repaint(); } if (firmPaint) { // So, with a firm paint, we want to clean the screen. If // the map is being buffered, we need to clean out the // buffer, which is why we set the Request paint to true, // to get the image rebuilt. Otherwise, a copy of the // graphic remains. map.setBufferDirty(true); graphic.generate(getProjection()); map.repaint(); } else { // If we get here, we are painting a moving object, so we // only want to do the outline to make it as fast as // possible. holder.setFrom(graphic); DrawingAttributes.DEFAULT.setTo(graphic); modifyOMGraphicForEditRender(); graphic.regenerate(getProjection()); if (drawXOR) { g.setXORMode(Color.lightGray); g.setColor((Color) graphic.getDisplayPaint()); render(g); } GrabPoint gp = getMovingPoint(); if (gp != null) { Point2D pnt = getProjectionPoint(e); double x = pnt.getX(); double y = pnt.getY(); gp.set((int) x, (int) y); if (gp instanceof OffsetGrabPoint) { ((OffsetGrabPoint) gp).moveOffsets(); } setGrabPoints(); } } if (!firmPaint) { generate(getProjection()); render(g); holder.setTo(graphic); } resetOMGraphicAfterEditRender(); g.dispose(); lastMouseEvent = e; } protected MouseEvent lastMouseEvent; /** * A convenience method that gives an EditableOMGraphic a chance to modify the OMGraphic so it can be drawn quickly, * by turning off labels, etc, right before the XORpainting happens. The OMGraphic should be configured so that the * render method does the least amount of painting possible. Note that the DrawingAttributes for the OMGraphic have * already been set to DrawingAttributes.DEFAULT (black line, clear fill). */ protected void modifyOMGraphicForEditRender() { } /** * A convenience method that gives an EditableOMGraphic a chance to reset the OMGraphic so it can be rendered * normally, after it has been modified for quick paints. The DrawingAttributes for the OMGraphic have already been * reset to their normal settings, from the DrawingAttributes.DEFAULT settings that were used for the quick paint. */ protected void resetOMGraphicAfterEditRender() { } public void repaint() { if (lastMouseEvent != null) { redraw(lastMouseEvent, true); } } protected void finalize() { if (getGraphic() != null) { getGraphic().setVisible(true); } if (Debug.debugging("gc")) { Debug.output("EditableOMGraphic gone."); } } /** * Use the current projection to place the graphics on the screen. Has to be called to at least assure the graphics * that they are ready for rendering. Called when the graphic position changes. * * @param proj com.bbn.openmap.proj.Projection * @return true */ public abstract boolean generate(Projection proj); /** * Given a new projection, the grab points may need to be repositioned off the current position of the graphic. * Called when the projection changes. IMPORTANT! Set the GrabPoints for the graphic here. */ public abstract void regenerate(Projection proj); public void repaintRender(Graphics g) { render(g); } /** */ public abstract void render(Graphics g); public boolean isXorRendering() { return xorRendering; } /** * Set whether the painting will occur using XOR rendering. If false, the mapbean will be repainted on every * movement. Looks better, but you need to make sure the repaint burden on the mapbean doesn't slow the drawing down * too much. * * @param xorRendering if true, XOR rendering will be used. Otherwise, the old location won't be drawn. */ public void setXorRendering(boolean xorRendering) { this.xorRendering = xorRendering; } /** * Set the current projection. */ public void setProjection(Projection proj) { projection = proj; // This is important. In the EditableOMGraphics, the // GrabPoints are set when regenerate is called. regenerate(proj); } /** * Get the current projection. */ public Projection getProjection() { return projection; } // Mouse Listener events // ////////////////////// /** */ public boolean mousePressed(MouseEvent e) { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mousePressed()"); } if (!mouseOnMap) { return false; } return stateMachine.getState().mousePressed(e); } /** */ public boolean mouseReleased(MouseEvent e) { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mouseReleased()"); } if (!mouseOnMap) { return false; } return stateMachine.getState().mouseReleased(e); } /** */ public boolean mouseClicked(MouseEvent e) { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mouseClicked()"); } if (!mouseOnMap) { return false; } return stateMachine.getState().mouseClicked(e); } boolean mouseOnMap = true; /** */ public void mouseEntered(MouseEvent e) { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mouseEntered()"); } mouseOnMap = true; stateMachine.getState().mouseEntered(e); } /** */ public void mouseExited(MouseEvent e) { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mouseExited()"); } mouseOnMap = false; stateMachine.getState().mouseExited(e); } // Mouse Motion Listener events // ///////////////////////////// /** */ public boolean mouseDragged(MouseEvent e) { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mouseDragged()"); } if (!mouseOnMap) { return false; } return stateMachine.getState().mouseDragged(e); } /** */ public boolean mouseMoved(MouseEvent e) { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mouseMoved()"); } if (!mouseOnMap) { return false; } return stateMachine.getState().mouseMoved(e); } /** */ public void mouseMoved() { if (DEBUG_DETAIL) { Debug.output(getClass().getName() + ".mouseMoved()"); } if (!mouseOnMap) { return; } stateMachine.getState().mouseMoved(); } /** * Add a EOMGListener. * * @param l EOMGListener */ public synchronized void addEOMGListener(EOMGListener l) { if (listeners == null) { listeners = new EOMGListenerSupport(this); } listeners.add(l); } /** * Remove a EOMGListener. * * @param l EOMGListener */ public synchronized void removeEOMGListener(EOMGListener l) { if (listeners == null) { return; } listeners.remove(l); } /** * The method to call if you want to let listeners know that the state has changed. Usually called when a graphic is * selected or not, so that GUIs can be directed. */ public void fireEvent(EOMGEvent event) { if (listeners != null) { listeners.fireEvent(event); } if (event.getStatus() == EOMGEvent.EOMG_UNDO) { updateCurrentState(null); } } /** * Create the event with a Cursor and/or message, and then fire it. * * @param cursor Cursor to be used. * @param message an instruction/error to be displayed to the user. * @param status the current status of the EditableOMGraphic. */ public void fireEvent(Cursor cursor, String message, int status) { fireEvent(cursor, message, null, status); } /** * Create the event with the Cursor, message and/or MouseEvent. * * @param cursor Cursor to be used. * @param message an instruction/error to be displayed to the user. * @param mouseEvent where that caused the EOMGEvent. May be null. * @param status the current status of the EditableOMGraphic. */ public void fireEvent(Cursor cursor, String message, MouseEvent mouseEvent, int status) { if (listeners != null) { EditableOMGraphic theSource = listeners.getEOMG(); EOMGEvent event = new EOMGEvent(theSource, cursor, message, mouseEvent, status); fireEvent(event); } } /** * Create the event with no cursor change or message to be displayed. */ public void fireEvent(int status) { fireEvent(null, null, null, status); } /** * If this EditableOMGraphic has parameters that can be manipulated that are independent of other EditableOMGraphic * types, then you can provide the widgets to control those parameters here. By default, this method returns null, * which indicates that you can extend this method to return a Component that controls parameters for the * EditableOMGraphic other than the GraphicAttribute parameters. Should return something like a toolbar, small. * * @return Component to control EOMG parameters, without the GraphicAttribute GUI. */ public Component getGUI() { return getGUI(null); } /** * If this EditableOMGraphic has parameters that can be manipulated that are independent of other EditableOMGraphic * types, then you can provide the widgets to control those parameters here. By default, returns the * GraphicAttributes GUI widgets. If you don't want a GUI to appear when a widget is being created/edited, then don't * call this method from the EditableOMGraphic implementation, and return a null Component from getGUI. * * @param graphicAttributes the GraphicAttributes that could be used to get the GUI widget from to control those * parameters for this EOMG. The GraphicAttributes used to provide the GUI widget, but it doesn't anymore. Subclasses * can take this opportunity to reset the GraphicAttributes interface for a new OMGraphic. * * @return Component to use to control parameters for this EOMG, generally a JPanel with a toolbar. */ public Component getGUI(GraphicAttributes graphicAttributes) { if (graphicAttributes != null) { graphicAttributes.setLineMenuAdditions(null); // Used to return the toolbar gui, now the color and line options provided on the right click menu. // return graphicAttributes.getGUI(); } return null; } public Point2D getProjectionPoint(MouseEvent e) { Point2D pnt = null; if (e instanceof MapMouseEvent && ((MapMouseEvent) e).mapIsRotated()) { MapMouseEvent mme = (MapMouseEvent) e; pnt = mme.getProjectedLocation(); } if (pnt == null) { pnt = new Point2D.Double(e.getX(), e.getY()); } return pnt; } public boolean isMouseEventTouching(MouseEvent e) { Point2D pnt = getProjectionPoint(e); return getGraphic().distance(pnt.getX(), pnt.getY()) <= 2; } public boolean isMouseEventTouchingTheEdge(MouseEvent e) { Point2D pnt = getProjectionPoint(e); return getGraphic().distanceToEdge(pnt.getX(), pnt.getY()) <= 2; } /** * This method should be overwritten for each EditableOMGraphic to save the state of the current OMGraphic, in case * the user wants to revert to this state. Called from the updateCurrentState method. * * @param whatHappened String describing what got you here. You can leave this null if you just want to go with the default. * @return UndoEvent reflecting current state. May be null if undo isn't handled. Returning null is the default * action. */ protected UndoEvent createUndoEventForCurrentState(String whatHappened) { if (whatHappened == null) { whatHappened = i18n.get(this.getClass(), "omgraphicUndoString", "Edit"); } try { return new OMGraphicUndoEvent(this, whatHappened); } catch (MissingResourceException mre) { // Return null so event won't be registered. return null; } } /** * Called by anything that knows that the EOMG has arrived at a stable state that should be kept for Undo actions. * * @param whatHappened a description of was done to get to this state. If null, the EOMG will create a default string * to use. */ public void updateCurrentState(String whatHappened) { UndoEvent undoEvent = createUndoEventForCurrentState(whatHappened); if (undoEvent != null && undoStack != null) { undoStack.setTheWayThingsAre(undoEvent); } } /** * @return the undoStack */ public UndoStack getUndoStack() { return undoStack; } /** * @param undoStack the undoStack to set */ public void setUndoStack(UndoStack undoStack) { this.undoStack = undoStack; } /** * A little flag to let the EOMG that a popup menu is up on the map. If the menu is up, and the menu is not clicked * on, we don't really want to deactivate the drawing tool right then - let a free click go by first, which will * dismiss the menu. * * @param popupIsUp */ public void setPopupIsUp(boolean popupIsUp) { this.popupIsUp = popupIsUp; } public boolean isPopupIsUp() { return this.popupIsUp; } public JComponent createAttributePanel(GraphicAttributes graphicAttributes) { // JPanel palette = new JPanel(); // GridBagLayout gridbag = new GridBagLayout(); // GridBagConstraints c = new GridBagConstraints(); // palette.setLayout(gridbag); JToolBar toolbar = new GridBagToolBar(); if (graphicAttributes != null) { int orientation = graphicAttributes.getOrientation(); toolbar.setOrientation(orientation); // if (orientation == SwingConstants.VERTICAL) { // c.gridwidth = GridBagConstraints.REMAINDER; // } } // gridbag.setConstraints(toolbar, c); // palette.add(toolbar); return toolbar; } /** * Generic undo event for basic OMGraphics. * * @author dietrick */ public static class OMGraphicUndoEvent implements UndoEvent { protected EditableOMGraphic eomg; protected OMGraphic stateHolder; protected String description; public OMGraphicUndoEvent(EditableOMGraphic eomg, String description) throws MissingResourceException { this.eomg = eomg; this.description = description; OMGraphic omg = eomg.getGraphic(); stateHolder = (OMGraphic) ComponentFactory.create(omg.getClass().getName()); if (stateHolder != null) { // stateHolder = new OMPoly(); stateHolder.restore(eomg.getGraphic()); } else { throw new MissingResourceException(eomg.getClass().getName() + " can't provide UndoEvents", eomg.getClass().getName(), ""); } } /* * (non-Javadoc) * * @see com.bbn.openmap.event.UndoEvent#getDescription() */ public String getDescription() { return description; } /* * (non-Javadoc) * * @see com.bbn.openmap.event.UndoEvent#setState() */ public void setState() { this.eomg.getGraphic().restore(stateHolder); setSubclassState(); this.eomg.regenerate(this.eomg.getProjection()); this.eomg.repaint(); } /** * Called from setState before repaint() is called, so subclasses can update anything in their EditableOMGraphic * state for the restored OMGraphic. */ protected void setSubclassState() { // noop, for subclasses to use so we don't waste a repaint. } /** * @return the stateHolder */ public OMGraphic getStateHolder() { return stateHolder; } /** * @param stateHolder the stateHolder to set */ public void setStateHolder(OMGraphic stateHolder) { this.stateHolder = stateHolder; } /** * @return the eomg */ public EditableOMGraphic getEomg() { return eomg; } /** * @param description the description to set */ public void setDescription(String description) { this.description = description; } } }