/******************************************************************************** * * * (c) Copyright 2010 Verizon Communications USA and The Open University UK * * * * This software is freely distributed in accordance with * * the GNU Lesser General Public (LGPL) license, version 3 or later * * as published by the Free Software Foundation. * * For details see LGPL: http://www.fsf.org/licensing/licenses/lgpl.html * * and GPL: http://www.fsf.org/licensing/licenses/gpl-3.0.html * * * * 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 com.compendium.ui.plaf; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Event; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.TimerTask; import java.util.Vector; import javax.swing.Action; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JTextArea; import javax.swing.JViewport; import javax.swing.RepaintManager; import javax.swing.SwingUtilities; import javax.swing.border.AbstractBorder; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicGraphicsUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.compendium.ProjectCompendium; import com.compendium.core.ICoreConstants; import com.compendium.core.datamodel.INodeSummary; import com.compendium.core.datamodel.Link; import com.compendium.core.datamodel.LinkProperties; import com.compendium.core.datamodel.Model; import com.compendium.core.datamodel.ModelSessionException; import com.compendium.core.datamodel.NodePosition; import com.compendium.core.datamodel.NodeSummary; import com.compendium.core.datamodel.ShortCutNodeSummary; import com.compendium.core.datamodel.View; import com.compendium.ui.ExecuteControl; import com.compendium.ui.FormatProperties; import com.compendium.ui.IUIArrange; import com.compendium.ui.IUIConstants; import com.compendium.ui.UIAudio; import com.compendium.ui.UIImages; import com.compendium.ui.UILine; import com.compendium.ui.UILink; import com.compendium.ui.UIMapViewFrame; import com.compendium.ui.UINode; import com.compendium.ui.UINodeTypeManager; import com.compendium.ui.UIUtilities; import com.compendium.ui.UIViewFrame; import com.compendium.ui.UIViewPane; import com.compendium.ui.dialogs.UINodeContentDialog; import com.compendium.ui.dialogs.UITrashViewDialog; import com.compendium.ui.edits.DeleteEdit; import com.compendium.ui.edits.PCEdit; import com.compendium.ui.linkgroups.UILinkType; import com.compendium.ui.movie.UIMovieMapViewFrame; import com.compendium.ui.movie.UIMovieMapViewPane; import com.compendium.ui.panels.UIHintNodeLabelPanel; import com.compendium.ui.popups.UINodeLinkingPopupMenu; /** * The UI class for the UINode Component * * @author Mohammed Sajid Ali / Michelle Bachler */ public class NodeUI extends ComponentUI implements MouseListener, MouseMotionListener, KeyListener, PropertyChangeListener { /** * class's own logger */ final Logger log = LoggerFactory.getLogger(getClass()); /** the colour to use for a selected node.*/ private static final Color SELECTED_COLOR = Color.yellow; /** The colour to use for selected text in the node label.*/ private static final Color SELECTED_TEXT_COLOR = Color.black; /** The colour to use for the label background when editing a node label.*/ private static final Color EDITING_COLOR = Color.white; /** The colour to use for the label background when text is selected.*/ private static final Color TSELECTED_COLOR = Color.blue; /** the colour to use for the text when text is selected.*/ private static final Color TSELECTED_TEXT_COLOR = Color.white; /** The colour to use for the border around the node if it has the focus.*/ private static final Color FOCUSED_COLOR = Color.blue; /** The colour to use for the node border when the node is rolled over with the mouse.*/ private static final Color BORDER_COLOR = Color.cyan; /** The colour to use for a map node border when it has an image in it.*/ private static final Color IMAGEMAP_COLOR = Color.darkGray; /** The extra gap to allow for the easy create arrows. */ public static final int ARROW_GAP = 9; /** Used for the date foramt when adding the current date to a node label.*/ private static SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); //$NON-NLS-1$ /** The UINode for this NodeUI */ protected UINode oNode; /** The view that this node is in*/ protected UIViewPane oViewPane; /** Key code that is being generated for. */ protected Action oRepeatKeyAction; /** The MouseListener registered for this class.*/ private MouseListener oMouseListener; /** The MouseMotionListener registered for this class.*/ private MouseMotionListener oMouseMotionListener; /** The KeyListener registered for this class.*/ private KeyListener oKeyListener; /** The ComponentListener registered for this class.*/ private ComponentListener oComponentListener; /** The PropertyChangeListener registered for this class.*/ private PropertyChangeListener oPropertyChangeListener; /** The rectangle defining this node oStartingBounds - used in mouse events.*/ private Rectangle oStartingBounds; /** lastMousePosX is the last mouseDragged location in absolute coordinate system.*/ private int lastMousePosX = 0; /** lastMousePosY is the last mouseDragged location in absolute coordinate system.*/ private int lastMousePosY = 0; /** _x & _y are the mousePressed location in absolute coordinate system.*/ private int _x, _y; /** __x & __y are the mousePressed location in source view's coordinate system.*/ private int __x, __y; /** Start point in view pane's coordinate system.*/ private Point ptStart; /** Used to hold the calculated maximum width required to paint this node.*/ private int nodeWidth = -1; /** Defines whether dragging is started with right mouse button*/ private boolean bDragging = false; /** if on the Mac, and a mock-right mouse was initialized (control-left mouse).*/ private boolean bIsMacRightMouse = false; /** Set to true while keyPressed is active. */ protected boolean bIsKeyDown; /** Current node edit dialog if opened from label editing - used to redirect key event to.*/ private UINodeContentDialog editDialog = null; /** Used when creating a temporary link while dragging to create a new link.*/ private UILink oUIConnectingLine = null; /** Used when creating one or more temporary links while dragging from multiple nodes to create new links.*/ private Vector oUIConnectingLines = new Vector(51); /** Are we in the process of opening a NodeContentDialog?*/ private boolean openingDialog = false; /** * Holds the letter types between reaching the label length limit * and opening the node contents dialog, so no letters are missed. * This buffer will be copied inot the detail box so typing can continue without interuption. */ private String dialogBuffer = ""; //$NON-NLS-1$ /** Holds the area for the node transclusion number.*/ private Rectangle transRectangle = null; /** Holds the area for the node detail text indicator.*/ private Rectangle textRectangle = null; /** Holds the area for the node code indicator.*/ private Rectangle codeRectangle = null; /** Holds the area for the node map weight indicator.*/ private Rectangle weightRectangle = null; /** Holds the area for the node icon.*/ private Rectangle iconRectangle = null; /** Holds the area for the node meeting replay indicator.*/ private Rectangle movieRectangle = null; /** The clipboard instance used when performing cut/copy/paste actions in the node label.*/ private Clipboard clipboard = null; /** The are for the caret in the node label.*/ private Rectangle caretRectangle = null; /** The area for the node label.*/ private Rectangle labelRectangle = null; /** The mouse sensitive area for quick node creation arrow on the right */ private Rectangle rightarrowRectangle = null; /** The mouse sensitive area for quick node creation arrow on the left */ private Rectangle leftarrowRectangle = null; /** The mouse sensitive area for quick node creation arrow upwards */ private Rectangle uparrowRectangle = null; /** The mouse sensitive area for quick node creation arrow downwards */ private Rectangle downarrowRectangle = null; /** The current position of the caret in the node label.*/ private int currentCaretPosition = 0; /** The previous contents of the label for undoind a cut/copy/paste to one level.*/ private String previousString = ""; //$NON-NLS-1$ /** Indocates if the node label is currently being edited - Is the node in edit mode?*/ private boolean editing = false; /** Indicates if a double-click was performed in the node label (for selecting a word).*/ private boolean doubleClicked = false; /** The x position the mouse was clicked to start label editing or move row.*/ private int editX = 0; /** The y position the mouse was clicked to start label editing or move row.*/ private int editY = 0; /** The starting position for text selection in the node label.*/ private int startSelection = -1; /** The stopping position for text selection in the node label.*/ private int stopSelection = -1; /** The current row the cursor is in, in the node label.*/ private int currentRow = 0; /** Was the up key pressed to move the cursor up a row in the node label?*/ private boolean caretUp = false; /** Was the down key pressed to move the cursor down a row in the node label?*/ private boolean caretDown = false; /** Not currently used.*/ private Thread cursorThread = null; /** Holds the last colour used for node background.*/ private Color lastColor = Color.black; /** Used for autoscrolling when dragged nodes hit the viewport edge.*/ private java.util.Timer timer = null; /** * Holds the list of the <code>TextRowElement</code> objects * with information on each row of text in the node label. */ private Vector<TextRowElement> textRowElements = null; /** The area for creating plus links from an argument node.*/ private Rectangle plusRectangle = null; /** The area to drag from to create con links from an Argument node.*/ private Rectangle minusRectangle = null; /** Indicates is a plus link should be created.*/ public boolean isPlus = false; /** Indicates if a con link should be created.*/ public boolean isMinus = false; /** Indicates if the paint methods should paint a transclucion indicator.*/ private boolean hasTrans = false; /** Indicates if the paint methods should paint a detail text indicator.*/ private boolean hasText = false; /** Indicates if the paint methods should paint a Code (tag) indicator.*/ private boolean hasCodes = false; /** Indicates if the paint methods should paint a map weight indicator.*/ private boolean hasWeight = false; /** Indicates if the paint methods should paint a node icon.*/ private boolean hasIcon = false; /** Indicates if the paint methods should paint a meeting replay indicator.*/ private boolean hasMovie = false; /** Used to hold extra width added to the node width depending which if any node indicator should be painted.*/ private int extraIconWidth = 0; /** Holds the last key pressed on this node.*/ private String sKeyPressed = ""; //$NON-NLS-1$ /** The shortcut key for the current platfrom.*/ private int shortcutKey; /** * Create a new NodeUI instance. * @param c, the component this is the ui for - NOT REALLY USED AT PRESENT HERE. */ public static ComponentUI createUI(JComponent c) { NodeUI nodeui = new NodeUI(); return nodeui; } /** * Constructor. Just calls super. */ public NodeUI() { super(); } /** * Return the UINode object associated with this ui. * @return com.compendium.ui.UINode, the node associated with this ui. */ public void setNode(UINode node) { oNode = node; } /***** USER INTERFACE INITIALIZATION METHODS *****/ /** * Run any install instructions for installing this UI. * @param c, the component this is the ui for. */ public void installUI(JComponent c) { super.installUI(c); oNode = (UINode)c; previousString = oNode.getText(); currentCaretPosition = previousString.length(); oViewPane = oNode.getViewPane(); clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); shortcutKey = ProjectCompendium.APP.shortcutKey; installListeners(c); installBorder(c); } /** * Install any Listener classes required by this UI. * @param c, the component to install the listeners for. */ protected void installListeners(JComponent c) { if ( (oMouseListener = createMouseListener( c )) != null ) { c.addMouseListener( oMouseListener ); } if ( (oMouseMotionListener = createMouseMotionListener( c )) != null ) { c.addMouseMotionListener( oMouseMotionListener ); } if ( (oKeyListener = createKeyListener( c )) != null ) { c.addKeyListener( oKeyListener ); } if ( (oPropertyChangeListener = createPropertyChangeListener( c )) != null ) { c.addPropertyChangeListener( oPropertyChangeListener ); } if ( (oComponentListener = createComponentListener( c )) != null ) { c.addComponentListener( oComponentListener ); } } /** * Just returns this class as the MouseListener. * @param c, the component to create the MouseLisener for. * @return MouseListener, the listener to use. */ protected MouseListener createMouseListener( JComponent c ) { return this; } /** * Just returns this class as the MouseMotionListener. * @param c, the component to create the MouseMotionLisener for. * @return MouseMotionListener, the listener to use. */ protected MouseMotionListener createMouseMotionListener( JComponent c ) { return this; } /** * Just returns this class as the KeyListener. * @param c, the component to create the KeyLisener for. * @return KeyListener, the listener to use. */ protected KeyListener createKeyListener(JComponent c) { return this; } /** * Just returns this class as the PropertyChangeListener. * @param c, the component to create the PropertyChangeLisener for. * @return PropertyChangeListener, the listener to use. */ protected PropertyChangeListener createPropertyChangeListener(JComponent c) { return this; } /** * Create and return a ComponentListener for use by this ui. * @param c, the component to create the ComponentLisener for. * @return ComponentListener, the listener to use. */ protected ComponentListener createComponentListener(JComponent c) { ComponentListener comp = new ComponentAdapter() { public void componentMoved(ComponentEvent evt) { if (FormatProperties.autoSearchLabel) { if (oViewPane == null) oViewPane = oNode.getViewPane(); if (oViewPane != null) { UIHintNodeLabelPanel panel = oViewPane.getLabelPanel(oNode.getNode().getId()); if (panel != null) { Point p = oNode.getLocation(); Dimension d = oNode.getSize(); int nX = p.x; int nY = p.y+d.height; panel.setLocation(nX, nY); } } } } }; return comp; } /** * Install the border used by this node. * @param c, the component to install the border for. * @see com.compendium.ui.plaf.NodeUI.NodeBorder */ public void installBorder(JComponent c) { c.setBorder(new NodeBorder()); } /** * Run any uninstall instructions for uninstalling this UI. * @param c, the component this is the ui to uninstall for. */ public void uninstallUI(JComponent c) { uninstallBorder(c); uninstallListeners(c); oNode = null; super.uninstallUI(c); } /** * Uninstall the border on this node by setting it to null. * @param c, the component this is the ui to uninstall for. */ public void uninstallBorder(JComponent c) { c.setBorder(null); } /** * Uninstall any listeners. * @param c, the component to uninstall the listeners for. */ protected void uninstallListeners(JComponent c) { if ( oPropertyChangeListener != null ) { c.removePropertyChangeListener( oPropertyChangeListener ); } if ( oMouseMotionListener!= null ) { c.removeMouseMotionListener( oMouseMotionListener ); } if ( oMouseListener!= null ) { c.removeMouseListener( oMouseListener ); } if ( oComponentListener!= null ) { c.removeComponentListener( oComponentListener ); } if ( oKeyListener != null ) { c.removeKeyListener( oKeyListener ); } oMouseListener = null; oMouseMotionListener = null; oPropertyChangeListener = null; oComponentListener = null; oKeyListener = null; } /***** PAINT METHODS *****/ /** * Paint clippedText at textX, textY with the nodes foreground color. * * @param g, the Graphics object to use to do the paint. * @param s, the String of text to paint. * @param textX, the x position to start the paint. * @param textY, the y position to start the paint * @see #paint * @see #paintDisabledText */ protected void paintEnabledText(UINode n, Graphics g, String s, int textX, int textY) { //g.setColor(n.getForeground()); BasicGraphicsUtils.drawString(g, s, '\0', textX, textY); } /** * Paint clippedText at textX, textY with background.lighter() and then * shifted down and to the right by one pixel with background.darker(). * * @param g, the Graphics object to use to do the paint. * @param s, the String of text to paint. * @param textX, the x position to start the paint. * @param textY, the y position to start the paint * @see #paint * @see #paintEnabledText */ protected void paintDisabledText(UINode n, Graphics g, String s, int textX, int textY) { Color background = n.getBackground(); g.setColor(background.brighter()); BasicGraphicsUtils.drawString(g, s, '\0', textX, textY); g.setColor(background.darker()); BasicGraphicsUtils.drawString(g, s, '\0', textX + 1, textY + 1); } /** * Is this node currently being edited? * @return boolean, true if it is, else false. */ public boolean isEditing() { return editing; } /** * Set the node in editing mode. * Make the caret position the edn of the current label text. */ public void setEditing() { setEditing(oNode.getText().length()); } /** * Set the node in editing mode. * @param int caretPosition, the position to set the caret to. */ public void setEditing(int caretPosition) { editing = true; startSelection = -1; stopSelection = -1; currentCaretPosition = caretPosition; doubleClicked = false; oNode.moveToFront(); oNode.setRollover(false); oNode.requestFocus(); } /** * Reset all the label editing variables. */ public void resetEditing() { editing = false; currentCaretPosition = -1; editX=0; editY=0; bDragging = false; doubleClicked = false; startSelection = -1; stopSelection = -1; } /** * This class holds information about each row of the node label. */ private class TextRowElement { String text = ""; //$NON-NLS-1$ int startPos = 0; Rectangle textR = null; boolean isRowWithCaret; public TextRowElement(String text, int startPos, Rectangle textR, boolean isRowWithCaret) { this.text = text; this.startPos = startPos; this.textR = textR; this.isRowWithCaret = isRowWithCaret; } public String getText() { return text; } public int getStartPosition() { return startPos; } public Rectangle getTextRect() { return textR; } public boolean getIsRowWithCaret() { return isRowWithCaret; } } /** * Paint the node. * * @param graphics, the Graphics object to use to do the paint. * @param c, the component being painted. * @see #paintEnabledText * @see #paintDisabledText * @see #drawText */ public void paint(Graphics graphics, JComponent c) { Graphics2D g = (Graphics2D)graphics; // CLEAR VARIABLES transRectangle = null; textRectangle = null; codeRectangle = null; weightRectangle = null; labelRectangle = null; movieRectangle = null; rightarrowRectangle = null; leftarrowRectangle = null; uparrowRectangle = null; downarrowRectangle = null; textRowElements = new Vector<TextRowElement>(); Color oldColor = null; UINode node = (UINode)c; String text = node.getText(); Font nodeFont = g.getFont(); FontMetrics fm = g.getFontMetrics(); Rectangle iconR = new Rectangle(); Rectangle textR = new Rectangle(); Rectangle viewR = new Rectangle(c.getSize()); Rectangle nodeR = new Rectangle(c.getSize()); Insets viewInsets = c.getInsets(); int maxWidth = nodeWidth; nodeR.x = viewInsets.left; nodeR.y = viewInsets.top; nodeR.width -= (viewInsets.left + viewInsets.right); nodeR.height -= (viewInsets.top + viewInsets.bottom); viewR.x = viewInsets.left+NodeUI.ARROW_GAP; viewR.y = viewInsets.top+NodeUI.ARROW_GAP; viewR.width -= (viewInsets.left + viewInsets.right + NodeUI.ARROW_GAP + NodeUI.ARROW_GAP); viewR.height -= (viewInsets.top + viewInsets.bottom + NodeUI.ARROW_GAP + NodeUI.ARROW_GAP); // DRAW ICON IF NOT HIDDEN int imageHeight = 0; int imageWidth = 0; ImageIcon icon = node.getIcon(); NodePosition position = node.getNodePosition(); boolean bSmallIcon = position.getShowSmallIcon(); if (position.getHideIcon() || icon == null) { if (text == null) return; iconR.width = 0; iconR.height = 0; iconR.x = maxWidth/2; iconR.y = viewR.y+1; textR.y = iconR.y + fm.getAscent(); } else { hasIcon = true; imageHeight = icon.getIconHeight(); imageWidth = icon.getIconWidth(); iconR.width = imageWidth+1; iconR.height = imageHeight+1; iconR.x = (maxWidth - imageWidth)/2; iconR.y = viewR.y+1; int type = node.getNode().getType(); if (type == ICoreConstants.ARGUMENT || type == ICoreConstants.ARGUMENT_SHORTCUT) { plusRectangle = new Rectangle(iconR.x, iconR.y, imageWidth/2, imageHeight); //g.fillRect(iconR.x, iconR.y+2, imageWidth/2, imageHeight/2); minusRectangle = new Rectangle(iconR.x+imageWidth/2, iconR.y+imageHeight/2, imageWidth/2, imageHeight/2); //g.fillRect(iconR.x+imageWidth/2, iconR.y+imageHeight/2, imageWidth/2, imageHeight/2); } // icon background will always be opaque oldColor = g.getColor(); if (node.isSelected()) { g.setColor(SELECTED_COLOR); g.drawRect(iconR.x-1, iconR.y-1, iconR.width, iconR.height); } g.setColor(oldColor); icon.paintIcon(c, g, iconR.x, iconR.y); //AffineTransform trans = nodeFont.getTransform(); //Font newFont = (new Font("Dialog", Font.BOLD, 10)).deriveFont(trans); // work around for Mac BUG with derive Font AffineTransform trans=new AffineTransform(); trans.setToScale(node.getScale(), node.getScale()); // FONT FOR THE ICON INDICATORS Point p1 = new Point(10, 10); try { p1 = (Point)trans.transform(p1, new Point(0, 0));} catch(Exception e) {log.info("can't convert font size (NodeUI.paint 1) \n\n"+e.getMessage()); } //$NON-NLS-1$ Font newFont = new Font("Dialog" , Font.BOLD, p1.x); //$NON-NLS-1$ g.setFont(newFont); FontRenderContext frc = g.getFontRenderContext(); NodeSummary nodeSumm = node.getNode(); // IF THIS NODE IS IN A MAP ASSOCIATED WITH A VIDEO // DRAW AN V if (hasMovie) { g.setColor(Color.red); int twidth = new Double((newFont.getStringBounds("M", frc)).getWidth()).intValue(); //$NON-NLS-1$ int pos = 20; int height = 12; int extra = 2; if (bSmallIcon) { extra = 3; pos = 12; height = 8; } movieRectangle = new Rectangle(iconR.x+iconR.width, (iconR.y+pos-(height/2)-extra), twidth, height); //g.fillRect(iconR.x+iconR.width, (iconR.y+pos-(height/2)-extra), twidth, height); g.drawString("M", iconR.x+iconR.width+1, iconR.y+pos); //$NON-NLS-1$ g.setFont(new Font("Dialog", Font.BOLD, 10)); //$NON-NLS-1$ } // DRAW * IF HAS DETAILS String detail = nodeSumm.getDetail(); detail = detail.trim(); if(hasText) { g.setColor(new Color(0, 91, 183)); //Font tFont = (new Font("Dialog", Font.BOLD, 18)).deriveFont(trans); // work around for Mac BUG with deriveFont Point p2 = new Point(18, 18); try { p2 = (Point)trans.transform(p2, new Point(0, 0));} catch(Exception e) {log.info("can't convert font size (NodeUI.paint 2) \n\n"+e.getMessage());} //$NON-NLS-1$ Font tFont = new Font("Dialog", Font.BOLD, p2.x); //$NON-NLS-1$ g.setFont(tFont); FontRenderContext frc2 = g.getFontRenderContext(); int twidth = new Double((newFont.getStringBounds("*", frc2)).getWidth()).intValue(); //$NON-NLS-1$ //int twidth = rfm.stringWidth("*")+3; int pos = 13; int height = 16; if (bSmallIcon) { pos = 11; height = 13; } textRectangle = new Rectangle(iconR.x+iconR.width, (iconR.y-5), twidth, height); //g.fillRect(iconR.x+iconR.width, (iconR.y-5), twidth, height); g.drawString("*", iconR.x+iconR.width+1, iconR.y+pos); //$NON-NLS-1$ g.setFont(newFont); } // DRAW TRANCLUSION NUMBER if(hasTrans) { int ncount = nodeSumm.getViewCount(); if (ncount > 1) { g.setColor(new Color(0, 0, 106)); String count = String.valueOf(ncount); //int nwidth = sfm.stringWidth(count)+2; int nwidth = new Double((newFont.getStringBounds(count, frc)).getWidth()).intValue(); int extra = 2; int back = 8; int theight = 14; if (bSmallIcon) { theight = 11; extra =4; back = 5; } transRectangle = new Rectangle(iconR.x+iconR.width, iconR.y+(iconR.height-back), nwidth, theight); //g.fillRect(iconR.x+iconR.width, iconR.y+(iconR.height-back), nwidth, theight); g.drawString(count, iconR.x+iconR.width+1, iconR.y+(iconR.height)+extra); } } textR.y = iconR.y + iconR.height + node.getIconTextGap() + fm.getAscent(); FontMetrics sfm = g.getFontMetrics(); // DRAW VIEW WEIGHT COUNT IF REQUESTED if (hasWeight && node.getNode() instanceof View) { g.setColor(new Color(0, 91, 183)); View view = (View)node.getNode(); String sCount = ""; //$NON-NLS-1$ try { sCount = String.valueOf(view.getNodeCount()); } catch(Exception ex) { log.info("Error: (NodeUI.paint)\n\n"+ex.getMessage());} //$NON-NLS-1$ int w = new Double((newFont.getStringBounds(sCount, frc)).getWidth()).intValue(); //int w = sfm.stringWidth(sCount); int h = sfm.getAscent(); int extra = 2; int back = 8; if (oNode.getNodePosition().getShowSmallIcon()) { extra = 4; back = 6; } weightRectangle = new Rectangle(iconR.x-(w+2), iconR.y+(iconR.height-back), w, h); //g.fillRect(iconR.x-(w+2), iconR.y+(iconR.height-back), w, h); g.drawString(sCount, iconR.x-(w+1), iconR.y+(iconR.height)+extra); } //if (node.getNode().getId().equals(ProjectCompendium.APP.getTrashBinID())) { // //} // DRAW 'T', if has Tags if (hasCodes) { g.setColor(new Color(0, 0, 106)); int twidth = new Double((newFont.getStringBounds("T", frc)).getWidth()).intValue(); //$NON-NLS-1$ //int twidth = sfm.stringWidth("T")+2; int pos = sfm.getAscent()-3; int theight = 14; if (bSmallIcon) { pos = 6; theight = 11; } codeRectangle = new Rectangle(iconR.x-(twidth+2), (iconR.y-3), twidth, theight); //g.fillRect(iconR.x-(twidth+2), (iconR.y-3), twidth, theight); g.drawString("T", iconR.x-(twidth+1), iconR.y+pos); //$NON-NLS-1$ } } iconRectangle = iconR; // DRAW TEXT int textWidth = text.length(); labelRectangle = viewR; labelRectangle.y = textR.y-fm.getAscent(); labelRectangle.height = viewR.height-textR.y+NodeUI.ARROW_GAP+fm.getAscent(); textR.width = fm.stringWidth( text ); textR.height = fm.getAscent()+fm.getDescent(); textR.x = viewR.x-NodeUI.ARROW_GAP; int startPos = 0; int stopPos = 0; // RE_SET THE FONT AND COLOR FOR TEXT g.setColor(Color.black); g.setFont(nodeFont); int wrapWidth = node.getNodePosition().getLabelWrapWidth(); if (wrapWidth <= 0) { wrapWidth = ((Model)ProjectCompendium.APP.getModel()).labelWrapWidth; } wrapWidth = wrapWidth+1; // Needs this for some reason. if (textWidth > wrapWidth) { int row = -1; String textLeft = text; boolean isRowWithCaret = false; while ( textLeft.length() > 0 ) { row ++; isRowWithCaret = false; startPos = stopPos; //int thisTextWidth = fm.stringWidth( textLeft ); int textLen = textLeft.length(); int curLen = wrapWidth; if (textLen < wrapWidth ) { curLen = textLen; } //int nextLen = 0; /*if (textLen > wrapWidth) { while(curLen <= textLen && curLen >= 1) { String next = textLeft.substring(0, curLen); nextLen = next.length(); //if (fm.stringWidth(next) < maxWidth) { if (nextLen < wrapWidth) { curLen++; } //else if (fm.stringWidth(next) >= maxWidth) { else if (nextLen >= wrapWidth) { curLen--; break; } } } else { curLen = textLen; } if (curLen == 0) { curLen = 1; } */ String nextText = textLeft.substring(0, curLen); if (curLen < textLen) { int lastSpace = nextText.lastIndexOf(" "); //$NON-NLS-1$ if (lastSpace != -1 && lastSpace != textLen) { curLen = lastSpace+1; nextText = textLeft.substring(0, curLen); textLeft = textLeft.substring(curLen); } else { nextText = textLeft.substring(0, curLen); textLeft = textLeft.substring(curLen); } } else { if (!textLeft.equals("")) //$NON-NLS-1$ nextText = textLeft; textLeft = ""; //$NON-NLS-1$ } stopPos += nextText.length(); // for dragging mouse to select if (node.hasFocus() && editing && (bDragging || doubleClicked)) { if (editY >= textR.y-fm.getAscent() && editY < (textR.y+fm.getDescent()) ) { int tX = textR.x; int tWidth = fm.stringWidth( nextText ); if (tWidth < iconR.width && iconR.width > maxWidth) { tX += (iconR.width-tWidth)/2; } else if (tWidth < maxWidth) { tX += (maxWidth-tWidth)/2; } int caretPos = 0; if (editX <= tX) caretPos = 0; else if (editX >= tX+tWidth && startPos+nextText.length() == text.length()) { caretPos = nextText.length(); } else if (editX >= tX+tWidth) { caretPos = nextText.length()-1; } else { int ind = 1; int prev = 0; while(ind <= nextText.length()) { String n = nextText.substring(0, ind); int charX = fm.stringWidth(n); if (editX >= (tX+prev) && editX <= (tX+charX) ) { if ( (tX+prev) - editX < editX - (tX+charX)) caretPos = ind-1; else caretPos = ind; break; } prev = charX; ind++; } } if (bDragging) { if (currentCaretPosition == -1) { currentCaretPosition = startPos+caretPos; startSelection = currentCaretPosition; stopSelection = currentCaretPosition; } else { // IF DRAGGING LEFT if (startPos+caretPos < currentCaretPosition) { if (stopSelection == -1) stopSelection = currentCaretPosition; currentCaretPosition = startPos+caretPos; if (startSelection == -1 || startSelection >= currentCaretPosition) startSelection = currentCaretPosition; else stopSelection = currentCaretPosition; } // IF DRAGGING RIGHT else { if (startSelection == -1) startSelection = currentCaretPosition; currentCaretPosition = startPos+caretPos; if (stopSelection == -1 || stopSelection < currentCaretPosition) stopSelection = currentCaretPosition; } } } // DOUBLE CLICK TO SELECT WORD if (doubleClicked) { int index = nextText.indexOf(" ", caretPos); //$NON-NLS-1$ if (index == -1) stopSelection = startPos + nextText.length(); else { stopSelection = startPos + index; } currentCaretPosition = stopSelection; String bit = nextText.substring(0, caretPos); index = bit.lastIndexOf(" "); //$NON-NLS-1$ if (index == -1) startSelection = startPos; else { startSelection = startPos + index+1; } doubleClicked = false; } } } drawText(g, fm, node, nextText, textR, iconR, maxWidth, startPos); // If mouse just clicked if (node.hasFocus() && currentCaretPosition == -1 && editing) { // IS THE CLICK IN THIS ROW if (editY >= textR.y-fm.getAscent() && editY < (textR.y+fm.getDescent()) ) { int tX = textR.x; int tWidth = fm.stringWidth( nextText ); if (tWidth < iconR.width && iconR.width > maxWidth) { tX += (iconR.width-tWidth)/2; } else if (tWidth < maxWidth) { tX += (maxWidth-tWidth)/2; } int caretPos = 0; if (editX <= tX) caretPos = 0; else if (editX >= tX+tWidth && startPos+nextText.length() == text.length()) { caretPos = nextText.length(); } else if (editX >= tX+tWidth) { caretPos = nextText.length()-1; } else { int ind = 1; int prev = 0; while(ind <= nextText.length()) { String n = nextText.substring(0, ind); int charX = fm.stringWidth(n); if (editX >= (tX+prev) && editX <= (tX+charX) ) { if ( (tX+prev) - editX < editX - (tX+charX)) caretPos = ind-1; else caretPos = ind; break; } prev = charX; ind++; } } currentCaretPosition = startPos+caretPos; currentRow = row; isRowWithCaret = true; setCaretRectangle(g, fm, textR, nextText, caretPos, iconR, maxWidth); } } else if (node.hasFocus() && editing) { if (caretUp) { // IF WE ARE ALREADY ON THE FIRST ROW if (currentRow == 0) { currentCaretPosition = 0; caretUp = false; } } if (caretDown) { // IF WE ARE ALREADY ON THE LAST ROW if (stopPos == text.length() && currentRow == row) { currentCaretPosition = text.length(); if (FormatProperties.autoSearchLabel) { UIHintNodeLabelPanel panel = oViewPane.getLabelPanel(oNode.getNode().getId()); if (panel != null) panel.focusList(); } caretDown = false; } } if (currentCaretPosition >= startPos && (currentCaretPosition < stopPos || currentCaretPosition == stopPos && stopPos == text.length())) { int caretPos = currentCaretPosition - startPos; setCaretRectangle(g, fm, textR, nextText, caretPos, iconR, maxWidth); currentRow = row; } isRowWithCaret = true; } TextRowElement element = new TextRowElement(nextText, startPos, new Rectangle(textR.x, textR.y, textR.width, textR.height), isRowWithCaret); textRowElements.addElement(element); textR.y += fm.getAscent() + fm.getDescent(); } if (caretUp) { if (currentRow > 0) { caretUp = false; recalculateCaretRectangle(g, fm, iconR, maxWidth, true); } } else if (caretDown) { if (currentRow < textRowElements.size()-1) { recalculateCaretRectangle(g, fm, iconR, maxWidth, false); if (FormatProperties.autoSearchLabel) { UIHintNodeLabelPanel panel = oViewPane.getLabelPanel(oNode.getNode().getId()); if (panel != null) panel.focusList(); } caretDown = false; } } } else { // if draggin mouse to select text or double clicked to select word calculate selection if (node.hasFocus() && editing && (bDragging || doubleClicked)) { int tX = textR.x; int tWidth = fm.stringWidth( text ); if (tWidth < iconR.width && iconR.width > maxWidth) { tX += (iconR.width-tWidth)/2; } else if (tWidth < maxWidth) { tX += (maxWidth-tWidth)/2; } int caretPos = 0; if (editX <= tX) caretPos = 0; else if (editX >= tX+tWidth) caretPos = text.length(); else { int ind = 1; int prev = 0; while(ind <= text.length()) { String n = text.substring(0, ind); int charX = fm.stringWidth(n); if (editX >= (tX+prev) && editX <= (tX+charX) ) { if ( editX-(tX+prev) < (tX+charX)-editX ) caretPos = ind-1; else caretPos = ind; break; } prev = charX; ind++; } } if (bDragging) { if (currentCaretPosition == -1) { currentCaretPosition = caretPos; startSelection = currentCaretPosition; stopSelection = currentCaretPosition; } else { // IF DRAGGING LEFT if (caretPos < currentCaretPosition) { if (stopSelection == -1) stopSelection = currentCaretPosition; currentCaretPosition = caretPos; if (startSelection == -1 || startSelection >= currentCaretPosition) startSelection = currentCaretPosition; else stopSelection = currentCaretPosition; } // IF DRAGGING RIGHT else { if (startSelection == -1) startSelection = currentCaretPosition; currentCaretPosition = caretPos; if (stopSelection == -1 || stopSelection < currentCaretPosition) stopSelection = currentCaretPosition; } } } // DOUBLE CLICK TO SELECT WORD if (doubleClicked) { int index = text.indexOf(" ", caretPos); //$NON-NLS-1$ if (index == -1) stopSelection = text.length(); else { stopSelection = index; } currentCaretPosition = stopSelection; String bit = text.substring(0, caretPos); index = bit.lastIndexOf(" "); //$NON-NLS-1$ if (index == -1) startSelection = 0; else { startSelection = index+1; } doubleClicked = false; } } drawText(g, fm, node, text, textR, iconR, maxWidth, 0); // If mouse just clicked if (node.hasFocus() && editing && currentCaretPosition == -1) { int tX = textR.x; int tWidth = fm.stringWidth( text ); if (tWidth < iconR.width && iconR.width > maxWidth) { tX += (iconR.width-tWidth)/2; } else if (tWidth < maxWidth) { tX += (maxWidth-tWidth)/2; } int caretPos = 0; if (editX <= tX) caretPos = 0; else if (editX >= tX+tWidth) caretPos = text.length(); else { int ind = 1; int prev = 0; while(ind <= text.length()) { String n = text.substring(0, ind); int charX = fm.stringWidth(n); if (editX >= (tX+prev) && editX <= (tX+charX) ) { if ( editX-(tX+prev) < (tX+charX)-editX ) caretPos = ind-1; else caretPos = ind; break; } prev = charX; ind++; } } currentCaretPosition = caretPos; currentRow = 0; setCaretRectangle(g, fm, textR, text, currentCaretPosition, iconR, maxWidth); } else if (node.hasFocus() && editing) { // IF UP/DOWN KEY PRESSED ON A SINGLE LINE LABEL GO HOME/END if (caretUp) { currentCaretPosition = 0; caretUp = false; } if (caretDown) { currentCaretPosition = text.length(); if (FormatProperties.autoSearchLabel) { UIHintNodeLabelPanel panel = oViewPane.getLabelPanel(oNode.getNode().getId()); if (panel != null) panel.focusList(); } caretDown = false; } currentRow = 0; setCaretRectangle(g, fm, textR, text, currentCaretPosition, iconR, maxWidth); } } if (editing) { // PAINT CARET if (caretRectangle != null) { Color oldCol = g.getColor(); g.setColor(Color.red); g.fillRect(caretRectangle.x, caretRectangle.y, caretRectangle.width, caretRectangle.height); g.setColor(oldCol); } // PAINT SUROUNDING BOX g.setColor(Color.blue); g.drawRect(labelRectangle.x, labelRectangle.y-1, labelRectangle.width, labelRectangle.height+1); } // ADD AUTO CREATE ARROWS if (node.isRollover() || node.hasFocus()) { ImageIcon rightarrow = UIImages.get(IUIConstants.RIGHT_ARROW_ICON); rightarrowRectangle = new Rectangle(); rightarrowRectangle.x=nodeR.x+nodeR.width-NodeUI.ARROW_GAP; rightarrowRectangle.y=nodeR.y+((nodeR.height/2)-(rightarrow.getIconHeight()/2)); rightarrowRectangle.height=rightarrow.getIconHeight(); rightarrowRectangle.width=rightarrow.getIconWidth(); rightarrow.paintIcon(c, g, rightarrowRectangle.x, rightarrowRectangle.y); ImageIcon leftarrow = UIImages.get(IUIConstants.LEFT_ARROW_ICON); leftarrowRectangle = new Rectangle(); leftarrowRectangle.x=nodeR.x; leftarrowRectangle.y=nodeR.y+((nodeR.height/2)-(leftarrow.getIconHeight()/2)); leftarrowRectangle.height=leftarrow.getIconHeight(); leftarrowRectangle.width=leftarrow.getIconWidth(); leftarrow.paintIcon(c, g, leftarrowRectangle.x, leftarrowRectangle.y); ImageIcon uparrow = UIImages.get(IUIConstants.UP_ARROW_ICON); uparrowRectangle = new Rectangle(); uparrowRectangle.x=nodeR.x+((nodeR.width/2)-(uparrow.getIconWidth()/2)); uparrowRectangle.y=nodeR.y; uparrowRectangle.height=uparrow.getIconHeight(); uparrowRectangle.width=uparrow.getIconWidth(); uparrow.paintIcon(c, g, uparrowRectangle.x, uparrowRectangle.y); ImageIcon downarrow = UIImages.get(IUIConstants.DOWN_ARROW_ICON); downarrowRectangle = new Rectangle(); downarrowRectangle.x=nodeR.x+((nodeR.width/2)-(downarrow.getIconWidth()/2)); downarrowRectangle.y=nodeR.y+nodeR.height-NodeUI.ARROW_GAP; downarrowRectangle.height=downarrow.getIconHeight(); downarrowRectangle.width=downarrow.getIconWidth(); downarrow.paintIcon(c, g, downarrowRectangle.x, downarrowRectangle.y); } } /** * A helper method for the <code>paint</code> method. Calulate the caretRectangle position when it is moving up or down a row. * * @param g, the current Graphics context. * @param fm, the font metrics to use. * @param iconR, the rectangle of the node icon. * @param maxWidth, the maximum width for the node. * @param isUp, is the caret moving up a row? True equals up a row, false equals down a row. */ private void recalculateCaretRectangle(Graphics g, FontMetrics fm, Rectangle iconR, int maxWidth, boolean isUp) { if (isUp) currentRow--; else currentRow++; TextRowElement element = (TextRowElement)textRowElements.elementAt(currentRow); Rectangle currR = element.getTextRect(); String currText = element.getText(); int currStart = element.getStartPosition(); Rectangle oldCaretRectangle = new Rectangle(caretRectangle.x, caretRectangle.y, caretRectangle.width, caretRectangle.height); int textWidth = fm.stringWidth( currText ); if (textWidth < iconR.width && iconR.width > maxWidth) { currR.x += (iconR.width-textWidth)/2; } else if (textWidth < maxWidth) { currR.x += (maxWidth-textWidth)/2; } if (oldCaretRectangle.x <= currR.x) { caretRectangle.x = currR.x; currentCaretPosition = currStart; } if (oldCaretRectangle.x >= currR.x+textWidth) { caretRectangle.x = currR.x+textWidth; currentCaretPosition = currStart+currText.length(); } else { // FIND THE CLOSEST CHAR TO THE ONE ABOVE WHERE THE CARET WAS int caretPos = 0; int ind = 1; int prev = 0; int length = currText.length(); while(ind <= length) { String n = currText.substring(0, ind); int charX = fm.stringWidth(n); if ( (currR.x+charX) > oldCaretRectangle.x ) { if ( oldCaretRectangle.x - (currR.x+prev) < (currR.x+charX)- oldCaretRectangle.x ) caretPos = ind-1; else caretPos = ind; break; } prev = charX; ind++; } currentCaretPosition = currStart+caretPos; caretRectangle.x = currR.x+fm.stringWidth(currText.substring(0, caretPos)) - 1; } caretRectangle.y = currR.y - fm.getAscent()+1; caretRectangle.width = oldCaretRectangle.width; caretRectangle.height = oldCaretRectangle.height; } /** * A helper method for the <code>paint</code> method. Calulate and set the caretRectangle. * * @param g, the current Graphics context. * @param fm, the font metrics to use. * @param textR, the rectangle of the current text area of this label row. * @param text, the row of text being addressed. * @param caretIndex, the current position of the caret in this row. * @param iconR, the rectangle of the node icon. * @param maxWidth, the maximum width for the node. * @param isUp, is the caret moving up a row? True equals up a row, false equals down a row. */ private void setCaretRectangle(Graphics g, FontMetrics fm, Rectangle textR, String text, int caretIndex, Rectangle iconR, int maxWidth) { if (caretIndex >= 0 && caretIndex <= text.length() ) { caretRectangle = new Rectangle(); int textX = textR.x; int textY = textR.y; int textWidth = fm.stringWidth( text ); int offset = 0; if (textWidth < iconR.width && iconR.width > maxWidth) { offset = (iconR.width-textWidth)/2; textX += offset; } else if (textWidth < maxWidth) { offset = (maxWidth-textWidth)/2; textX += offset; } caretRectangle.x = textX + fm.stringWidth(text.substring(0, caretIndex)); caretRectangle.y = textY - fm.getAscent()+1; caretRectangle.width = 1; caretRectangle.height = fm.getAscent()+1; } } /** * A helper method for the <code>paint</code> method. Paint a row of text. * * @param g, the current Graphics context. * @param fm, the font metrics to use. * @param node com.compendium.ui.UINode, the current node being painted. * @param text, the row of text being painted. * @param textR, the rectangle of the current text area of this label row. * @param caretIndex, the current position of the caret in this row. * @param iconR, the rectangle of the node icon. * @param maxWidth, the maximum width for the node. * @param startPos, the starting position of this row in the context of the while label. * @param isUp, is the caret moving up a row? True equals up a row, false equals down a row. */ private void drawText(Graphics g, FontMetrics fm, UINode node, String text, Rectangle textR, Rectangle iconR, int maxWidth, int startPos) { Color oldColor = null; if (text != null) { int textX = textR.x; int textY = textR.y; int textWidth = fm.stringWidth( text ); if (textWidth < iconR.width && iconR.width > maxWidth) { textR.width = textWidth; textX += (iconR.width-textWidth)/2; } else if (textWidth < maxWidth) { textR.width = textWidth; textX += (maxWidth-textWidth)/2; } // text background will always be opaque oldColor = g.getColor(); //int state = node.getNode().getState(); int stopPos = startPos+text.length(); if (node.isSelected()) { if (editing && (startSelection > -1 && stopSelection > -1 && stopSelection > startSelection) && (startSelection < stopPos) && (startSelection >= startPos || stopSelection > startPos) ) { // ONLY PAINT THE PART INSIDE SELECTION int begin = startSelection-startPos; int end = stopSelection-startPos; if (end > text.length()) end = text.length(); if (begin < 0) begin = 0; String beginText = text.substring(0, begin); String selText = text.substring(begin, end); String endText = text.substring(end); int beginWidth = fm.stringWidth(beginText); int selWidth = fm.stringWidth(selText); if (iconR.x < textR.x) { g.setColor(EDITING_COLOR); g.fillRect(iconR.x, textY-fm.getAscent(), beginWidth, textR.height); g.setColor(TSELECTED_COLOR); g.fillRect(iconR.x+beginWidth, textY-fm.getAscent(), selWidth, textR.height); g.setColor(EDITING_COLOR); g.fillRect(iconR.x+beginWidth+selWidth, textY-fm.getAscent(), iconR.width-selWidth, textR.height); } else { g.setColor(EDITING_COLOR); g.fillRect(textX, textY-fm.getAscent(), beginWidth, textR.height); g.setColor(TSELECTED_COLOR); g.fillRect(textX+beginWidth, textY-fm.getAscent(), selWidth, textR.height); g.setColor(EDITING_COLOR); g.fillRect(textX+beginWidth+selWidth, textY-fm.getAscent(), textR.width-selWidth, textR.height); } if (node.isEnabled()) { /* if (state == ICoreConstants.UNREADSTATE) { g.setColor(UNREAD_TEXT_COLOR); } else if (state == ICoreConstants.MODIFIEDSTATE) { g.setColor(MODIFIED_TEXT_COLOR); } else { g.setColor(SELECTED_TEXT_COLOR); } */ g.setColor(SELECTED_TEXT_COLOR); paintEnabledText(node, g, beginText, textX, textY); g.setColor(TSELECTED_TEXT_COLOR); paintEnabledText(node, g, selText, textX+beginWidth, textY); /* if (state == ICoreConstants.UNREADSTATE) { g.setColor(UNREAD_TEXT_COLOR); } else if (state == ICoreConstants.MODIFIEDSTATE) { g.setColor(MODIFIED_TEXT_COLOR); } else { g.setColor(SELECTED_TEXT_COLOR); } */ g.setColor(SELECTED_TEXT_COLOR); paintEnabledText(node, g, endText, textX+beginWidth+selWidth, textY); } else { // NEVER REACHED AT PRESENT g.setColor(SELECTED_TEXT_COLOR); paintDisabledText(node, g, beginText, textX, textY); g.setColor(TSELECTED_TEXT_COLOR); paintDisabledText(node, g, selText, textX+beginWidth, textY); g.setColor(SELECTED_TEXT_COLOR); paintDisabledText(node, g, endText, textX+beginWidth+selWidth, textY); } g.setColor(oldColor); } else { if (editing) { g.setColor(EDITING_COLOR); } else { g.setColor(SELECTED_COLOR); } if (iconR.x < textR.x) { g.fillRect(iconR.x, textY-fm.getAscent(), iconR.width, textR.height); } else { g.fillRect(textX, textY-fm.getAscent(), textR.width, textR.height); } /* if (state == ICoreConstants.UNREADSTATE) { g.setColor(UNREAD_TEXT_COLOR); } else if (state == ICoreConstants.MODIFIEDSTATE) { g.setColor(MODIFIED_TEXT_COLOR); } else { g.setColor(SELECTED_TEXT_COLOR); } */ g.setColor(SELECTED_TEXT_COLOR); if (node.isEnabled()) { paintEnabledText(node, g, text, textX, textY); } else { paintDisabledText(node, g, text, textX, textY); } g.setColor(oldColor); } } else { g.setColor(new Color(node.getNodePosition().getBackground())); g.fillRect(textX, textY-fm.getAscent(), textR.width, textR.height); g.setColor(oldColor); if (node.isEnabled()) { /* if (state == ICoreConstants.UNREADSTATE) { g.setColor(UNREAD_TEXT_COLOR); } else if (state == ICoreConstants.MODIFIEDSTATE) { g.setColor(MODIFIED_TEXT_COLOR); } else { g.setColor(new Color(node.getNodePosition().getForeground())); } */ g.setColor(new Color(node.getNodePosition().getForeground())); paintEnabledText(node, g, text, textX, textY); } else { // NEVER REACHED AT PRESENT paintDisabledText(node, g, text, textX, textY); } } } } /** * Calculate the requred dimensions of the given node. * Checks for icon and various node indicator extras when calculating. * @param node com.compendium.ui.UINode, the node to calculate the dimensions for. * @return Dimension, the dimension for the given node. */ private Dimension calculateDimension(UINode node) { hasTrans = false; hasText = false; hasCodes = false; hasWeight = false; hasMovie = false; String text = node.getText(); String id = node.getNode().getId(); Insets insets = node.getInsets(); int dx = insets.left + insets.right; int dy = insets.top + insets.bottom; Font font = node.getFont(); FontMetrics fm = node.getFontMetrics(font); Rectangle iconR = new Rectangle(); Rectangle textR = new Rectangle(); Rectangle viewR = new Rectangle(node.getSize()); viewR.x = insets.left; viewR.y = insets.top; NodePosition pos = node.getNodePosition(); Icon icon = node.getIcon(); if (pos.getHideIcon() || icon == null) { iconR.width=0; iconR.height=0; iconR.y = 1; textR.y = iconR.y + iconR.height + fm.getAscent(); } else { iconR.width = icon.getIconWidth()+1; iconR.height = icon.getIconHeight()+1; iconR.y = viewR.y+1; textR.y = iconR.y + iconR.height + node.getIconTextGap() + fm.getAscent(); // FOR EXTRA BIT ON SIDE //AffineTransform trans = font.getTransform(); //Font newFont = (new Font("Dialog", Font.BOLD, 10)).deriveFont(trans); // work around for Mac BUG with derive Font AffineTransform trans=new AffineTransform(); trans.setToScale(node.getScale(), node.getScale()); Point p1 = new Point(10, 10); try { p1 = (Point)trans.transform(p1, new Point(0, 0));} catch(Exception e) {log.info("can't convert font size (UINode.calculateDimension)\n\n"+e.getMessage()); } //$NON-NLS-1$ Font newFont = new Font("Dialog" , Font.BOLD, p1.x); //$NON-NLS-1$ NodeSummary nodeSumm = node.getNode(); FontRenderContext frc = UIUtilities.getDefaultFontRenderContext(); //LineMetrics metrics = newFont.getLineMetrics(message, frc); //float lineheight = metrics.getHeight(); // Total line height //float ascent = metrics.getAscent(); // Top of text to baseline String detail = nodeSumm.getDetail(); detail = detail.trim(); int type = node.getType(); float widestExtra = 0; if (pos.getShowTrans() && (nodeSumm.isInMultipleViews()) && (nodeSumm.getViewCount() > 1)) { hasTrans = true; Rectangle2D bounds = newFont.getStringBounds(String.valueOf(nodeSumm.getViewCount()), frc); float width = (float) bounds.getWidth(); if (width > widestExtra) { widestExtra = width; } } if (pos.getShowText() && (type != ICoreConstants.TRASHBIN && !detail.equals("") //$NON-NLS-1$ && !detail.equals(ICoreConstants.NODETAIL_STRING) && !id.equals(ProjectCompendium.APP.getInBoxID()))) { hasText = true; Point p2 = new Point(18, 18); try { p2 = (Point)trans.transform(p2, new Point(0, 0));} catch(Exception e) {} Font tFont = new Font("Dialog", Font.BOLD, p2.x); //$NON-NLS-1$ Rectangle2D bounds = tFont.getStringBounds("*", frc); //$NON-NLS-1$ float width = (float) bounds.getWidth(); if (width > widestExtra) { widestExtra = width; } } if (pos.getShowWeight() && View.isViewType(type)) { hasWeight = true; View view = (View)node.getNode(); try { Rectangle2D bounds = newFont.getStringBounds(String.valueOf(view.getNodeCount()), frc); float width = (float) bounds.getWidth(); if (width > widestExtra) { widestExtra = width; } } catch(Exception e){} } try { if (pos.getShowTags() && nodeSumm.getCodeCount() > 0) { hasCodes = true; Rectangle2D bounds = newFont.getStringBounds("T", frc); //$NON-NLS-1$ float width = (float) bounds.getWidth(); if (width > widestExtra) { widestExtra = width; } } } catch(Exception ex) { log.info("Error: (NodeUI.calculateDimension) \n\n"+ex.getMessage()); //$NON-NLS-1$ } if (hasMovie || hasTrans || hasText || hasWeight || hasCodes) { //add 4 to allow for drawing borders iconR.width += new Float(widestExtra).intValue()+4; } } int wrapWidth = pos.getLabelWrapWidth(); if (wrapWidth <= 0) { wrapWidth = ((Model)ProjectCompendium.APP.getModel()).labelWrapWidth; } wrapWidth = wrapWidth+1; // Needs this for some reason. int textWidth = text.length(); textR.width = textWidth; int widestLine = 0; textR.height = 0; textR.x = dx; if (textWidth > wrapWidth) { int loop = -1; String textLeft = text; while ( textLeft.length() > 0 ) { loop ++; int textLen = textLeft.length(); int curLen = wrapWidth; if (textLen < wrapWidth ) { curLen = textLen; } String nextText = textLeft.substring(0, curLen); if (curLen < textLen) { int lastSpace = nextText.lastIndexOf(" "); //$NON-NLS-1$ if (lastSpace != -1 && lastSpace != textLen) { curLen = lastSpace+1; nextText = textLeft.substring(0, curLen); textLeft = textLeft.substring(curLen); } else { nextText = textLeft.substring(0, curLen); textLeft = textLeft.substring(curLen); } textR.height += fm.getAscent()+fm.getDescent(); } else { if (!textLeft.equals("")) { //$NON-NLS-1$ textR.height += (fm.getDescent())*2; } nextText = textLeft; textLeft = ""; //$NON-NLS-1$ } int thisWidth = fm.stringWidth( nextText ); if ( thisWidth > widestLine) { widestLine = thisWidth; } } } else { widestLine = fm.stringWidth( text ); textR.height += (fm.getDescent()*2); } textR.width = widestLine; if (iconR.width > textR.width) { textR.width = iconR.width; } Dimension rv = iconR.union(textR).getSize(); //Add extra space for new node creation arrows rv.width += dx+1+ARROW_GAP+ARROW_GAP; rv.height += dy+ARROW_GAP+ARROW_GAP; nodeWidth = rv.width; return rv; } /** * Return the node's preferred size. * @param c, the component to return the preferred size for. * @return Dimension, the preferred size for the given node. */ public Dimension getPreferredSize(JComponent c) { UINode node = (UINode)c; String text = node.getText(); Icon icon = node.getIcon(); Insets insets = node.getInsets(); Font font = node.getFont(); int dx = insets.left + insets.right; int dy = insets.top + insets.bottom; if ((icon == null) && ((text == null) || ((text != null) && (font == null)))) { return new Dimension(dx, dy); } else if ((text == null) || ((icon != null) && (font == null))) { return new Dimension(icon.getIconWidth() + dx, icon.getIconHeight() + dy); } else { return calculateDimension(node); } } /** * Return the node's minimum size. Just calls <ocde>getPreferredSize</code>. * @param c, the component to return the minimum size for. * @return Dimension, the minimum size for the given node. * @see #getPreferredSize */ public Dimension getMinimumSize(JComponent c) { return getPreferredSize(c); } /** * Return the node's maximum size. Just calls <ocde>getPreferredSize</code>. * @param c, the component to return the maximum size for. * @return Dimension, the maximum size for the given node. * @see #getPreferredSize */ public Dimension getMaximumSize(JComponent c) { return getPreferredSize(c); } /***** EVENT HANDLING METHODS *****/ /** * Update the local and global mouse position information. * @param Point p, the mouse position. */ private void updateMousePosition(Point p ) { Point point = new Point(p.x, p.y); SwingUtilities.convertPointToScreen(point, oNode); ProjectCompendium.APP._x = point.x; ProjectCompendium.APP._y = point.y; } /** * Handles the initiation of drag and drop events. * @param evt, the associated MouseEvent. */ public void mousePressed(MouseEvent evt) { stopMovie(); Point p = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), null); // coordinates of the pressed event converted into the event's source object _x = p.x; _y = p.y; // coordinates of the event __x = evt.getX(); __y = evt.getY(); // set this up for when the mouse is dragged so coord can be updated to new position lastMousePosX = _x; lastMousePosY = _y; startSelection = -1; stopSelection = -1; doubleClicked = false; //the rectangle defining this node oStartingBounds oStartingBounds = oNode.getBounds(); // start dragging if left or right mouse button is pressed boolean isLeftMouse = SwingUtilities.isLeftMouseButton(evt); boolean isRightMouse = SwingUtilities.isRightMouseButton(evt); if (ProjectCompendium.isMac && ((evt.getButton() == 3 && evt.isShiftDown()) || (evt.getButton() == 1 && evt.isAltDown()))) { bIsMacRightMouse = true; isRightMouse = true; isLeftMouse = false; } if (isLeftMouse || isRightMouse ) { if (editing && isLeftMouse) { if (labelRectangle != null && labelRectangle.contains(evt.getX(), evt.getY())) { editX = evt.getX(); editY = evt.getY(); currentCaretPosition = -1; oNode.repaint(); return; } else { editing = false; oNode.getViewPane().hideLabels(); } } else { // convert event coordinats to the view pane coord system. ptStart = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), oNode.getViewPane()); if (isRightMouse) { int modifiers = evt.getModifiers(); if ((modifiers & MouseEvent.SHIFT_MASK) != 0) { oNode.setSelected(true); oNode.setRollover(false); } else { oNode.getViewPane().setSelectedNode(oNode,ICoreConstants.SINGLESELECT); oNode.setSelected(true); oNode.setRollover(false); } int type = oNode.getType(); if (type == ICoreConstants.ARGUMENT || type == ICoreConstants.ARGUMENT_SHORTCUT) { isPlus = false; isMinus = false; if (plusRectangle != null && minusRectangle != null) { if (plusRectangle.contains(__x, __y)) { isPlus = true; } else if (minusRectangle.contains(__x, __y)) { isMinus = true; } } } } } } } /** * Handles the single and double click events. * @param evt, the associated MouseEvent. */ public void mouseClicked(MouseEvent evt) { if (timer != null) { timer.cancel(); } int clickCount = evt.getClickCount(); int modifiers = evt.getModifiers(); boolean isRightMouse = SwingUtilities.isRightMouseButton(evt); boolean isLeftMouse = SwingUtilities.isLeftMouseButton(evt); if (ProjectCompendium.isMac && (evt.getButton() == 3 && evt.isShiftDown())) { isRightMouse = true; isLeftMouse = false; } oUIConnectingLine = null; oUIConnectingLines.removeAllElements(); final UIViewPane oViewPane = oNode.getViewPane(); if (isRightMouse || (ProjectCompendium.isMac && (modifiers & MouseEvent.CTRL_MASK) != 0)) { if(clickCount == 1) { oNode.requestFocus(); if ((modifiers & MouseEvent.SHIFT_MASK) != 0) { oViewPane.setSelectedNode(oNode,ICoreConstants.MULTISELECT); oNode.setSelected(true); oNode.setRollover(false); oNode.showPopupMenu(this, evt.getX(),evt.getY()); } else { oViewPane.setSelectedLink(null, ICoreConstants.DESELECTALL); oViewPane.setSelectedNode(oNode,ICoreConstants.SINGLESELECT); oNode.setSelected(true); oNode.setRollover(false); oNode.showPopupMenu(this, evt.getX(),evt.getY()); } } } else if (isLeftMouse) { //SELECT ALL ANCESTOR NODES if ( ((modifiers & MouseEvent.ALT_MASK) != 0) && ((modifiers & MouseEvent.SHIFT_MASK) != 0)) { oViewPane.selectAllAncestors(oNode); return; } //SELECT ALL CHILD NODES else if ((modifiers & MouseEvent.ALT_MASK) != 0 && (modifiers & MouseEvent.CTRL_MASK) == 0 && (modifiers & MouseEvent.SHIFT_MASK) == 0) { oViewPane.selectAllChildren(oNode); return; } int nX = evt.getX(); int nY = evt.getY(); // CHECK LABEL HAS BEEN CLICKED if (labelRectangle != null && labelRectangle.contains(nX, nY)) { if (clickCount == 1) { editing = true; editX = nX; editY = nY; startSelection = -1; stopSelection = -1; currentCaretPosition = -1; doubleClicked = false; oNode.moveToFront(); if (!oNode.isSelected()) { oViewPane.setSelectedNode(null, ICoreConstants.DESELECTALL); oViewPane.setSelectedLink(null, ICoreConstants.DESELECTALL); oViewPane.setSelectedNode(oNode, ICoreConstants.SINGLESELECT); oNode.setSelected(true); } oNode.setRollover(false); oNode.requestFocus(); return; } else if (clickCount == 2) { editing = true; editX = nX; editY = nY; startSelection = -1; stopSelection = -1; currentCaretPosition = -1; doubleClicked=true; oNode.moveToFront(); if (!oNode.isSelected()) { oViewPane.setSelectedNode(null, ICoreConstants.DESELECTALL); oViewPane.setSelectedLink(null, ICoreConstants.DESELECTALL); oViewPane.setSelectedNode(oNode, ICoreConstants.SINGLESELECT); oNode.setSelected(true); } oNode.setRollover(false); oNode.requestFocus(); return; } } else { editing = false; oViewPane.hideLabels(); doubleClicked = false; } if (oNode.isRollover() || oNode.hasFocus()) { // CHECK IF NODE ARROW AND IF IT HAS BEEN CLICKED if (rightarrowRectangle != null && rightarrowRectangle.contains(nX, nY)) { evt.consume(); int nType = ICoreConstants.POSITION; UINodeLinkingPopupMenu ns = new UINodeLinkingPopupMenu( ProjectCompendium.APP, UIUtilities.DIRECTION_RIGHT, oViewPane, oNode ); ns.show(oViewPane); } else if (leftarrowRectangle != null && leftarrowRectangle.contains(nX, nY)) { evt.consume(); int nType = ICoreConstants.POSITION; UINodeLinkingPopupMenu ns = new UINodeLinkingPopupMenu( ProjectCompendium.APP, UIUtilities.DIRECTION_LEFT, oViewPane, oNode); ns.show(oViewPane); return; } else if (uparrowRectangle != null && uparrowRectangle.contains(nX, nY)) { evt.consume(); int nType = ICoreConstants.POSITION; UINodeLinkingPopupMenu ns = new UINodeLinkingPopupMenu( ProjectCompendium.APP, UIUtilities.DIRECTION_UP, oViewPane, oNode ); ns.show(oViewPane); return; } else if (downarrowRectangle != null && downarrowRectangle.contains(nX, nY)) { evt.consume(); int nType = ICoreConstants.POSITION; UINodeLinkingPopupMenu ns = new UINodeLinkingPopupMenu( ProjectCompendium.APP, UIUtilities.DIRECTION_DOWN, oViewPane, oNode ); ns.show(oViewPane); return; } } // CHECK IF NODE HAS A M AND IF IT HAS BEEN CLICKED if (hasMovie) { if (movieRectangle != null && movieRectangle.contains(nX, nY)) { return; } } // CHECK IF NODE HAS A T AND IF IT HAS BEEN CLICKED if (hasText) { if (textRectangle != null && textRectangle.contains(nX, nY)) { openEditDialog(false); return; } } // CHECK IF NODE HAS A TRANSCLUSION NUMBER AND IF IT HAS BEEN CLICKED if (hasTrans) { if (transRectangle != null && transRectangle.contains(nX, nY)) { oNode.showViewsDialog(); return; } } // CHECK IF NODE HAS CODES C AND IF IT HAS BEEN CLICKED if (hasCodes) { if (codeRectangle != null && codeRectangle.contains(nX, nY)) { oNode.setSelected(true); oViewPane.setSelectedNode(oNode, ICoreConstants.MULTISELECT); ProjectCompendium.APP.onCodes(); return; } } // CHECK IF NODE HAS WEIGHTS AND IF IT HAS BEEN CLICKED if (hasWeight) { if (weightRectangle != null && weightRectangle.contains(nX, nY)) { ProjectCompendium.APP.getAudioPlayer().playAudio(UIAudio.ABOUT_ACTION); View view = null; int type = oNode.getNode().getType(); if( View.isShortcutViewType(type) ) { view = (View)(((ShortCutNodeSummary)oNode.getNode()).getReferredNode()); } else { view = (View)oNode.getNode(); } ProjectCompendium.APP.addViewToDesktop(view, oNode.getText()); return; } } if ((modifiers & MouseEvent.SHIFT_MASK) != 0) { oNode.moveToFront(); if(oNode.isSelected()) { oNode.setSelected(false); oViewPane.removeNode(oNode); // USUSALLY UIViewPane.setSelectedNode does this. // But there is no SINGLEDESELECT mode. // So I need to make sure the setNodeSelected methods get called correctly for the tags view. if (oViewPane.getNumberOfSelectedNodes() > 0) { ProjectCompendium.APP.setNodeSelected(true); } else { ProjectCompendium.APP.setNodeSelected(false); } } else { oNode.setSelected(true); oViewPane.setSelectedNode(oNode, ICoreConstants.MULTISELECT); } oNode.requestFocus(); } else { if ((clickCount > 1) || (FormatProperties.singleClick)) { openNode(); } else { if (clickCount == 1) { oNode.moveToFront(); oViewPane.setSelectedNode(null, ICoreConstants.DESELECTALL); oViewPane.setSelectedLink(null, ICoreConstants.DESELECTALL); oNode.setRollover(false); oNode.requestFocus(); oViewPane.setSelectedNode(oNode, ICoreConstants.SINGLESELECT); oNode.setSelected(true); } } } } } /** * Open this node depending on type. * If a map/list node, open the view. * If the trashbin open the Trashbin dialog. * If a reference node, open any associated reference in an external application. * If any other node, open the UINodeContentDialog for this node. */ public void openNode() { releaseFocusAndRollover(); int type = oNode.getNode().getType(); if (View.isViewType(type) || View.isShortcutViewType(type)) { ProjectCompendium.APP.getAudioPlayer().playAudio(UIAudio.ABOUT_ACTION); View view = null; if( View.isShortcutViewType(type) ) { view = (View)(((ShortCutNodeSummary)oNode.getNode()).getReferredNode()); } else { view = (View)oNode.getNode(); } UIViewFrame frame = ProjectCompendium.APP.addViewToDesktop(view, oNode.getText()); frame.setNavigationHistory(oNode.getViewPane().getViewFrame().getChildNavigationHistory()); stopMovie(); } else if(type == ICoreConstants.TRASHBIN) { UITrashViewDialog dlgTrash = new UITrashViewDialog(ProjectCompendium.APP, this); UIUtilities.centerComponent(dlgTrash, ProjectCompendium.APP); dlgTrash.setVisible(true); } else if (type == ICoreConstants.REFERENCE || type == ICoreConstants.REFERENCE_SHORTCUT) { try { oNode.getNode().setState(ICoreConstants.READSTATE); // Mark the node read (doesn't happen elsewhere) } catch (SQLException ex) {} catch (ModelSessionException ex) {}; String path = oNode.getNode().getSource(); if (path == null || path.equals("")) { //$NON-NLS-1$ openEditDialog(false); } else if (path.startsWith(ICoreConstants.sINTERNAL_REFERENCE)) { path = path.substring(ICoreConstants.sINTERNAL_REFERENCE.length()); int ind = path.indexOf("/"); //$NON-NLS-1$ if (ind != -1) { String sGoToViewID = path.substring(0, ind); String sGoToNodeID = path.substring(ind+1); UIUtilities.jumpToNode(sGoToViewID, sGoToNodeID, oNode.getViewPane().getViewFrame().getChildNavigationHistory()); } } else if (path.startsWith("http:") || path.startsWith("https:") || path.startsWith("www.") || //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ProjectCompendium.isLinux && (path.startsWith("fish:") || path.startsWith("ssh:") || path.startsWith("ftp:") || path.startsWith("smb:"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ if (ExecuteControl.launch( path ) == null) { openEditDialog(false); } } else { File file = new File(path); String sPath = path; if (file.exists()) { sPath = file.getAbsolutePath(); } // It the reference is not a file, just pass the path as is, as it is probably a special type of url. if (ExecuteControl.launch( sPath ) == null) { openEditDialog(false); } } } else { openEditDialog(false); } } /** * Handles drag and drop finish operations. * @param evt, the associated MouseEvent. */ public void mouseReleased(MouseEvent evt) { if (timer != null) { timer.cancel(); } Point p = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), null); boolean isRightMouse = SwingUtilities.isRightMouseButton(evt); boolean isLeftMouse = SwingUtilities.isLeftMouseButton(evt); if (ProjectCompendium.isMac && bIsMacRightMouse) { isRightMouse = true; isLeftMouse = false; } if (bDragging) { if (isLeftMouse && !evt.isAltDown()) { if (editing) { if (labelRectangle != null && labelRectangle.contains(evt.getX(), evt.getY())) { editX = evt.getX(); editY = evt.getY(); oNode.repaint(); } } else if (_x != p.x || _y != p.y) { UIViewPane viewPane = oNode.getViewPane(); // if oNode is selected then confirm move in view for all seleted nodes if (oNode.isSelected()) { for(Enumeration e = oNode.getViewPane().getSelectedNodes();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); Rectangle r = uinode.getBounds(); //rescale the position to actual position double scale = viewPane.getScale(); Point transPoint = new Point(r.x, r.y); transPoint = UIUtilities.scalePoint(r.x, r.y, scale); try { // This also set the value in the NodePosition object uinode.getViewPane().getView().setNodePosition(uinode.getNode().getId(), transPoint); } catch(Exception ex) { log.info(ex.getMessage()); } } } //otherwise just handle this node else { // node moved, update node's coordinates in view INodeSummary node = oNode.getNode(); if (node != null) { Rectangle r = oNode.getBounds(); //rescale the position to actual position Point transPoint = UIUtilities.scalePoint(r.x, r.y, viewPane.getScale()); //confirm move in the view try { // This also set the value in the NodePosition object oNode.getViewPane().getView().setNodePosition(oNode.getNode().getId(), transPoint); } catch(Exception ex) { log.info(ex.getMessage()); } } } } } else if (isRightMouse) { Point ptNew2 = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), oNode.getViewPane()); Component comp = SwingUtilities.getDeepestComponentAt(oNode.getViewPane(), ptNew2.x, ptNew2.y); if (comp instanceof UINode) { UINode node = (UINode)comp; NodeUI nodeui = node.getUI(); nodeui.drop(oNode); } clearDummyLinks(); } } _x = 0; _y = 0; __x = 0; __y = 0; lastMousePosX = 0; lastMousePosY = 0; oStartingBounds = null; bIsMacRightMouse=false; bDragging = false; } /** * Flushed updated view coordinates to the database. This is basically a bug fix that keeps label editing * from scooting the node's apparent X coordinate to the right or left. */ public void flushPosition() { UIViewPane viewPane = oNode.getViewPane(); INodeSummary node = oNode.getNode(); if (node != null) { Rectangle r = oNode.getBounds(); //rescale the position to actual position Point transPoint = UIUtilities.scalePoint(r.x, r.y, viewPane.getScale()); //confirm move in the view try { // This also set the value in the NodePosition object oNode.getViewPane().getView().setNodePosition(oNode.getNode().getId(), transPoint); } catch(Exception ex) { log.info(ex.getMessage()); } } } /** * Visualizes when a mouse enters the node. * Also, display any detail text for the node in the status bar. * @param evt, the associated MouseEvent. */ public void mouseEntered(MouseEvent evt) { if (timer != null) { timer.cancel(); } if (oViewPane == null) { oViewPane = oNode.getViewPane(); } if (oViewPane != null) { oViewPane.getUI().setCurrentNode(oNode, false); } Point p = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), oNode); updateMousePosition(p); oNode.setRollover(true); //Lakshmi (6/7/06) - updated status info to include author and date of creation String sStatus = ""; //$NON-NLS-1$ String author = oNode.getNode().getAuthor(); String creationDate = (UIUtilities.getSimpleDateFormat("dd, MMMM, yyyy h:mm a").format(oNode.getNode().getCreationDate()).toString()); //$NON-NLS-1$ String showtext = author + " " + creationDate +", " + //$NON-NLS-1$ //$NON-NLS-2$ oNode.getNode().getDetail(); if (showtext != null) { showtext = showtext.replace('\n',' '); showtext = showtext.replace('\r',' '); showtext = showtext.replace('\t',' '); sStatus = showtext; } ProjectCompendium.APP.setStatus(sStatus); } /** * Visualizes when a mouse exits the node. * @param evt, the associated MouseEvent. */ public void mouseExited(MouseEvent evt) { if (timer != null) { timer.cancel(); } if (oViewPane == null) { oViewPane = oNode.getViewPane(); } if (oViewPane != null) { oViewPane.getUI().setCurrentNode(oNode, true); } Point p = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), oNode); updateMousePosition(p); oNode.setToolTipText(null); ProjectCompendium.APP.setStatus(""); //$NON-NLS-1$ UIViewPane nodeViewPane = oNode.getViewPane(); oNode.setRollover(false); if (nodeViewPane != null) { nodeViewPane.hideCodes(); nodeViewPane.hideDetail(); if (FormatProperties.imageRollover && nodeViewPane.hasImages()) { if (oViewPane instanceof UIMovieMapViewPane) { UIMovieMapViewPane pane = (UIMovieMapViewPane)oViewPane; UIMovieMapViewFrame frame = (UIMovieMapViewFrame)pane.getViewFrame(); if (frame.wasMoviePlaying()) { frame.startTimeLine(true); } } nodeViewPane.hideImages(); } } if (nodeViewPane != null) nodeViewPane.repaint(); } /** * Invoked when a mouse is dragged (pressed and moved). * @param evt, the associated MouseEvent. */ public void mouseDragged(MouseEvent evt) { //log.info("Mouse dragged " + oNode.getNode().getLabel()+" at "+evt.getX()+" , "+evt.getY()+" time="+new Date()); boolean isRightMouse = SwingUtilities.isRightMouseButton(evt); boolean isLeftMouse = SwingUtilities.isLeftMouseButton(evt); if (ProjectCompendium.isMac && bIsMacRightMouse) { isRightMouse = true; isLeftMouse = false; } processMouseDragged(evt, isRightMouse, isLeftMouse); } private static String sDirection = ""; //$NON-NLS-1$ private static int oXPos = 0; private static int oYPos = 0; /** * Prcess a mouse is dragged (or moved on the Mac) * @param evt, the associated MouseEvent. * @param isRightMouse, is this a right mouse event. * @param isLeftMouse, is this a left mouse event. */ private void processMouseDragged(MouseEvent evt, boolean isRightMouse, boolean isLeftMouse) { bDragging = true; if (timer != null) { timer.cancel(); } int type = oNode.getViewPane().getView().getType(); if(View.isMapType(type)) { oViewPane = oNode.getViewPane(); if ( oStartingBounds == null ) { return; } if (isLeftMouse && !evt.isAltDown()) { if (editing) { if (labelRectangle != null && labelRectangle.contains(evt.getX(), evt.getY())) { editX = evt.getX(); editY = evt.getY(); oNode.repaint(); return; } } else { Point p = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), null); Dimension s = oNode.getParent().getSize(); int pWidth = s.width; int pHeight = s.height; int diffX = p.x - lastMousePosX; int diffY = p.y - lastMousePosY; // if this node is selected, then find out if any of the selected // nodes are going to go out of bounds, if so, then limit // the entire set of nodes so that does not happen. int minX, minY, maxX, maxY; minX = oStartingBounds.x + diffX; maxX = minX + oStartingBounds.width; minY = oStartingBounds.y + diffY; maxY = minY + oStartingBounds.height; // if the node is selected then we have to worry about all // the other selected nodes bc they will be moving as well. if (oNode.isSelected()) { for(Enumeration e = oNode.getViewPane().getSelectedNodes();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); NodeUI nodeui = (NodeUI)uinode.getUI(); // skip current node since we started w/this node. if(!nodeui.equals(this)) { Rectangle uinode_oStartingBounds = uinode.getBounds(); int uinode_newX = uinode_oStartingBounds.x + diffX; int uinode_newY = uinode_oStartingBounds.y + diffY; if (uinode_newX < minX) minX = uinode_newX; if (uinode_newX + uinode_oStartingBounds.width > maxX) maxX = uinode_newX + uinode_oStartingBounds.width; if (uinode_newY < minY) minY = uinode_newY; if (uinode_newY + uinode_oStartingBounds.height > maxY) maxY = uinode_newY + uinode_oStartingBounds.height; } } } // Make sure we stay in-bounds if (minX < 0) diffX = diffX - minX; if (minY < 0) diffY = diffY - minY; if (maxX > pWidth) diffX = diffX - (maxX - pWidth); if (maxY > pHeight) diffY = diffY - (maxY - pWidth); int newX = oStartingBounds.x + diffX; int newY = oStartingBounds.y + diffY; ///////////////MUTLIDRAG MOUSE LEFT BUTTON (MOVE)////////////////////////// oNode.setBounds(newX, newY, oNode.getWidth(), oNode.getHeight()); //Point ptNew = SwingUtilities.convertPoint((Component)evt.getSource(), // evt.getX(), evt.getY(), oNode.getViewPane()); oNode.updateLinks(); // If this node is selected then move the other selected nodes as well // otherwise just move this node. if (oNode.isSelected()) { for(Enumeration e = oNode.getViewPane().getSelectedNodes();e.hasMoreElements();) { //Point ptNewOther = null; UINode uinode = (UINode)e.nextElement(); NodeUI nodeui = (NodeUI)uinode.getUI(); if(!nodeui.equals(this)) { Rectangle uinode_oStartingBounds = uinode.getBounds(); int uinode_newX = uinode_oStartingBounds.x + diffX; int uinode_newY = uinode_oStartingBounds.y + diffY; uinode.setBounds(uinode_newX, uinode_newY, uinode.getWidth(), uinode.getHeight()); uinode.updateLinks(); } } } //update positions for next call to this function: // coordinates of the drag event converted into the event's source object lastMousePosX = p.x; lastMousePosY = p.y; //the rectangle defining this node oStartingBounds oStartingBounds = oNode.getBounds(); ///////////////END MUTLIDRAG MOUSE LEFT BUTTON (MOVE)////////////////////////// // IF DRAGGING OF NODE/LINK IS LEAVING THE SCREEN - SCROLL IT JViewport viewport = oViewPane.getViewFrame().getViewport(); Rectangle nodeBounds = oNode.getBounds(); Point parentPos = SwingUtilities.convertPoint((Component)oViewPane, nodeBounds.x, nodeBounds.y, viewport); viewport.scrollRectToVisible( new Rectangle( parentPos.x, parentPos.y, nodeBounds.width, nodeBounds.height ) ); } } else if (isRightMouse) { Point ptNew2 = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), oNode.getViewPane()); drawDummyLinks(ptNew2); } RepaintManager mgr = RepaintManager.currentManager(oViewPane); mgr.addDirtyRegion(oViewPane,0,0, oViewPane.getWidth(),oViewPane.getHeight()); mgr.paintDirtyRegions(); } } /** * This inner class is used to perform the autoscrolling of nodes when they hit the edge of the view. */ private class ScrollNodes extends TimerTask { public ScrollNodes() {} public void run() { JViewport oViewPort = oViewPane.getViewFrame().getViewport(); //Point parentPos = SwingUtilities.convertPoint((Component)oViewPane, oStartingBounds.x, oStartingBounds.y, oViewPort); int x=0; int y=0; if (sDirection.equals("UP")) { //$NON-NLS-1$ y-=1; } else if (sDirection.equals("DOWN")) { //$NON-NLS-1$ y+=1; } else if (sDirection.equals("LEFT")) { //$NON-NLS-1$ x-=1; } else if (sDirection.equals("RIGHT")) { //$NON-NLS-1$ x+=1; } int oX = oXPos+x; int oY = oYPos+y; oXPos = oX; oYPos = oY; Point parentPos2 = SwingUtilities.convertPoint(oViewPort, oX, oY, (Component)oViewPane); oViewPort.scrollRectToVisible( new Rectangle( oX, oY, oStartingBounds.width, oStartingBounds.height ) ); moveNodes(parentPos2.x, parentPos2.y); } } /** * Move this node and any selected nodes byt the passed amounts * @param diffX the amount to move the x position by. * @param diffY the amount to move the y position by. */ private void moveNodes(int diffX, int diffY) { int newX = oStartingBounds.x + diffX; int newY = oStartingBounds.y + diffY; oNode.setBounds(newX, newY, oNode.getWidth(), oNode.getHeight()); oNode.updateLinks(); oStartingBounds = oNode.getBounds(); // If this node is selected then move the other selected nodes as well // otherwise just move this node. if (oNode.isSelected()) { for(Enumeration e = oNode.getViewPane().getSelectedNodes();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); NodeUI nodeui = (NodeUI)uinode.getUI(); if(!nodeui.equals(this)) { Rectangle uinode_oStartingBounds = uinode.getBounds(); int uinode_newX = uinode_oStartingBounds.x + diffX; int uinode_newY = uinode_oStartingBounds.y + diffY; uinode.setBounds(uinode_newX, uinode_newY, uinode.getWidth(), uinode.getHeight()); uinode.updateLinks(); } } } } /** * Draws dummy links displayed while dragging to create links between nodes * @param Point fromPoint is the point to draw the dummy link to. * This point is given in the system screen co-ordinates */ public void drawDummyLinks(Point toPoint) { Point ptNew = toPoint; oNode.setRollover(false); String os = ProjectCompendium.platform.toLowerCase(); oViewPane = oNode.getViewPane(); String sAuthor = oViewPane.getCurrentAuthor(); ///////////////MUTLIDRAG MOUSE RIGHT BUTTON (LINK)////////////////////////// //draw drag line which is a temp link if(oUIConnectingLines.isEmpty()) { for(Enumeration e = oNode.getViewPane().getSelectedNodes();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); NodeUI nodeui = (NodeUI)uinode.getUI(); Rectangle rFrom = oNode.getBounds(); Point ptFromCenter = new Point(rFrom.x+(rFrom.width/2), rFrom.y+(rFrom.height/2)); //create a dummy UINode Date date = new Date(); UINode dummyToNode = new UINode(new NodePosition(oNode.getViewPane().getView(), oNode.getNode(), ptFromCenter.x, ptFromCenter.y, date, date), sAuthor); UILink link = new UILink(uinode, dummyToNode, UIUtilities.getLinkType(uinode)); ((UILine)link).setTo(ptNew); oNode.getViewPane().add(link, (UIViewPane.LINK_LAYER)); link.setBounds(link.getPreferredBounds()); oUIConnectingLines.addElement((Object)link); } } else { int count = oUIConnectingLines.size(); for (int j=0; j<count; j++) { UILink link = (UILink)oUIConnectingLines.elementAt(j); ((UILine)link).setTo(ptNew); link.setBounds(link.getPreferredBounds()); link.repaint(); } } ///////////////SINGLEDRAG MOUSE RIGHT BUTTON (LINK)////////////////////////// //draw drag line which is a temp link if(oUIConnectingLine == null) { Rectangle rFrom = oNode.getBounds(); Point ptFromCenter = new Point(rFrom.x+(rFrom.width/2), rFrom.y+(rFrom.height/2)); //create a dummy UINode Date date = new Date(); UINode dummyToNode = new UINode(new NodePosition(oNode.getViewPane().getView(), oNode.getNode(), ptFromCenter.x, ptFromCenter.y, date, date), sAuthor); oUIConnectingLine = new UILink(oNode, dummyToNode, UIUtilities.getLinkType(oNode)); ((UILine)oUIConnectingLine).setTo(ptNew); oNode.getViewPane().add(oUIConnectingLine, (UIViewPane.LINK_LAYER)); oUIConnectingLine.setBounds(oUIConnectingLine.getPreferredBounds()); } else { ((UILine)oUIConnectingLine).setTo(ptNew); oUIConnectingLine.setBounds(oUIConnectingLine.getPreferredBounds()); oUIConnectingLine.repaint(); } // IF DRAGGING OF LINK IS LEAVING THE SCREEN - SCROLL IT JViewport viewport = oViewPane.getViewFrame().getViewport(); Point nodePos = ptNew; Point parentPos = SwingUtilities.convertPoint((Component)oViewPane, nodePos.x, nodePos.y, viewport); Rectangle parentBounds = new Rectangle(parentPos); viewport.scrollRectToVisible( new Rectangle( parentPos.x, parentPos.y, 5, 5 ) ); } /** * Clears any dummy links created while node linking is in transit. */ public void clearDummyLinks() { //reset the connecting line used in for linking if(oUIConnectingLine != null) { oNode.getViewPane().remove(oUIConnectingLine); oUIConnectingLine = null; } if(oUIConnectingLines.size() > 0) { int j=0; for(Enumeration e = oNode.getViewPane().getSelectedNodes();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); uinode.getViewPane().remove((UILink)oUIConnectingLines.elementAt(j)); j++; } oUIConnectingLines.removeAllElements(); } for(Enumeration e = oNode.getViewPane().getSelectedNodes();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); NodeUI nodeui = (NodeUI)uinode.getUI(); } bDragging = false; } /** * Invoked when a mouse is moved in a component. * @param evt, the associated MouseEvent. */ public void mouseMoved(MouseEvent evt) { Point p = new Point(0, 0); if (oNode != null) p = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), oNode); else p = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), null); updateMousePosition(p); int nX = evt.getX(); int nY = evt.getY(); oViewPane = oNode.getViewPane(); if (oViewPane != null) { Point p2 = SwingUtilities.convertPoint((Component)evt.getSource(), evt.getX(), evt.getY(), oViewPane); if (FormatProperties.imageRollover && hasIcon && iconRectangle != null && iconRectangle.contains(nX, nY) ) { NodeSummary node = oNode.getNode(); boolean showImage = false; int nodeType = node.getType(); if (nodeType == ICoreConstants.REFERENCE || nodeType == ICoreConstants.REFERENCE_SHORTCUT) { String img = node.getImage(); if (img == null || img.equals("")) { //$NON-NLS-1$ String ref = node.getSource(); if ( UIImages.isImage(ref) && oNode.hasImageBeenScaled()) showImage = true; } else { if (oNode.hasImageBeenScaled()) { showImage = true; } } } else if (View.isViewType(nodeType) || View.isShortcutViewType(nodeType)) { String img = node.getImage(); if (img != null && !img.equals("") && oNode.hasImageBeenScaled()) { //$NON-NLS-1$ showImage = true; } } if (showImage) { oViewPane.hideCodes(); oViewPane.hideViews(); oViewPane.hideDetail(); // check to see if moviemap with timeline playing stopMovie(); oViewPane.showImage(oNode.getNode(), p2.x, p2.y); } } else { oViewPane.hideDetail(); } if (hasText && textRectangle != null && textRectangle.contains(nX, nY) ) { //oNode.setToolTipText("Click to open node details"); oViewPane.hideCodes(); oViewPane.hideViews(); oViewPane.hideImages(); oViewPane.showDetail(oNode.getNode(), p2.x, p2.y); } else { oViewPane.hideDetail(); } if (hasTrans && transRectangle != null && transRectangle.contains(nX, nY) ) { //oNode.setToolTipText("Number of transclusion. Click to open Views list"); oViewPane.hideCodes(); oViewPane.hideDetail(); oViewPane.hideImages(); // oViewPane.hideViews(); oViewPane.showViews(oNode.getNode(), p2.x, p2.y); } else { //oViewPane.hideViews(); } if (hasCodes && codeRectangle != null && codeRectangle.contains(nX, nY) ) { //oNode.setToolTipText("Click to open codes list"); oViewPane.hideViews(); oViewPane.hideDetail(); oViewPane.hideImages(); oViewPane.showCodes(oNode.getNode(), p2.x, p2.y); } else { oViewPane.hideCodes(); } } } /** * If the parent of this node is a movie map, and the movie is playing, * stop the movie playing. */ private void stopMovie() { if (oViewPane instanceof UIMovieMapViewPane) { UIMovieMapViewPane pane = (UIMovieMapViewPane)oViewPane; UIMovieMapViewFrame frame = (UIMovieMapViewFrame)pane.getViewFrame(); if (frame.isPlaying()) { frame.stopTimeLine(true); } } } // DND EVENTS /** * Called if the user has modified the current drop gesture. * <P> * HERE THE METHOD DOES NOTHING. * @param e the <code>DropTargetDragEvent</code> */ public void dropActionChanged(DropTargetDragEvent evt) {} /** * Called while a drag operation is ongoing, when the mouse pointer has * exited the operable part of the drop site for the * <code>DropTarget</code> registered with this listener. * <p> * HERE THE METHOD DOES NOTHING. * @param e the <code>DropTargetEvent</code> */ public void dragExit(DropTargetEvent evt) { if (oNode != null) oNode.setRollover(false); } /** * Called when a drag operation is ongoing, while the mouse pointer is still * over the operable part of the drop site for the <code>DropTarget</code> * registered with this listener. * <p> * HERE THE METHOD DOES NOTHING. * * @param e the <code>DropTargetDragEvent</code> */ public void dragOver(DropTargetDragEvent evt) {} /** * Called while a drag operation is ongoing, when the mouse pointer enters * the operable part of the drop site for the <code>DropTarget</code> * registered with this listener. * <p> * HERE THE METHOD DOES NOTHING. * @param e the <code>DropTargetDragEvent</code> */ public void dragEnter(DropTargetDragEvent evt) { if (oNode != null) oNode.setRollover(true); } /** * Called when the drag operation has terminated with a drop on * the operable part of the drop site for the <code>DropTarget</code> * registered with this listener. * <p> * Invoked when a node is dragged and dropped over this component to link them. * <P> * @param e the <code>DropTargetDropEvent</code> * // METHOD NOT USED AT PRESENT */ public void drop(DropTargetDropEvent evt) { oViewPane = oNode.getViewPane(); boolean audioPlayed = false; UINode from = null; try { Transferable trans = evt.getTransferable(); Object obj = trans.getTransferData(UINode.nodeFlavor); if (obj != null && (obj instanceof String)) { String nodeID = (String)obj; if (oViewPane != null) { Object obj2 = oViewPane.get(nodeID); if (obj2 instanceof UINode) { from = (UINode)obj2; } } } } catch(IOException io) { io.printStackTrace(); } catch(UnsupportedFlavorException io) { io.printStackTrace(); } UINode to = oNode; //if either node is null, or you are trying to link to yourself, return if (from == null || to == null) { evt.getDropTargetContext().dropComplete(true); return; } //dont link with the trashbin NodeSummary fromNode = from.getNode(); NodeSummary toNode = to.getNode(); String inbox = ProjectCompendium.APP.getInBoxID(); if( (fromNode == null || fromNode.getType() == ICoreConstants.TRASHBIN) || (toNode ==null || toNode.getType() == ICoreConstants.TRASHBIN) || (fromNode.getId()).equals(toNode.getId()) || (fromNode.getId().equals(inbox)) || (toNode.getId().equals(inbox))) { evt.getDropTargetContext().dropComplete(true); return; } if (!from.containsLink(to)) { //create a link in the datamodel layer String linktype = UIUtilities.getLinkType(from); UILinkType oLinkType = ProjectCompendium.APP.oLinkGroupManager.getLinkType(linktype); String sLabel = ""; //$NON-NLS-1$ if (oLinkType != null) sLabel = oLinkType.getLabel(); LinkProperties props = UIUtilities.getLinkProperties(linktype); createLink(from, to, linktype, sLabel, props); } else { ProjectCompendium.APP.getAudioPlayer().playAudio(UIAudio.ABORT_ACTION); audioPlayed = true; } UINode nextFrom = oNode; NodeSummary nextFromNode = null; if (oViewPane != null) { // MULTISELECT Drop (if there has been multi-selection!)// for(Enumeration e = oViewPane.getSelectedNodes();e.hasMoreElements();) { nextFrom = (UINode)e.nextElement(); if (nextFrom == null || nextFrom.getNode().getId().equals(toNode.getId())) continue; nextFromNode = nextFrom.getNode(); if( nextFromNode == null || nextFromNode.getType() == ICoreConstants.TRASHBIN || nextFromNode.getId().equals(inbox)) { continue; } if (!nextFrom.equals(from)) { if (!nextFrom.containsLink(to)) { String linktype = UIUtilities.getLinkType(nextFrom); UILinkType oLinkType = ProjectCompendium.APP.oLinkGroupManager.getLinkType(linktype); String sLabel = ""; //$NON-NLS-1$ if (oLinkType != null) sLabel = oLinkType.getLabel(); LinkProperties props = UIUtilities.getLinkProperties(linktype); createLink(nextFrom, to, linktype, sLabel, props); } } } } if(!audioPlayed) ProjectCompendium.APP.getAudioPlayer().playAudio(UIAudio.LINKING_ACTION); evt.getDropTargetContext().dropComplete(true); } /** * Invoked when a node is dragged and dropped over this component to link them, * @param source com.compendium.ui.UINode, the source node for the drag. */ public void drop(UINode source) { oViewPane = oNode.getViewPane(); boolean audioPlayed = false; UINode from = source; UINode to = oNode; //if either node is null, or you are trying to link to yourself, return if (from == null || to == null) { return; } //dont link with the trashbin NodeSummary fromNode = from.getNode(); NodeSummary toNode = to.getNode(); String inbox = ProjectCompendium.APP.getInBoxID(); if( (fromNode == null || fromNode.getType() == ICoreConstants.TRASHBIN) || (toNode == null || toNode.getType() == ICoreConstants.TRASHBIN) || (fromNode.getId().equals(inbox)) || (toNode.getId().equals(inbox)) || (fromNode.getId()).equals(toNode.getId())) { return; } if (!from.containsLink(to)) { //create a link in the datamodel layer String linktype = UIUtilities.getLinkType(from); UILinkType oLinkType = ProjectCompendium.APP.oLinkGroupManager.getLinkType(linktype); String sLabel = ""; //$NON-NLS-1$ if (oLinkType != null) sLabel = oLinkType.getLabel(); LinkProperties props = UIUtilities.getLinkProperties(linktype); //props.setArrowType(ICoreConstants.ARROW_TO); createLink(from, to, linktype, sLabel, props); } else { ProjectCompendium.APP.getAudioPlayer().playAudio(UIAudio.ABORT_ACTION); audioPlayed = true; } UINode nextFrom = oNode; NodeSummary nextFromNode = null; if (oViewPane != null) { // MULTISELECT Drop (if there has been multi-selection!)// for(Enumeration e = oViewPane.getSelectedNodes();e.hasMoreElements();) { nextFrom = (UINode)e.nextElement(); if (nextFrom == null || nextFrom.getNode().getId().equals(toNode.getId())) continue; nextFromNode = nextFrom.getNode(); if( nextFromNode == null || nextFromNode.getType() == ICoreConstants.TRASHBIN || oNode.getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) { continue; } if (!nextFrom.equals(from)) { if (!nextFrom.containsLink(to)) { String linktype = UIUtilities.getLinkType(nextFrom); UILinkType oLinkType = ProjectCompendium.APP.oLinkGroupManager.getLinkType(linktype); String sLabel = ""; //$NON-NLS-1$ if (oLinkType != null) sLabel = oLinkType.getLabel(); LinkProperties props = UIUtilities.getLinkProperties(linktype); createLink(nextFrom, to, linktype, sLabel, props); } } } } if(!audioPlayed) ProjectCompendium.APP.getAudioPlayer().playAudio(UIAudio.LINKING_ACTION); } /** * Add the passed string to the node label at the point of the current caret position. * If the user set label length has been reached, and they have request it, * open the NodeContentDialog and place the text in the details box. * * @param key, the string to add to the label. */ private void addCharToLabel(String key) { if (oNode.getNode().getType() != ICoreConstants.TRASHBIN && !oNode.getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) { String oldText = oNode.getText(); if (startSelection > -1 && stopSelection > -1 && stopSelection > startSelection) { String text = oldText.substring(0, startSelection) + oldText.substring(stopSelection); currentCaretPosition = startSelection; startSelection = -1; stopSelection = -1; oldText = text; } if(oldText.equals(ICoreConstants.NOLABEL_STRING)) { oldText = ""; //$NON-NLS-1$ currentCaretPosition = 0; } String newText = ""; //$NON-NLS-1$ //newText = oldText + key; if (currentCaretPosition < oldText.length()) newText = oldText.substring(0, currentCaretPosition) + key + oldText.substring(currentCaretPosition); else newText = oldText + key; currentCaretPosition ++; Model oModel = (Model)ProjectCompendium.APP.getModel(); boolean bDetailPopup = oModel.detailPopup; int nLabelPopupLength = oModel.labelPopupLength; if(bDetailPopup && newText.length() >= nLabelPopupLength) { if ( openingDialog ) { dialogBuffer += key; } else if (editDialog != null && editDialog.isVisible()) { JTextArea textArea = editDialog.getDetailField(); textArea.setText(textArea.getText()+key); textArea.setCaretPosition(textArea.getText().length()); } else { // TIMING HEAR WAS REALLY IMPORTANT HENCE VARIOUS ODDITIES openingDialog = true; dialogBuffer += key; openEditDialog(true); } return; } previousString = oldText; oNode.setText(newText, true); // mlb: Database deferred update ProjectCompendium.APP.setStatus(newText); if (FormatProperties.autoSearchLabel && (!bDetailPopup || bDetailPopup && newText.length() < nLabelPopupLength)) { if (oViewPane != null && oNode != null) oViewPane.showLabels(oNode, newText); } } } /** * If editing, do a paste from the clipboard into the node label. */ public void paste() { if (oNode.getNode().getType() == ICoreConstants.TRASHBIN || oNode.getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) { return; } if (editing) { String oldText = oNode.getText(); previousString = oNode.getText(); if (startSelection > -1 && stopSelection > -1 && stopSelection > startSelection) { String text = oldText.substring(0, startSelection) + oldText.substring(stopSelection); currentCaretPosition = startSelection; startSelection = -1; stopSelection = -1; oldText = text; } if (clipboard == null) clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable clipData = clipboard.getContents(this); String s=""; //$NON-NLS-1$ try { s = (String)(clipData.getTransferData(DataFlavor.stringFlavor)); } catch (Exception ufe) {} if (oldText.equals(ICoreConstants.NOLABEL_STRING)) { currentCaretPosition = 0; oldText = ""; //$NON-NLS-1$ } String text = oldText.substring(0, currentCaretPosition) + s + oldText.substring(currentCaretPosition); currentCaretPosition+=s.length(); oNode.setText(text, true); // mlb: Database deferred update ProjectCompendium.APP.setStatus(text); if (FormatProperties.autoSearchLabel) oViewPane.showLabels(oNode, text); } } /** * If editing, do a cut to the clipboard from the node label. */ public void cut() { if (oNode.getNode().getType() == ICoreConstants.TRASHBIN || oNode.getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) { return; } if (editing) { String text = oNode.getText(); if (startSelection < 0 || stopSelection < 0 || stopSelection > text.length()) return; if (clipboard == null) clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); StringSelection data; String selectedText = text.substring(startSelection, stopSelection); data = new StringSelection(selectedText); clipboard.setContents(data, data); previousString = text; text = text.substring(0, startSelection) + text.substring(stopSelection); oNode.setText(text, true); // mlb: Database deferred update currentCaretPosition = startSelection; startSelection = -1; stopSelection = -1; oNode.repaint(); if (FormatProperties.autoSearchLabel) oViewPane.showLabels(oNode, text); } } /** * If editing, delete selected text from the node label. */ public void delete() { if (oNode.getNode().getType() == ICoreConstants.TRASHBIN || oNode.getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) { return; } if (editing) { if (startSelection > -1 && stopSelection > -1 && stopSelection > startSelection) { String text = oNode.getText(); previousString = text; text = text.substring(0, startSelection) + text.substring(stopSelection); currentCaretPosition = startSelection; startSelection = -1; stopSelection = -1; oNode.setText(text, true); // mlb: Database deferred update oNode.repaint(); ProjectCompendium.APP.setStatus(text); if (FormatProperties.autoSearchLabel) oViewPane.showLabels(oNode, text); } else { String text = oNode.getText(); previousString = text; if (text.equals(ICoreConstants.NOLABEL_STRING)) { text = " "; //$NON-NLS-1$ currentCaretPosition = 0; } else if (currentCaretPosition >= 0 && currentCaretPosition < text.length() && text != null && !text.equals("")) { //$NON-NLS-1$ text = text.substring(0, currentCaretPosition) + text.substring(currentCaretPosition+1); } oNode.setText(text, true); // mlb: Database deferred update oNode.repaint(); ProjectCompendium.APP.setStatus(text); if (FormatProperties.autoSearchLabel) oViewPane.showLabels(oNode, text); } } } /** * If editing, do a copy to the clipboard from the node label. */ public void copy() { if (editing) { String text = oNode.getText(); if (startSelection < 0 || stopSelection < 0 || stopSelection > text.length()) return; if (clipboard == null) clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); StringSelection data; String selectedText = text.substring(startSelection, stopSelection); data = new StringSelection(selectedText); clipboard.setContents(data, data); } } /** * If editing, select all the text in the node label. */ public void selectAll() { if (editing) { String temp = oNode.getText(); startSelection = 0; stopSelection =temp.length(); oNode.repaint(); } } /** * Invoked when a key is pressed in a component. * @param evt, the associated KeyEvent. */ // MOVED ALL REGISTERED KEYBOARD ACTIONS DOWN HERE DUE TO INHERANT MEMORY LEAKS public void keyPressed(KeyEvent evt) { if (oNode != null && !oNode.hasFocus()) { oNode.getViewPane().getUI().keyPressed(evt); return; } if (oViewPane == null) oViewPane = oNode.getViewPane(); int keyCode = evt.getKeyCode(); int modifiers = evt.getModifiers(); // IF EDITING THE TEXT AREA if (editing) { if (modifiers == java.awt.Event.ALT_MASK) { switch(keyCode) { case KeyEvent.VK_T: { String today = (sdf.format(new Date())).toString(); addCharToLabel(today+" "); //$NON-NLS-1$ currentCaretPosition += today.length()-1; evt.consume(); break; } case KeyEvent.VK_LEFT: { if (ProjectCompendium.isMac) { // ONLY ON THE MAC if (currentCaretPosition > 0) { String text = oNode.getText(); String section = text.substring(0, currentCaretPosition); int index = section.lastIndexOf(" "); //$NON-NLS-1$ if (index == section.length()-1) { section = section.substring(0, section.length()-2); index = section.lastIndexOf(" ") - 1; //$NON-NLS-1$ if (index == -1) { currentCaretPosition = 0; } else { currentCaretPosition = currentCaretPosition - ( section.length() - index); } } else if (index == -1) { currentCaretPosition = 0; } else { currentCaretPosition = index - 1; } } oNode.repaint(); evt.consume(); } break; } case KeyEvent.VK_RIGHT: { if (ProjectCompendium.isMac) { // ONLY ON THE MAC String text = oNode.getText(); if (currentCaretPosition < text.length()) { String section = text.substring(currentCaretPosition); int index = section.indexOf(" "); //$NON-NLS-1$ if (index == currentCaretPosition+1) { section = section.substring(1); index = section.indexOf(" ")+1; //$NON-NLS-1$ } if (index == -1) currentCaretPosition = text.length(); else currentCaretPosition += index+1; } oNode.repaint(); evt.consume(); } break; } } } else if (modifiers == shortcutKey) { // ctrl on Windows / apple on Windows switch(keyCode) { case KeyEvent.VK_X: { // CUT cut(); evt.consume(); break; } case KeyEvent.VK_C: { // COPY copy(); evt.consume(); break; } case KeyEvent.VK_V: { // PASTE INTO LABEL paste(); evt.consume(); break; } case KeyEvent.VK_Z: { // UNDO LABEL PASTE String temp = oNode.getText(); oNode.setText(previousString, true); // mlb: Database deferred update currentCaretPosition = previousString.length(); if (FormatProperties.autoSearchLabel) oViewPane.showLabels(oNode, previousString); previousString = temp; evt.consume(); break; } case KeyEvent.VK_A: { // SELECT ALL selectAll(); evt.consume(); break; } case KeyEvent.VK_LEFT: { if (!ProjectCompendium.isMac) { // ONLY ON WINDOWS/LINUX if (currentCaretPosition > 0) { String text = oNode.getText(); int i = currentCaretPosition; while ((i > 0) && (text.charAt(i-1) == ' ')) i--; // Move backwards over whitespace if any while ((i > 0) && (text.charAt(i-1) != ' ')) i--; // Then move back until next whitespace found currentCaretPosition = i; } oNode.repaint(); evt.consume(); } break; } case KeyEvent.VK_RIGHT: { if (!ProjectCompendium.isMac) { // ONLY ON WINDOWS/LINUX String text = oNode.getText(); if (currentCaretPosition < text.length()) { String section = text.substring(currentCaretPosition); int index = section.indexOf(" "); //$NON-NLS-1$ if (index == currentCaretPosition+1) { section = section.substring(1); index = section.indexOf(" ")+1; //$NON-NLS-1$ } if (index == -1) currentCaretPosition = text.length(); else currentCaretPosition += index+1; } oNode.repaint(); evt.consume(); } break; } } } // FOLLOW SECTIONS FOR MIMICING TEXT FIELD BEHAVIOUR // MOVEMENT else if (keyCode == KeyEvent.VK_HOME && modifiers == 0) { currentCaretPosition=0; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_END && modifiers == 0) { String text = oNode.getText(); currentCaretPosition=text.length(); oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_UP && modifiers == 0) { startSelection = -1; stopSelection = -1; caretUp = true; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_DOWN && modifiers == 0) { startSelection = -1; stopSelection = -1; caretDown = true; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_LEFT && modifiers == 0) { startSelection = -1; stopSelection = -1; if (currentCaretPosition > 0) currentCaretPosition--; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_RIGHT && modifiers == 0) { startSelection = -1; stopSelection = -1; String text = oNode.getText(); if (currentCaretPosition < text.length()) currentCaretPosition++; oNode.repaint(); evt.consume(); } // SELECTION else if (keyCode == KeyEvent.VK_HOME && modifiers == Event.SHIFT_MASK) { if (startSelection == -1) startSelection = 0; if (stopSelection == -1) stopSelection = currentCaretPosition; currentCaretPosition=0; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_END && modifiers == Event.SHIFT_MASK) { if (startSelection == -1) startSelection = currentCaretPosition; String text = oNode.getText(); currentCaretPosition=text.length(); stopSelection = currentCaretPosition; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_LEFT && modifiers == Event.SHIFT_MASK) { if (stopSelection == -1) stopSelection = currentCaretPosition; if (currentCaretPosition > 0) currentCaretPosition--; if (startSelection == -1 || (startSelection < stopSelection && startSelection >= currentCaretPosition)) { startSelection = currentCaretPosition; } else stopSelection = currentCaretPosition; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_RIGHT && modifiers == Event.SHIFT_MASK) { if (startSelection == -1) startSelection = currentCaretPosition; String text = oNode.getText(); if (currentCaretPosition < text.length()) currentCaretPosition++; if (stopSelection == -1 || stopSelection < currentCaretPosition) stopSelection = currentCaretPosition; oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_LEFT && modifiers == Event.SHIFT_MASK+Event.CTRL_MASK && !ProjectCompendium.isMac) { // ON WINDOWS AND LINUX ONLY if (currentCaretPosition > 0) { if (stopSelection == -1) stopSelection = currentCaretPosition; String text = oNode.getText(); String section = text.substring(0, currentCaretPosition); int index = section.lastIndexOf(" "); //$NON-NLS-1$ if (index == section.length()-1) { section = section.substring(0, section.length()-2); index = section.lastIndexOf(" ") - 1; //$NON-NLS-1$ if (index == -1) currentCaretPosition = 0; else currentCaretPosition = currentCaretPosition - ( section.length() - index); } else if (index == -1) currentCaretPosition = 0; else currentCaretPosition = index+1; if (startSelection == -1 || startSelection > currentCaretPosition) startSelection = currentCaretPosition; } oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_RIGHT && modifiers == Event.SHIFT_MASK+Event.CTRL_MASK && !ProjectCompendium.isMac) { // ON WINDOWS AND LINUX ONLY String text = oNode.getText(); if (currentCaretPosition < text.length()) { if (startSelection == -1) startSelection = currentCaretPosition; String section = text.substring(currentCaretPosition); int index = section.indexOf(" "); //$NON-NLS-1$ if (index == currentCaretPosition+1) { section = section.substring(1); index = section.indexOf(" ")+1; //$NON-NLS-1$ } if (index == -1) currentCaretPosition = text.length(); else currentCaretPosition += index; stopSelection = currentCaretPosition; } oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_LEFT && modifiers == Event.SHIFT_MASK+Event.ALT_MASK && ProjectCompendium.isMac) { // ON MAC ONLY if (currentCaretPosition > 0) { if (stopSelection == -1) stopSelection = currentCaretPosition; String text = oNode.getText(); String section = text.substring(0, currentCaretPosition); int index = section.lastIndexOf(" "); //$NON-NLS-1$ if (index == section.length()-1) { section = section.substring(0, section.length()-2); index = section.lastIndexOf(" ") - 1; //$NON-NLS-1$ if (index == -1) currentCaretPosition = 0; else currentCaretPosition = currentCaretPosition - ( section.length() - index); } else if (index == -1) currentCaretPosition = 0; else currentCaretPosition = index+1; if (startSelection == -1 || startSelection > currentCaretPosition) startSelection = currentCaretPosition; } oNode.repaint(); evt.consume(); } else if (keyCode == KeyEvent.VK_RIGHT && modifiers == Event.SHIFT_MASK+Event.ALT_MASK && ProjectCompendium.isMac) { // ON MAC ONLY String text = oNode.getText(); if (currentCaretPosition < text.length()) { if (startSelection == -1) startSelection = currentCaretPosition; String section = text.substring(currentCaretPosition); int index = section.indexOf(" "); //$NON-NLS-1$ if (index == currentCaretPosition+1) { section = section.substring(1); index = section.indexOf(" ")+1; //$NON-NLS-1$ } if (index == -1) currentCaretPosition = text.length(); else currentCaretPosition += index; stopSelection = currentCaretPosition; } oNode.repaint(); evt.consume(); } // DELETING CHARS else if (keyCode == KeyEvent.VK_BACK_SPACE && ( modifiers == 0 || modifiers == Event.SHIFT_MASK)) { if (oNode.getNode().getType() != ICoreConstants.TRASHBIN && !oNode.getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) { if (startSelection > -1 && stopSelection > -1 && stopSelection > startSelection) { String text = oNode.getText(); previousString = text; text = text.substring(0, startSelection) + text.substring(stopSelection); currentCaretPosition = startSelection; startSelection = -1; stopSelection = -1; oNode.setText(text, true); // mlb: Database deferred update oNode.repaint(); ProjectCompendium.APP.setStatus(text); if (FormatProperties.autoSearchLabel) oViewPane.showLabels(oNode, text); } else { String text = oNode.getText(); previousString = text; if (text.equals(ICoreConstants.NOLABEL_STRING)) { text = " "; //$NON-NLS-1$ currentCaretPosition = 0; } else if (currentCaretPosition > 0 && text != null && !text.equals("")) { //$NON-NLS-1$ text = text.substring(0, currentCaretPosition-1) + text.substring(currentCaretPosition); currentCaretPosition--; } if (stopSelection > -1) stopSelection = currentCaretPosition; oNode.setText(text, true); // mlb: Database deferred update oNode.repaint(); ProjectCompendium.APP.setStatus(text); if (FormatProperties.autoSearchLabel) { if (oViewPane == null) oViewPane = oNode.getViewPane(); oViewPane.showLabels(oNode, text); } } } evt.consume(); } else if (keyCode == KeyEvent.VK_DELETE && modifiers == 0) { delete(); evt.consume(); } else if (keyCode == KeyEvent.VK_ENTER && modifiers == 0) { oViewPane.hideLabels(); evt.consume(); } else if (keyCode == KeyEvent.CHAR_UNDEFINED && modifiers == 0) { addCharToLabel("undefined"); //$NON-NLS-1$ currentCaretPosition += 8; evt.consume(); } else if (keyCode == KeyEvent.VK_ESCAPE && modifiers == 0) { resetEditing(); oViewPane.hideLabels(); oNode.requestFocus(); evt.consume(); } // MOVED TO KEYTYPED TO PICK UP ACCENTED CHARACTER ETC WHICH ARE DOUBLE KEYSTOKES /*else if ( /*modifiers != java.awt.Event.ALT_MASK + java.awt.Event.SHIFT_MASK && modifiers != java.awt.Event.ALT_MASK &&*/ /*( Character.isLetterOrDigit(keyChar) || sKeyPressed.equals(" ") || IUIConstants.NAVKEYCHARS.indexOf(sKeyPressed) != -1) ) { addCharToLabel(sKeyPressed); evt.consume(); }*/ } //*********** NONE EDITING VARIATIONS *************// else { if (modifiers == shortcutKey) { // ctrl on windows switch(keyCode) { case KeyEvent.VK_F: { // OPEN SEARCH ProjectCompendium.APP.onSearch(); evt.consume(); break; } case KeyEvent.VK_O: { // OPEN PROJECT DIALOG ProjectCompendium.APP.onFileOpen(); evt.consume(); break; } case KeyEvent.VK_N: { // NEW PROJECT DIALOG ProjectCompendium.APP.onFileNew(); evt.consume(); break; } case KeyEvent.VK_X: { // CUT if (oNode.isSelected()) oNode.getViewPane().getUI().cutToClipboard(null); else oNode.getViewPane().getUI().cutToClipboard(oNode.getUI()); evt.consume(); break; } case KeyEvent.VK_C: { // COPY if (oNode.isSelected()) oNode.getViewPane().getUI().copyToClipboard(null); else oNode.getViewPane().getUI().copyToClipboard(oNode.getUI()); evt.consume(); break; } case KeyEvent.VK_W: { // CLOSE WINDOW try { if (oNode.getViewPane().getView() != ProjectCompendium.APP.getHomeView() ) oNode.getViewPane().getViewFrame().setClosed(true); } catch(Exception e) {} evt.consume(); break; } } } if (modifiers == java.awt.Event.CTRL_MASK) { switch(keyCode) { case KeyEvent.VK_RIGHT: { // ARRANGE ProjectCompendium.APP.onViewArrange(IUIArrange.LEFTRIGHT); evt.consume(); break; } case KeyEvent.VK_DOWN: { // ARRANGE ProjectCompendium.APP.onViewArrange(IUIArrange.TOPDOWN); evt.consume(); break; } } } else if ((keyCode == KeyEvent.VK_DELETE && modifiers == 0) || (keyCode == KeyEvent.VK_BACK_SPACE && modifiers == 0)) { // delete node here if key pressed is delete UIViewFrame viewFrame = findViewFrame(); oNode.setCursor(new Cursor(java.awt.Cursor.WAIT_CURSOR)); DeleteEdit edit = new DeleteEdit(viewFrame); if ((oViewPane.getNumberOfSelectedNodes() > 0) || (oViewPane.getNumberOfSelectedLinks() > 0) ) { // delete all the selected nodes if user MULTISELECTs if(oViewPane.getNumberOfSelectedNodes() >= 1) { oViewPane.deleteSelectedNodesAndLinks(edit); } } else { oViewPane.setSelectedNode(oNode, ICoreConstants.SINGLESELECT); oViewPane.deleteSelectedNodesAndLinks(edit); // delete node and corresponding links that are attached to the node. //deleteNodeAndLinks(oNode, edit); } // notify the listeners oViewPane.getViewFrame().getUndoListener().postEdit(edit); //Thread thread = new Thread() { // public void run() { ProjectCompendium.APP.setTrashBinIcon(); // } //}; //thread.start(); oNode.setCursor(Cursor.getDefaultCursor()); evt.consume(); } else if (keyCode == KeyEvent.VK_HOME && modifiers == 0) { oViewPane.getViewFrame().scrollHome(true); evt.consume(); } else if (keyCode == KeyEvent.VK_UP && modifiers == 0) { if (oNode.hasFocus()) { //oViewPane.moveUp(oNode); evt.consume(); // Fix for Mac Tiger bug final int fnType = ICoreConstants.POSITION; //Thread thread = new Thread("") { // public void run() { UINode node = UIUtilities.createNodeAndLinkUp(oNode, fnType, 100, "", ProjectCompendium.APP.getModel().getUserProfile().getUserName()); //$NON-NLS-1$ oViewPane.setSelectedNode(node, ICoreConstants.SINGLESELECT); node.getUI().setEditing(); //node.setText(""); // } //}; //thread.start(); return; } else { oViewPane.getUI().moveCursorUp(); } evt.consume(); } else if (keyCode == KeyEvent.VK_DOWN && modifiers == 0) { if (oNode.hasFocus()) { //oViewPane.moveDown(oNode); evt.consume(); // Fix for Mac Tiger bug final int fnType = ICoreConstants.POSITION; //Thread thread = new Thread("") { // public void run() { UINode node = UIUtilities.createNodeAndLinkDown(oNode, fnType, 100, "", ProjectCompendium.APP.getModel().getUserProfile().getUserName()); //$NON-NLS-1$ oViewPane.setSelectedNode(node, ICoreConstants.SINGLESELECT); node.getUI().setEditing(); //node.setText(""); // } //}; //thread.start(); return; } else { oViewPane.getUI().moveCursorDown(); } evt.consume(); } else if (keyCode == KeyEvent.VK_LEFT && modifiers == 0) { if (oNode.hasFocus()) { //oViewPane.moveLeft(oNode); evt.consume(); // Fix for Mac Tiger bug final int fnType = ICoreConstants.POSITION; //Thread thread = new Thread("") { // public void run() { UINode node = UIUtilities.createNodeAndLinkLeft(oNode, fnType, 100, "", ProjectCompendium.APP.getModel().getUserProfile().getUserName()); //$NON-NLS-1$ oViewPane.setSelectedNode(node, ICoreConstants.SINGLESELECT); node.getUI().setEditing(); //node.setText(""); // } //}; //thread.start(); return; } else { oViewPane.getUI().moveCursorLeft(); } evt.consume(); } else if (keyCode == KeyEvent.VK_RIGHT && modifiers == 0) { if (oNode.hasFocus()) { //oViewPane.moveRight(oNode); evt.consume(); // Fix for Mac Tiger bug final int fnType = ICoreConstants.POSITION; //Thread thread = new Thread("") { // public void run() { UINode node = UIUtilities.createNodeAndLinkRight(oNode, fnType, 100, "", ProjectCompendium.APP.getModel().getUserProfile().getUserName()); //$NON-NLS-1$ oViewPane.setSelectedNode(node, ICoreConstants.SINGLESELECT); node.getUI().setEditing(); //node.setText(""); // } //}; //thread.start(); return; } else { oViewPane.getUI().moveCursorRight(); } evt.consume(); } else if (keyCode == KeyEvent.VK_ESCAPE && modifiers == 0) { oViewPane = oNode.getViewPane(); oViewPane.removeNode(oNode); oNode.setSelected(false); oViewPane.getParent().requestFocus(); oViewPane.requestFocus(); evt.consume(); } // These need to be here for the Mac as they cannot use alt+keyChar and keyCode only worked here else if (modifiers == java.awt.Event.ALT_MASK && ProjectCompendium.isMac) { // see keyTyped for Windows/Linux int nType = UINodeTypeManager.getTypeForKeyCode(keyCode); if (nType > -1) { evt.consume(); UINode node = UIUtilities.createNodeAndLinkRight(oNode, nType, 100, "", ProjectCompendium.APP.getModel().getUserProfile().getUserName()); //$NON-NLS-1$ oViewPane.setSelectedNode(node, ICoreConstants.SINGLESELECT); node.getUI().setEditing(); } } else if (modifiers == (java.awt.Event.ALT_MASK+java.awt.Event.SHIFT_MASK) && ProjectCompendium.isMac) { // see keyTyped for Windows/Linux int nType = UINodeTypeManager.getTypeForKeyCode(evt.getKeyCode()); if (nType > -1) { oNode.setType(nType, true, currentCaretPosition); evt.consume(); } } } //******** GENERIC KEY PRESSES ***********// if (modifiers == java.awt.Event.ALT_MASK && keyCode == KeyEvent.VK_V) { oNode.showViewsDialog(); evt.consume(); } // else if (modifiers == java.awt.Event.ALT_MASK && keyCode == KeyEvent.VK_W) { // String nodeId = oNode.getNode().getId(); // UIReadersDialog readers = new UIReadersDialog(ProjectCompendium.APP, nodeId); // UIUtilities.centerComponent(readers, ProjectCompendium.APP); // readers.setVisible(true); // evt.consume(); // } else if (modifiers == java.awt.Event.ALT_MASK && keyCode == KeyEvent.VK_X) { releaseFocusAndRollover(); ProjectCompendium.APP.onCodes(); evt.consume(); } else if (modifiers == shortcutKey && keyCode == KeyEvent.VK_P) { oNode.getViewPane().getUI().pasteFromClipboard(); evt.consume(); } else if (modifiers == java.awt.Event.CTRL_MASK) { switch(keyCode) { case KeyEvent.VK_R: { // ARRANGE ProjectCompendium.APP.onViewArrange(IUIArrange.LEFTRIGHT); evt.consume(); break; } case KeyEvent.VK_T: { // OPEN TAG WINDOW ProjectCompendium.APP.onCodes(); evt.consume(); break; } case KeyEvent.VK_B: { // BOLD / UNBOLD THE TEXT OF ALL SELECTED NODES IN THE CURRENT MAP ProjectCompendium.APP.getToolBarManager().addFontStyle(Font.BOLD); evt.consume(); break; } case KeyEvent.VK_I: { // ITALIC / UNITALIC THE TEXT OF ALL SELECTED NODES IN THE CURRENT MAP ProjectCompendium.APP.getToolBarManager().addFontStyle(Font.ITALIC); evt.consume(); break; } case KeyEvent.VK_ENTER: { try { if (oNode.getViewPane().getView() != ProjectCompendium.APP.getHomeView() ) oNode.getViewPane().getViewFrame().setClosed(true); } catch(Exception e) {} evt.consume(); break; } } } else if (keyCode == KeyEvent.VK_ENTER && modifiers == 0) { openNode(); evt.consume(); } else if (keyCode == KeyEvent.VK_INSERT && modifiers == 0) { releaseFocusAndRollover(); openEditDialog(false); evt.consume(); } else if (keyCode == KeyEvent.VK_F2 && modifiers == 0) { ProjectCompendium.APP.zoomNext(); evt.consume(); } else if (keyCode == KeyEvent.VK_F3 && modifiers == 0) { ProjectCompendium.APP.zoomFit(); evt.consume(); } else if (keyCode == KeyEvent.VK_F4 && modifiers == 0) { ProjectCompendium.APP.zoomFocused(); evt.consume(); } else if (keyCode == KeyEvent.VK_F12 && modifiers == 0) { oViewPane.markSelectionSeen(); // Might have a selection but gethere from user Shift-clicking nodes evt.consume(); } else if (keyCode == KeyEvent.VK_F12 && modifiers == Event.SHIFT_MASK) { oViewPane.markSelectionUnseen(); // Might have a selection but gethere from user Shift-clicking nodes evt.consume(); } } /** * Invoked when a key is released in a component. * @param e, the associated KeyEvent. */ public void keyReleased(KeyEvent e) {} /** * Invoked when a key is typed in a component. * @param e, the associated KeyEvent. */ // NEED THIS HEAR TO PICK UP KEYCHARS FROM MULTIPLE KEYS LIKE ACCENTED LETTER ON FOREIGHN KEYBOARDS. public void keyTyped(KeyEvent evt) { int modifiers = evt.getModifiers(); char keyChar = evt.getKeyChar(); char[] key = {keyChar}; sKeyPressed = new String(key); if (oNode != null && !oNode.hasFocus()) { return; } // IF EDITING THE TEXT AREA if (editing) { if (ProjectCompendium.isMac && modifiers == shortcutKey) { evt.consume(); } else { if (( Character.isLetterOrDigit(keyChar) || sKeyPressed.equals(" ") || //$NON-NLS-1$ IUIConstants.NAVKEYCHARS.indexOf(sKeyPressed) != -1) ) { addCharToLabel(sKeyPressed); evt.consume(); } } } else { if (modifiers == java.awt.Event.ALT_MASK && !ProjectCompendium.isMac) { int nType = UINodeTypeManager.getTypeForKeyPress(sKeyPressed); if (nType > -1) { evt.consume(); UINode node = UIUtilities.createNodeAndLinkRight(oNode, nType, 100, "", ProjectCompendium.APP.getModel().getUserProfile().getUserName()); //$NON-NLS-1$ oViewPane.setSelectedNode(node, ICoreConstants.SINGLESELECT); node.getUI().setEditing(); } } else if (modifiers == (java.awt.Event.ALT_MASK+java.awt.Event.SHIFT_MASK) && !ProjectCompendium.isMac) { int nType = UINodeTypeManager.getTypeForKeyPress(sKeyPressed); if (nType > -1) { oNode.setType(nType, true, currentCaretPosition); evt.consume(); } } } } /** * Find the viewframe for this node. If the node does not know it get the current frame. * This should not be necessary but fixes an occassional bug. * This method sets the variable 'oViewPane', as well as returning the frame. */ private UIViewFrame findViewFrame() { UIViewFrame viewFrame = null; if (oNode == null) { viewFrame = ProjectCompendium.APP.getCurrentFrame(); oViewPane = ((UIMapViewFrame)viewFrame).getViewPane(); } else { oViewPane = oNode.getViewPane(); if (oViewPane == null) { viewFrame = ProjectCompendium.APP.getCurrentFrame(); oViewPane = ((UIMapViewFrame)viewFrame).getViewPane(); } else viewFrame = oViewPane.getViewFrame(); } return viewFrame; } /** * Handles a property change to the UINode. * @param evt, the associated PropertyChagenEvent object. */ public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); if (prop.equals(UINode.TEXT_PROPERTY) || prop.equals(UINode.ICON_PROPERTY)) { refreshBounds(); } else if (prop.equals(UINode.TYPE_PROPERTY)) { refreshBounds(); } else if (prop.equals(UINode.CHILDREN_PROPERTY)) { //refreshBounds(); } else if (prop.equals(NodeSummary.STATE_PROPERTY)) { refreshBounds(); } // UPDATE NODE INDICATORS else if (prop.equals(NodeSummary.DETAIL_PROPERTY)) { refreshBounds(); } else if (prop.equals(NodeSummary.TAG_PROPERTY)) { refreshBounds(); } else if (prop.equals(NodeSummary.VIEW_NUM_PROPERTY)) { //refreshBounds(); } } /** * Refresh the bounds of this object. * Calls <code>getPreferredSize</code>, * which is important for the paint method to work correctly later.# * @see #getPreferredSize */ public void refreshBounds() { if (oNode == null) { return; } Rectangle r = oNode.getBounds(); int prefX = r.x; int prefY = r.y; Dimension d = getPreferredSize(oNode); // ADJUST X TO KEEP CENTER POINT THE SAME int oldCenter = r.x+(r.width/2); if (d.width > r.width) prefX = r.x - ((d.width - r.width)/2); else if (d.width < r.width) prefX = r.x + ((r.width - d.width)/2); int newCenter = prefX+(d.width/2); // ADJUST FOR SLIPPAGE DUE TO ROUNDING OF NUMBERS if (newCenter > oldCenter) prefX -= 1; else if (newCenter < oldCenter) prefX += 1; oNode.setBounds(prefX, prefY, d.width, d.height); } /** * This border class paints the border for this node. */ private class NodeBorder extends AbstractBorder { public void paintBorder (Component c, Graphics g, int x, int y, int width, int height) { boolean isHot = false; UINode node = null; if (c instanceof UINode) { node = (UINode)c; isHot = node.isRollover(); } int type = node.getNode().getType(); Model oModel = (Model)ProjectCompendium.APP.getModel(); boolean bMapBorder = oModel.mapBorder; if (node.hasFocus() && !editing) { if ((View.isViewType(type) || View.isShortcutViewType(type)) && node.getNode().getImage() != null && !node.getNode().getImage().equals("")) { //$NON-NLS-1$ if (bMapBorder) { paintRaisedBevel(c, g, x, y, width, height, FOCUSED_COLOR); } else { Color oldColor = g.getColor(); g.setColor(FOCUSED_COLOR); g.draw3DRect(x, y, width-1, height-1, true); g.setColor(oldColor); } } else { Color oldColor = g.getColor(); g.setColor(FOCUSED_COLOR); g.draw3DRect(x, y, width-1, height-1, true); g.setColor(oldColor); } } else if (isHot && !editing) { if ( (View.isViewType(type) || View.isShortcutViewType(type)) && node.getNode().getImage() != null && !node.getNode().getImage().equals("")) { //$NON-NLS-1$ if (bMapBorder) { paintRaisedBevel(c, g, x, y, width, height, BORDER_COLOR); } else { Color oldColor = g.getColor(); g.setColor(BORDER_COLOR); g.draw3DRect(x, y, width-1, height-1, true); g.setColor(oldColor); } } else { Color oldColor = g.getColor(); g.setColor(BORDER_COLOR); g.draw3DRect(x, y, width-1, height-1, true); g.setColor(oldColor); } } else if (node != null) { boolean bShowMapBorder = false; if ( (View.isViewType(type) || View.isShortcutViewType(type)) && node.getNode().getImage() != null && !node.getNode().getImage().equals("")) { //$NON-NLS-1$ bShowMapBorder = true; } int state = node.getNode().getState(); if (state == ICoreConstants.UNREADSTATE) { if (bShowMapBorder) { if (bMapBorder) { paintRaisedBevel(c, g, x, y, width, height, IUIConstants.UNREAD_BORDER_COLOR); } } else { Color oldColor = g.getColor(); g.setColor(IUIConstants.UNREAD_BORDER_COLOR); g.draw3DRect(x, y, width-1, height-1, true); g.setColor(oldColor); } } else if (state == ICoreConstants.MODIFIEDSTATE) { if (bShowMapBorder) { if (bMapBorder) { paintRaisedBevel(c, g, x, y, width, height, IUIConstants.MODIFIED_BORDER_COLOR); } } else { Color oldColor = g.getColor(); g.setColor(IUIConstants.MODIFIED_BORDER_COLOR); g.draw3DRect(x, y, width-1, height-1, true); g.setColor(oldColor); } } else { if (node.getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) { bMapBorder = false; } if (bShowMapBorder) { if (bMapBorder) { paintRaisedBevel(c, g, x, y, width, height, IMAGEMAP_COLOR); } } } } } protected void paintRaisedBevel(Component c, Graphics g, int x, int y, int width, int height, Color color) { Color oldColor = g.getColor(); int h = height; int w = width; g.translate(x, y); g.setColor(color.brighter().brighter().brighter()); g.drawLine(0, 0, 0, h-2); g.drawLine(1, 0, w-2, 0); g.setColor(color.brighter().brighter()); g.drawLine(1, 1, 1, h-3); g.drawLine(2, 1, w-3, 1); g.setColor(color.darker().darker().darker()); g.drawLine(0, h-1, w-1, h-1); g.drawLine(w-1, 0, w-1, h-2); g.setColor(color.darker()); g.drawLine(1, h-2, w-2, h-2); g.drawLine(w-2, 1, w-2, h-3); g.translate(-x, -y); g.setColor(oldColor); } protected void paintLoweredBevel(Component c, Graphics g, int x, int y, int width, int height, Color color) { Color oldColor = g.getColor(); int h = height; int w = width; g.translate(x, y); g.setColor(color.darker()); g.drawLine(0, 0, 0, h-1); g.drawLine(1, 0, w-1, 0); g.setColor(color.darker().darker().darker()); g.drawLine(1, 1, 1, h-2); g.drawLine(2, 1, w-2, 1); g.setColor(color.brighter().brighter().brighter()); g.drawLine(1, h-1, w-1, h-1); g.drawLine(w-1, 1, w-1, h-2); g.setColor(color.brighter().brighter()); g.drawLine(2, h-2, w-2, h-2); g.drawLine(w-2, 2, w-2, h-3); g.translate(-x, -y); g.setColor(oldColor); } public Insets getBorderInsets(Component c) { int type = oNode.getNode().getType(); if (View.isViewType(type) || View.isShortcutViewType(type)) { Model oModel = (Model)ProjectCompendium.APP.getModel(); boolean bMapBorder = oModel.mapBorder; if (bMapBorder) return new Insets(2,2,2,2); else return new Insets(1, 1, 1, 1); } else return new Insets(1, 1, 1, 1); } } /** * If this node has the focus pass it to its parent, and set the rollover off. */ private void releaseFocusAndRollover() { if (oNode.hasFocus()) { oNode.setRollover(false); oNode.getParent().requestFocus(); } } /** * Delete all the links attached to the given node. * @param node com.compendium.ui.UINode, the node to delete the links for. * @param edit, the object to add deleted links to ofr potential undo/redo operations. */ public void deleteLinksforNode(UINode node, PCEdit edit) { //remove all the ui links that connect to this node for(Enumeration e = node.getLinks();e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); LinkUI linkui = (LinkUI)uilink.getUI(); linkui.deleteLink(uilink); // save link in case operation needs to be undone. if (edit != null) { edit.AddLinkToEdit (uilink); } } } /** * Delete the given node and its links. * @param node com.compendium.ui.UINode, the node to delete. * @param edit the object to add deleted nodes to for potential undo/redo operations. * @return true if the node was the last instalce and has been totatlly deleted, else false. */ public boolean deleteNodeAndLinks(UINode node, PCEdit edit) { boolean bDeleted = false; deleteLinksforNode(node, edit); bDeleted = deleteNode(node); if (edit != null) { edit.AddNodeToEdit (node); } return (bDeleted); } /** * Delete the given node from the database and the parent view. * @param node com.compendium.ui.UINode, the node to delete. */ private boolean deleteNode(UINode node) { boolean nodeDeletedFromDB = removeFromDatamodel(node); if (nodeDeletedFromDB) { ProjectCompendium.APP.setTrashBinIcon(); } removeFromUI(node); return nodeDeletedFromDB; } /** * Marks the given node as deleted in the database. * @param node the node to delete. * @return true if the node was the last instance and has been totally deleted, else false. */ public boolean removeFromDatamodel(UINode node) { //don't delete the trashbin NodeSummary oNode = node.getNode(); if((oNode.getType() == ICoreConstants.TRASHBIN) || oNode.getId().equals(ProjectCompendium.APP.getInBoxID())) { return false; } boolean nodeDeletedFromDB = false; oViewPane = node.getViewPane(); try { nodeDeletedFromDB = oViewPane.getView().removeMemberNode(node.getNode()); } catch(Exception ex) { log.error("Error...", ex); log.info("Error "+ex.getMessage()); //$NON-NLS-1$ return false; } if (nodeDeletedFromDB) { // IF THIS WAS A VIEW NODE LET THE HISTORY KNOW TO REMOVE IT if (oNode instanceof View) { View view = (View) oNode; ProjectCompendium.APP.removeViewFromHistory(view); } } if(oNode.getViewCount() > 0 ) { return false; } else { return true; } } /** * Delete the given node from the ui layer. * @param node com.compendium.ui.UINode, the node to delete. */ public void removeFromUI(UINode node) { // Lakshmi - 5/25/06 if(oViewPane == null) oViewPane = node.getViewPane(); //remove node from the UIviewpane layer oViewPane.remove(node); // paint the new updated layered pane oViewPane.paintImmediately(node.getBounds()); //finalize delete in the model //oViewPane.getView().getModel().removeObject(node.getNode()); //clear rollover image or any hints if (oViewPane != null) { oViewPane.hideCodes(); oViewPane.hideDetail(); if (FormatProperties.imageRollover) oViewPane.hideImages(); } //IF NODE IS A VIEW, REMOVE IT FROM DESKTOP IF OPEN if(node.getNode() instanceof View) { ProjectCompendium.APP.removeView((View)node.getNode()); } // the viewpane gets the focus oViewPane.requestFocus(); } /** * This method Delinks a Node from all its links. */ public void delink() { //remove all the ui links that connect to this node for(Enumeration e = oNode.getLinks();e.hasMoreElements();) { UILink link = (UILink)e.nextElement(); LinkUI linkui = (LinkUI)link.getUI(); linkui.deleteLink(link); } //make sure all the links are removed oNode.removeAllLinks(); ProjectCompendium.APP.getAudioPlayer().playAudio(UIAudio.DELINKING_ACTION); } /** * Convenience method to get the UINode by the popupmenu and other gui operations. * @return com.compendium.ui.UINode, the UINode associated with this NodeUI instance. */ public UINode getUINode() { return oNode; } /** * Creates a link. * @param uifrom the originating node for the link to create. * @param uito the destination node for the link to create. * @param type the type of link to create. * @param props the link properties to apply to this link. * @return com.compendium.ui.UILink, the newly created link. * @see com.compendium.core.ICoreConstants */ public UILink createLink(UINode uifrom, UINode uito, String type, LinkProperties props) { return createLink(uifrom, uito, type, "", props); //$NON-NLS-1$ } /** * Creates a link. * @param uifrom com.compendium.ui.UINode, the originating node for the link to create. * @param uito com.compendium.ui.UINode, the destination node for the link to create. * @param type, the type of link to create. * @param sLabel, the labe for this node. * @param props the link properties to apply to this link. * @return com.compendium.ui.UILink, the newly created link. * @see com.compendium.core.ICoreConstants */ public UILink createLink(UINode uifrom, UINode uito, String type, String sLabel, LinkProperties props) { oViewPane = oNode.getViewPane(); NodeSummary from = uifrom.getNode(); NodeSummary to = uito.getNode(); if (oViewPane == null || from == null || to == null) return null; View view = oViewPane.getView(); if (view == null) return null; int permission = ICoreConstants.WRITE; String sOriginalID = ""; //$NON-NLS-1$ LinkProperties linkProps = null; try { //add the link to the datamodel view linkProps = (LinkProperties)view.addMemberLink(type, sOriginalID, ProjectCompendium.APP.getModel().getUserProfile().getUserName(), from, to, sLabel, props); } catch(Exception ex){ log.error("Error...", ex); ProjectCompendium.APP.displayError("Error: (NodeUI.createLink)\n\n"+ex.getLocalizedMessage()); //$NON-NLS-1$ return null; } Link link = linkProps.getLink(); link.initialize(view.getModel().getSession(), view.getModel()); //create a link in UI layer - NOW DONE BY PROPERTY CHANGE EVENT UILink uilink = (UILink)oViewPane.get(link.getId()); if (uilink == null) { uilink = new UILink(link, linkProps, uifrom, uito); double currentScale = oViewPane.getZoom(); AffineTransform trans=new AffineTransform(); trans.setToScale(currentScale, currentScale); uilink.scaleLink(trans); uito.getViewPane().add(uilink, (UIViewPane.LINK_LAYER)); uilink.setBounds(uilink.getPreferredBounds()); uifrom.addLink(uilink); uito.addLink(uilink); } return uilink; } /** * Creates a link. * @param sLinkID, the id to give this link. * @param uifrom com.compendium.ui.UINode, the originating node for the link to create. * @param uito com.compendium.ui.UINode, the destination node for the link to create. * @param type, the type of link to create. * @param sLabel, the labe for this node. * @param props the link properties to apply to this link. * @return com.compendium.ui.UILink, the newly created link. * @see com.compendium.core.ICoreConstants */ public UILink createLink(String sImportedID, UINode uifrom, UINode uito, String type, String sLabel, LinkProperties props) { oViewPane = oNode.getViewPane(); NodeSummary from = uifrom.getNode(); NodeSummary to = uito.getNode(); if (oViewPane == null || from == null || to == null) return null; View view = oViewPane.getView(); if (view == null) return null; int permission = ICoreConstants.WRITE; String sOriginalID = ""; //$NON-NLS-1$ LinkProperties linkProps = null; try { //add the link to the datamodel view linkProps = (LinkProperties)view.addMemberLink(type, sImportedID, sOriginalID, ProjectCompendium.APP.getModel().getUserProfile().getUserName(), from, to, sLabel, props); } catch(Exception ex){ log.error("Error...", ex); ProjectCompendium.APP.displayError("Error: (NodeUI.createLink2)\n\n"+ex.getLocalizedMessage()); //$NON-NLS-1$ return null; } Link link = linkProps.getLink(); link.initialize(view.getModel().getSession(), view.getModel()); //create a link in UI layer - NOW DONE BY PROPERTY CHANGE EVENT UILink uilink = (UILink)oViewPane.get(link.getId()); if (uilink == null) { uilink = new UILink(link, linkProps, uifrom, uito); double currentScale = oViewPane.getZoom(); AffineTransform trans=new AffineTransform(); trans.setToScale(currentScale, currentScale); uilink.scaleLink(trans); uito.getViewPane().add(uilink, (UIViewPane.LINK_LAYER)); uilink.setBounds(uilink.getPreferredBounds()); uifrom.addLink(uilink); uito.addLink(uilink); } return uilink; } /** * Open the node contents dialog with the details tab showing. * @param fromKeyEvent, indicates if this method was called from a key event. */ public void openEditDialog(boolean fromKeyEvent) { final boolean isFromKeyEvent = fromKeyEvent; Thread thread = new Thread("NodeUI: EditDialog") { //$NON-NLS-1$ public void run() { editDialog = oNode.showEditDialog(); if (isFromKeyEvent) { JTextArea textArea = editDialog.getDetailField(); textArea.setText(textArea.getText()+dialogBuffer); dialogBuffer = ""; //$NON-NLS-1$ textArea.setCaretPosition(textArea.getText().length()); openingDialog = false; } } }; thread.start(); Thread.currentThread().yield(); } //GETTER AND SETTERS /** * @return the hasTrans */ public boolean hasTrans() { return hasTrans; } /** * @param nodeWidth the nodeWidth to set */ public void setNodeWidth(int nodeWidth) { this.nodeWidth = nodeWidth; } /** * @param hasTrans the hasTrans to set */ public void setHasTrans(boolean hasTrans) { this.hasTrans = hasTrans; } /** * @return the hasText */ public boolean hasText() { return hasText; } /** * @param hasText the hasText to set */ public void setHasText(boolean hasText) { this.hasText = hasText; } /** * @return the hasCodes */ public boolean hasCodes() { return hasCodes; } /** * @param hasCodes the hasCodes to set */ public void setHasCodes(boolean hasCodes) { this.hasCodes = hasCodes; } /** * @return the hasWeight */ public boolean hasWeight() { return hasWeight; } /** * @param hasWeight the hasWeight to set */ public void setHasWeight(boolean hasWeight) { this.hasWeight = hasWeight; } /** * @return the hasIcon */ public boolean hasIcon() { return hasIcon; } /** * @param hasIcon the hasIcon to set */ public void setHasIcon(boolean hasIcon) { this.hasIcon = hasIcon; } /** * @return the hasMovie */ public boolean hasMovie() { return hasMovie; } /** * @param hasMovie the hasMovie to set */ public void setHasMovie(boolean hasMovie) { this.hasMovie = hasMovie; } /** * @return the extraIconWidth */ public int getExtraIconWidth() { return extraIconWidth; } /** * @param extraIconWidth the extraIconWidth to set */ public void setExtraIconWidth(int extraIconWidth) { this.extraIconWidth = extraIconWidth; } /** * @return the iconRectangle */ public Rectangle getIconRectangle() { return iconRectangle; } }