/******************************************************************************** * * * (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; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.awt.image.AreaAveragingScaleFilter; import java.awt.image.BufferedImage; import java.awt.image.FilteredImageSource; import java.awt.image.ImageFilter; import java.awt.image.ImageProducer; import java.awt.image.RenderedImage; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.sql.SQLException; import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.Vector; import javax.help.CSH; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.RepaintManager; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.compendium.LanguageProperties; import com.compendium.ProjectCompendium; import com.compendium.core.CoreUtilities; import com.compendium.core.ICoreConstants; import com.compendium.core.datamodel.Code; import com.compendium.core.datamodel.IModel; import com.compendium.core.datamodel.LinkProperties; import com.compendium.core.datamodel.LinkedFile; import com.compendium.core.datamodel.LinkedFile.LFType; import com.compendium.core.datamodel.ModelSessionException; import com.compendium.core.datamodel.NodePosition; import com.compendium.core.datamodel.NodeSummary; import com.compendium.core.datamodel.PCSession; import com.compendium.core.datamodel.View; import com.compendium.core.datamodel.ViewLayer; import com.compendium.ui.dialogs.UIDropSelectionDialog; import com.compendium.ui.dialogs.UINodeContentDialog; import com.compendium.ui.edits.PCEdit; import com.compendium.ui.panels.UIHintNodeCodePanel; import com.compendium.ui.panels.UIHintNodeDetailPanel; import com.compendium.ui.panels.UIHintNodeImagePanel; import com.compendium.ui.panels.UIHintNodeLabelPanel; import com.compendium.ui.panels.UIHintNodeViewsPanel; import com.compendium.ui.plaf.LinkUI; import com.compendium.ui.plaf.NodeUI; import com.compendium.ui.plaf.ViewPaneUI; import com.compendium.ui.popups.UIDropFilePopupMenu; import com.compendium.ui.popups.UIDropFolderPopupMenu; import com.compendium.ui.popups.UIDropImportPopupMenu; import com.compendium.ui.popups.UIViewPopupMenu; import com.compendium.ui.stencils.DraggableStencilIcon; /** * This class is the main class that draws and handles Compendium maps and their events. * * @author Mohammed Sajid Ali / Michelle Bachler */ public class UIViewPane extends JLayeredPane implements PropertyChangeListener, DropTargetListener, Printable, Transferable, DragSourceListener, DragGestureListener{ /** * class's own logger */ final Logger log = LoggerFactory.getLogger(getClass()); /** The generated serial version id */ private static final long serialVersionUID = -6997855860445477967L; /** view property name for use with property change events */ public final static String VIEW_PROPERTY = "view"; //$NON-NLS-1$ //place nodes on higher layers so that when mouse goes over it, rollover is enabled //by placing the link on the lower layer, its bounds doesnt override the node bounds //and the node can be selected even if it is inside link preferred bound range /** A reference to the layer to hold background images. */ public final static Integer BACKGROUNDIMAGE_LAYER = new Integer(200); /** A reference to the layer to hold grid layout stuff NOT IMPLEMENTED YET.*/ public final static Integer GRID_LAYER = new Integer(230); /** A reference to the layer holding the scribble notes when moved to the back of the nodes.*/ public final static Integer SCRIBBLE_LAYER_BACK = new Integer(260); /** A reference to the layer to hold links.*/ public final static Integer LINK_LAYER = new Integer(350); /** A reference to the layer to hold nodes.*/ public final static Integer NODE_LAYER = new Integer(400); /** A reference to the layer to hold the rollover hint popups.*/ public final static Integer HINT_LAYER = new Integer(450); /** A reference to the layer holding the scribble notes, when sitting infront of the nodes.*/ public final static Integer SCRIBBLE_LAYER = new Integer(480); /** The current scaling resolution for this view.*/ public double currentScale = 1.0; /** The previous scaling resolution for this view.*/ public double previousScale = 1.0; /** The View object tha holds the data for this view.*/ protected View oView = null; /** The parent view frame that holds this view.*/ protected UIViewFrame oViewFrame = null; /** The UI object that paints this view.*/ protected ViewPaneUI oViewPaneUI = null; /** The node last selected in this view.*/ protected UINode oNode = null; /** A list off all currently selected nodes in this view.*/ protected Vector vtNodeSelected = new Vector(); /** The link last selected in this view.*/ protected UILink oLink = null; /** A list of all links selected in this view.*/ protected Vector vtLinkSelected = new Vector(); /** The instance of the scribble pad class used in this view - CURRENTLY NOT IMPLEMENTED.*/ protected UIScribblePad oScribblePad = null; /** Holds a list of currently displayed tag rollover popups -CURRENTLY SHOULD BE ONLY ONE.*/ protected Hashtable tagPopups = new Hashtable(51); /** Holds a list of currently displayed detail rollover popups -CURRENTLY SHOULD BE ONLY ONE.*/ protected Hashtable detailPopups = new Hashtable(51); /** Holds a list of currently displayed parent view rollover popups -CURRENTLY SHOULD BE ONLY ONE.*/ protected Hashtable viewsPopups = new Hashtable(51); /** Holds a list of currently displayed image rollover popups -CURRENTLY SHOULD BE ONLY ONE.*/ protected Hashtable imagePopups = new Hashtable(51); /** Holds a list of currently displayed label search rollover popups -CURRENTLY SHOULD BE ONLY ONE.*/ protected Hashtable labelPopups = new Hashtable(51); /** Holds a list of currently displayed node focus rollover popups -CURRENTLY SHOULD BE ONLY ONE.*/ protected Hashtable nodeFocusPopups = new Hashtable(51); /** The offset to use when displaying rollover popups.*/ protected int hintOffset = 20; /** The drop target instance associated with this vie.*/ protected DropTarget dropTarget = null; /** The instance of the view right-click popup menu last accessed for this view.*/ protected UIViewPopupMenu viewPopup = null; /** The label holding the background layer image.*/ protected JLabel lblBackgroundLabel = null; /** The original title of the map.*/ protected String sTitle = ""; //$NON-NLS-1$ /** The user name of the current user */ protected String sAuthor = ""; //$NON-NLS-1$ /** Stringbuffer holding a list of Files that could not be copied. */ private StringBuffer oErrFilesNotCopied = null; /* sehrich */ /** Use a separate DataFlavor for Linux to work around a bug in the linux java vm * see bugs.sun.com/bugdatabase/view_bug.do?bug_id=4899516 * This is not important for dropping files. But when dragging a file in i.e. GNOME when * we'd use the stringFlavour GNOME would asks for a file name, wheres it creates a file * with the correct file name when using the uri-list flavour */ public static DataFlavor uriListFlavor = null; /* sehrich */ /** The drag source object associated with this node.*/ private DragSource dragSource = null; /** * Constructor. Creates and initializes a new instance of UIViewPane. * @param view the view holding the data for this pane to dispaly. * @param viewFrame the parent frame containing this view pane */ public UIViewPane(View view, UIViewFrame viewframe) { oViewFrame = viewframe; this.sAuthor = viewframe.getCurrentAuthor(); /* set the uriListFlavor */ try { uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String"); //$NON-NLS-1$ } catch (ClassNotFoundException e1) { e1.printStackTrace(); } dragSource = new DragSource(); dragSource.createDefaultDragGestureRecognizer((Component)this, DnDConstants.ACTION_COPY , this); if (oViewFrame != null) { sTitle = oViewFrame.getTitle(); } view.addPropertyChangeListener(this); setView(view); updateUI(); setBackground(Color.white); ViewLayer oViewLayer = view.getViewLayer(); if (oViewLayer != null) { int nBackgroundColor = oViewLayer.getBackgroundColor(); Color oBackgroundColor = new Color(nBackgroundColor); setBackground(oBackgroundColor); repaint(); String sBackground = oViewLayer.getBackgroundImage(); if (!sBackground.equals("") && UIImages.isImage(sBackground)) { //$NON-NLS-1$ addBackgroundImage(sBackground); } } setHelpString(); dropTarget = new DropTarget(this, this); } /** * Set the help string link for this view */ protected void setHelpString() { CSH.setHelpIDString(this,"node.views"); //$NON-NLS-1$ } /** * Return the current user's author name. * @return the current user's author name. */ public String getCurrentAuthor() { return sAuthor; } /** * Set the current zoom scale for this view pane. * @param zoom, the current zoom scale for this view pane. */ public void setZoom(double zoom) { previousScale = currentScale; currentScale = zoom; } /** * Get the current zoom scale for this view pane. * @return double, the current zoom scale for this view pane. */ public double getZoom() { return currentScale; } // DRAG AND DROP STUFF /** * Called if the user has modified * the current drop gesture. * <P> * THIS METHOD DOES NOTHING HERE. * @param e the <code>DropTargetDragEvent</code> */ public void dropActionChanged (DropTargetDragEvent dropTargetDragEvent){} /** * 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. * THIS METHOD DOES NOTHING HERE. * * @param e the <code>DropTargetEvent</code> */ public void dragExit(DropTargetEvent e) {} /** * 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. * THIS METHOD DOES NOTHING HERE. * * @param e the <code>DropTargetDragEvent</code> */ public void dragOver(DropTargetDragEvent e) {} /** * 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. Accepts COPY_ACTION drags. * * @param e the <code>DropTargetDragEvent</code> */ public void dragEnter(DropTargetDragEvent e) { e.acceptDrag(DnDConstants.ACTION_COPY); } /** * 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> * This method is responsible for undertaking * the transfer of the data associated with the * gesture. The <code>DropTargetDropEvent</code> * provides a means to obtain a <code>Transferable</code> * object that represents the data object(s) to * be transfered.<P> * From this method, the <code>DropTargetListener</code> * shall accept or reject the drop via the * acceptDrop(int dropAction) or rejectDrop() methods of the * <code>DropTargetDropEvent</code> parameter. * <P> * Subsequent to acceptDrop(), but not before, * <code>DropTargetDropEvent</code>'s getTransferable() * method may be invoked, and data transfer may be * performed via the returned <code>Transferable</code>'s * getTransferData() method. * <P> * At the completion of a drop, an implementation * of this method is required to signal the success/failure * of the drop by passing an appropriate * <code>boolean</code> to the <code>DropTargetDropEvent</code>'s * dropComplete(boolean success) method. * <P> * This method accept or declines the drop of an external file, directory or text block. * <P> * @param e the <code>DropTargetDropEvent</code> */ public void drop(DropTargetDropEvent e) { // IF THE SCRIBBLE LAYER IS ON AND ON THE TOP LAYER, REJECT ALL DROPS UIScribblePad pad = getScribblePad(); if (pad != null && pad.isVisible() && getLayer(oScribblePad) == SCRIBBLE_LAYER) { return; } try { final Transferable tr = e.getTransferable(); final UIViewPane pane = this; final DropTargetDropEvent evt = e; Point dropPoint = e.getLocation(); int nX = dropPoint.x; int nY = dropPoint.y; if (nX >= 20 && nY >= 10) { nX -= 20; nY -= 10; } if (tr.isDataFlavorSupported(DraggableStencilIcon.supportedFlavors[0])) { Object source = tr.getTransferData(DraggableStencilIcon.supportedFlavors[0]); if (source instanceof DraggableStencilIcon) { DraggableStencilIcon stencil = (DraggableStencilIcon)source; createNodeFromStencil(stencil, nX, nY); } } else if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); final java.util.List fileList = (java.util.List) tr.getTransferData(DataFlavor.javaFileListFlavor); // new Thread required for Mac bug caused when code calls UIUtilities.checkCopyLinkedFile // and tries to open a JOptionPane popup. final int xPos = nX; final int yPos = nY; Thread thread = new Thread("UIViewPane.drop-FileListFlavor") { //$NON-NLS-1$ public void run() { int nX = xPos; int nY = yPos; // initialize error list oErrFilesNotCopied = new StringBuffer(); Iterator iterator = fileList.iterator(); DragAndDropProperties props = FormatProperties.dndProperties.clone(); boolean success = true; while (iterator.hasNext() && success) { File file = (File) iterator.next(); success = createNode(pane.getView(), file, nX, nY, props); nY += 80; } evt.getDropTargetContext().dropComplete(true); if (oErrFilesNotCopied.length() > 0) { ProjectCompendium.APP.displayMessage( LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.message1") //$NON-NLS-1$ +" "+LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.message1b")+":\n\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + oErrFilesNotCopied.toString(), LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.message1Title")); //$NON-NLS-1$ oErrFilesNotCopied = null; } } }; thread.start(); } else if (tr.isDataFlavorSupported(DataFlavor.stringFlavor)) { e.acceptDrop(DnDConstants.ACTION_COPY); String tmpdropString = (String)tr.getTransferData(DataFlavor.stringFlavor); int lastcode = tmpdropString.codePointAt(tmpdropString.length()-1); if (lastcode==0) { // workaround for bug when dropping unicode strings in KDE tmpdropString = tmpdropString.substring(0, tmpdropString.length()-1); } final String dropString = tmpdropString; // new Thread required for Mac bug caused when code calls UIUtilities.checkCopyLinkedFile // and tries to open a JOptionPane popup. final int xPos = nX; final int yPos = nY; Thread thread = new Thread("UIViewPane.drop-StringFlavor") { //$NON-NLS-1$ public void run() { int nX = xPos; int nY = yPos; String s = dropString; // initialize error list oErrFilesNotCopied = new StringBuffer(); /*if (s.startsWith("memetic-replay")) { ProjectCompendium.APP.oMeetingManager = new MeetingManager(MeetingManager.REPLAY); ProjectCompendium.APP.oMeetingManager.processAsMeetingReplay(s); } else if (s.startsWith("memetic-index")) { if (ProjectCompendium.APP.oMeetingManager == null) { ProjectCompendium.APP.displayError("You are not currently replaying a Meeting"); return; } else { ProjectCompendium.APP.oMeetingManager.processAsMeetingReplayIndex(s, nX, nY); } }*/ boolean bdragdropKDE = false; if (ProjectCompendium.isLinux) { if (s.startsWith("www.") || s.startsWith("http://") //$NON-NLS-1$ //$NON-NLS-2$ || s.startsWith("https://")) { //$NON-NLS-1$ UINode node = oViewPaneUI.addNewNode( ICoreConstants.REFERENCE, nX, nY); node.setText(s); try { node.getNode().setSource(s, "", sAuthor); //$NON-NLS-1$ node.setReferenceIcon(s); } catch (Exception ex) { log.error("Error...", ex); //$NON-NLS-1$ } node.getUI().refreshBounds(); } else { final java.util.List fileList = new LinkedList(); if (s.startsWith("file://")) { //$NON-NLS-1$ // remove 'file://' from file path String[] liste = s.split("file://"); //$NON-NLS-1$ for (int i = 1; i < liste.length; i++) { // remove 'file://' from file path String filename = new String(liste[i] .replaceFirst("\n", "")); //$NON-NLS-1$ //$NON-NLS-2$ File file = new File(filename); fileList.add(file); } Iterator iterator = fileList.iterator(); nX = xPos; nY = yPos; DragAndDropProperties props = FormatProperties.dndProperties.clone(); boolean success = true; while (iterator.hasNext() && success) { success = createNode(pane.getView(), (File) iterator .next(), nX, nY, props); nY = +80; } // drop object is not a file but e.g. text bdragdropKDE = true; } else { bdragdropKDE = false; } } } try { int nType = new Integer(s).intValue(); oViewPaneUI.addNewNode(nType, nX, nY); evt.getDropTargetContext().dropComplete(true); } catch(NumberFormatException io) { if (UINode.isReferenceNode(s)) { File newFile = new File(s); String fileName = newFile.getName(); fileName = fileName.toLowerCase(); String sFullPath = UIUtilities.sGetLinkedFilesLocation(); String sFilePath = sFullPath; File directory = new File(sFilePath); if (ProjectCompendium.isMac) sFilePath = directory.getAbsolutePath()+ProjectCompendium.sFS; String sActualFilePath = ""; //$NON-NLS-1$ try { sActualFilePath = UIImages.loadWebImageToLinkedFiles(s, fileName, sFilePath); } catch(Exception exp) {} if (!sActualFilePath.equals("")) { //$NON-NLS-1$ UINode node = oViewPaneUI.addNewNode(ICoreConstants.REFERENCE, nX, nY); node.setReferenceIcon(sActualFilePath); try { node.getNode().setSource("", sActualFilePath, sAuthor); //$NON-NLS-1$ } catch(Exception ex) { log.info("error in UIViewPane.drop-3b) \n\n"+ex.getMessage()); //$NON-NLS-1$ } File temp = new File(sActualFilePath); node.setText(temp.getName()); node.getUI().refreshBounds(); } else if (!ProjectCompendium.isLinux) { //newFile = UIUtilities.checkCopyLinkedFile(newFile); //if (newFile != null) // s = newFile.getPath(); UINode node = oViewPaneUI.addNewNode(ICoreConstants.REFERENCE, nX, nY); String name = s; String path = s; String uri = s; node.setReferenceIcon(path); try { if (UIImages.isImage(s)) node.getNode().setSource("", uri, sAuthor); //$NON-NLS-1$ else { node.getNode().setSource(uri, "", sAuthor); //$NON-NLS-1$ } } catch(Exception ex) { log.info("error in UIViewPane.drop-3) \n\n"+ex.getMessage()); //$NON-NLS-1$ } node.setText(name); node.getUI().refreshBounds(); } evt.getDropTargetContext().dropComplete(true); } else { if (!bdragdropKDE) { UIDropSelectionDialog dropDialog = new UIDropSelectionDialog(ProjectCompendium.APP, pane, s, nX, nY); //dropDialog.setVisible(true); DragAndDropProperties dndprops = FormatProperties.dndProperties; if (dndprops.dndNoTextChoice) { dropDialog.processAsPlain(); dropDialog.onCancel(); } else { dropDialog.setVisible(true); } evt.getDropTargetContext().dropComplete(true); } } } if (oErrFilesNotCopied.length() > 0) { ProjectCompendium.APP.displayMessage( LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.message1") //$NON-NLS-1$ +" "+LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.message1b")+":\n\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + oErrFilesNotCopied.toString(), LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.message1Title")); //$NON-NLS-1$ oErrFilesNotCopied = null; } } }; thread.start(); } else if (tr.isDataFlavorSupported(DataFlavor.imageFlavor)) { e.acceptDrop(DnDConstants.ACTION_COPY); Image img = (Image)tr.getTransferData(DataFlavor.imageFlavor); if (img instanceof BufferedImage) { try { File newFile = new File(UIUtilities.sGetLinkedFilesLocation()+"External_Image_"+(new Date()).getTime()+".jpg"); //$NON-NLS-1$ //$NON-NLS-2$ ImageIO.write((RenderedImage)img, "jpeg", newFile); //$NON-NLS-1$ if (newFile.exists()) { String s = ""; //$NON-NLS-1$ if (newFile != null) s = newFile.getPath(); UINode node = oViewPaneUI.addNewNode(ICoreConstants.REFERENCE, nX, nY); node.setReferenceIcon(s); try { if (UIImages.isImage(s)) node.getNode().setSource("", s, sAuthor); //$NON-NLS-1$ else { node.getNode().setSource(s, "", sAuthor); //$NON-NLS-1$ } } catch(Exception ex) { log.info("error in UIViewPane.drop-4) \n\n"+ex.getMessage()); //$NON-NLS-1$ } node.setText(s); node.getUI().refreshBounds(); } } catch(IOException io) { log.info("io exception "+io.getMessage()); //$NON-NLS-1$ } } } else { e.rejectDrop(); } } catch (IOException io) { io.printStackTrace(); System.out.flush(); e.rejectDrop(); } catch (UnsupportedFlavorException ufe) { log.error("Error...", ufe); System.out.flush(); e.rejectDrop(); } } /** * Create a new node from a stencil item. * @param stencil, the stencil item to create the node from. * @param nX, the x position for the new node. * @param nY, the y position for the new node. */ public void createNodeFromStencil( DraggableStencilIcon stencil, int nX, int nY) { String sImage = stencil.getImage(); String sBackgroundImage = stencil.getBackgroundImage(); String sTemplate = stencil.getTemplate(); String sLabel = stencil.getLabel(); int nType = stencil.getNodeType(); Vector vtTags = stencil.getTags(); UINode node = oViewPaneUI.addNewNode(nType, nX, nY); node.setReferenceIcon(sImage); try { node.getNode().setSource("", sImage, sAuthor); //$NON-NLS-1$ } catch(Exception ex) { log.info("error in UIViewPane.createNodeFromStencil) \n\n"+ex.getMessage()); //$NON-NLS-1$ } node.setText(sLabel); node.getUI().setEditing(); // ADD THE TAGS IModel oModel = ProjectCompendium.APP.getModel(); PCSession oSession = oModel.getSession(); NodeSummary nodeSum = node.getNode(); int count = vtTags.size(); for(int i=0; i<count;i++) { Vector data = (Vector)vtTags.elementAt(i); String sID = (String)data.elementAt(0); String sName = (String)data.elementAt(1); String sAuthor = (String)data.elementAt(2); String sDescription = (String)data.elementAt(3); String sBehavior = (String)data.elementAt(4); Date dCreated = (Date)data.elementAt(5); Date dLastModified = (Date)data.elementAt(6); Code codeObj = null; try { // CHECK IF ALREADY IN DATABASE Vector existingCodesForName = (oModel.getCodeService()).getCodeIDs(oSession, sName); if (existingCodesForName.size() == 0) { codeObj = oModel.getCodeService().createCode(oSession, sID, sAuthor, dCreated, dLastModified, sName, sDescription, sBehavior); oModel.addCode(codeObj); // SHOULD I UPDATE THE XML STENCIL DATA? } else { String existingCodeID = (String)existingCodesForName.elementAt(0); codeObj = oModel.getCodeService().getCode(oSession, existingCodeID); } nodeSum.addCode(codeObj); } catch(Exception ex) { log.info("Unable to add tag = "+codeObj.getName()+"\n\ndue to:\n\n"+ex.getMessage()); } //$NON-NLS-1$ //$NON-NLS-2$ } // ADD BACKGROUND IMAGE AND TEMPLATE IF REQUIRED if (node.getNode() instanceof View) { View view = (View)node.getNode(); if (sBackgroundImage != null && !sBackgroundImage.equals("")) { //$NON-NLS-1$ try { view.setBackgroundImage(sBackgroundImage); view.updateViewLayer(); } catch(Exception ex) { log.info("error in UIViewPane.createNodeFromStencil) \n\n"+ex.getMessage()); //$NON-NLS-1$ } } if (sTemplate != null && !sTemplate.equals("")) { //$NON-NLS-1$ UIMapViewFrame mapFrame = null; try { view.initializeMembers(); mapFrame = new UIMapViewFrame(view, view.getLabel()); } catch(Exception ex) { log.error("Error...", ex); } if (mapFrame != null) { ProjectCompendium.APP.onTemplateImport(sTemplate, mapFrame.getViewPane()); } } } node.getUI().refreshBounds(); } /** * Create a new node representing the given file. * @param view the view to create the node in * @param file the file to represent * @param nX x coordinate of node * @param nY y coordinate of node * @param props drag and drop properties for creating the node. May be modified by this method, * e.g. to reflect user choices * @return true if node has been successfully created, false otherwise (user has cancelled or an * error occurred) */ public boolean createNode( View view, File file, int nX, int nY, DragAndDropProperties props ) { if (file.isDirectory()) { return createFolderNode( view, file, nX, nY, props ); } else { return createFileNode( view, file, nX, nY, props ); } } private boolean createFolderNode( View view, File file, int nX, int nY, DragAndDropProperties props ) { assert(file.isDirectory()); if (props.dndFolderPrompt) { // only ask once: props.dndFolderPrompt = false; UIDropFolderPopupMenu pm = new UIDropFolderPopupMenu( ProjectCompendium.APP ); pm.setLocation(nX, nY); pm.show(this); if (pm.selection == UIDropFolderPopupMenu.FolderDropAction.LINK) { props.dndFolderMap = false; props.dndFolderMapRecursively = false; } else if (pm.selection == UIDropFolderPopupMenu.FolderDropAction.MAP) { props.dndFolderMap = true; props.dndFolderMapRecursively = false; } else if (pm.selection == UIDropFolderPopupMenu.FolderDropAction.MAPRECURSIVE) { props.dndFolderMap = true; props.dndFolderMapRecursively = true; } else if (pm.selection == UIDropFolderPopupMenu.FolderDropAction.CANCEL) { return false; } } if (props.dndFolderMap) { return createMapFolderNode(view, file, nX, nY, props); } else { return createLinkNode(view, file, nX, nY); } } private boolean createFileNode( View view, File file, int nX, int nY, DragAndDropProperties props ) { assert( !file.isDirectory() ); UIDropImportPopupMenu.ImportAction iaction = UIDropImportPopupMenu.ImportAction.DROP; if (CoreUtilities.isPotentialExportFile(file)) { iaction = processPotentialExportFile(file, props, nX, nY); } if (iaction == UIDropImportPopupMenu.ImportAction.IMPORT) { return true; } else if (iaction == UIDropImportPopupMenu.ImportAction.DROP) { // do nothing - just skip to dropping according to props } else { assert false; } if (props.dndFilePrompt) { UIDropFilePopupMenu pm = new UIDropFilePopupMenu( ProjectCompendium.APP, props ); pm.setLocation(nX, nY); pm.show(this); // only ask once: props.dndFilePrompt = false; if (pm.selection == UIDropFilePopupMenu.FileDropAction.LINK) { props.dndFileCopy = false; } else if (pm.selection == UIDropFilePopupMenu.FileDropAction.COPY) { props.dndFileCopy = true; } else if (pm.selection == UIDropFilePopupMenu.FileDropAction.CANCEL) { return false; } } if (props.dndFileCopy) { return createCopyFileNode(view, file, nX, nY, props); } else { return createLinkNode(view, file, nX, nY); } } /** * Create a node which is a link to the given file. File may be a directory or a * normal file. * * @param view * @param file * @param nX * @param nY * @return true if the node was successfully created. */ private boolean createLinkNode( View view, File file, int nX, int nY ) { NodePosition np = addMemberNode( view, ICoreConstants.REFERENCE, file.getName(), file.toURI().toString(), "", nX, nY ); //$NON-NLS-1$ return (null != np); } /** * Create a map node for a file system folder. For each file in the folder, a node * is added in the map (wrt. prompting according to user settings). When * <code>recursive</code>, subfolders are added as maps themselves; folders are * omitted otherwise. * * @param view the View to create the node in * @param file the file system folder to create a map node for * @param nX x coordinate for node * @param nY y coordinate for node * @param props the drag and drop properties for this node and its subordinate nodes * @return */ private boolean createMapFolderNode( View view, File file, int nX, int nY, DragAndDropProperties props ) { assert(file.isDirectory()); NodePosition nodePos = addMemberNode(view, ICoreConstants.MAPVIEW, file.getName(), file.getPath(), "", nX, nY); //$NON-NLS-1$ if (null == nodePos) { return false; } nY += 80; View mapview = (View)nodePos.getNode(); boolean success = true; assert(mapview != null); File[] files = file.listFiles(); // all files in directory nX = 10; nY = 10; for (int i = 0; i < files.length && success; i++) { if ( !props.dndFolderMapRecursively && files[i].isDirectory() ) { success = createLinkNode(mapview, files[i], nX, nY); nY += 80; } else { success = createNode(mapview, files[i], nX, nY, props ); nY += 80; } } try { mapview.initializeMembers(); // refresh mapnode indicators } catch (ModelSessionException ex) { log.error("Error...", ex); log.info("ModelSession error in UIViewPane.createMapFolderNode initM \n\n" //$NON-NLS-1$ + ex.getMessage()); } catch (SQLException ex) { log.error("Error...", ex); log.info("SQL error in UIViewPane.createMapFolderNode initM \n\n" //$NON-NLS-1$ + ex.getMessage()); } return success; } /** * Create a node which is a copy of the given file. File may not be a directory. * * @param view * @param file * @param nX * @param nY * */ private boolean createCopyFileNode( View view, File file, int nX, int nY, DragAndDropProperties props ) { assert(!file.isDirectory()); LinkedFile lf = UIUtilities.copyDnDFile(file, props); if (lf == null) { oErrFilesNotCopied.append(file.getPath() + "\n"); //$NON-NLS-1$ return createLinkNode(view, file, nX, nY); } else { String sLabel = ((lf.getLFType() == LFType.DATABASE)? "[DB] " : "") + file.getName(); //$NON-NLS-1$ //$NON-NLS-2$ NodePosition np = addMemberNode(view, ICoreConstants.REFERENCE, sLabel, lf.getSourcePath(), "", nX, nY); //$NON-NLS-1$ return (null != np); } } private boolean isVisible( View view ) { return (getView() == view); // to be correct, we should look if there is any ViewPane instance // for the given View... is there a way to get a list of all // current ViewPanes? } /** * Add a new Node with the given data to the given view. * @param view the view to add a new node to * @param nType the type of the node from <code>ICoreConstants</code> * @param sLabel the label to display under the node * @param sSourceUri the URI or path of a file the node references to * @param sIconUri the URI or path of an icon to display for the node ("" for no icon) * @param nX x coordinate of the node * @param nY y coordinate of the node * @return the NodePosition object for the newly created node, or <code>null</code> if * the node could not be created */ private NodePosition addMemberNode( View view, int nType, String sLabel, String sSourceUri, String sIconUri, int nX, int nY ) { assert null != sIconUri; assert null != sSourceUri; assert null != sLabel; try { NodePosition nodePos = view.addMemberNode(nType, "", "", //$NON-NLS-1$ //$NON-NLS-2$ getCurrentAuthor(), sLabel, "", nX, nY); //$NON-NLS-1$ nodePos.getNode().setSource(sSourceUri, sIconUri, getCurrentAuthor()); if (isVisible(view)) { getUI().addNode(nodePos); } return nodePos; } catch (ModelSessionException ex) { log.error("Error...", ex); log.info("ModelSession error in UIViewPane.addMemberNode) \n\n" //$NON-NLS-1$ + ex.getMessage()); return null; } catch (SQLException ex) { log.error("Error...", ex); log.info("SQL error in UIViewPane.addMemberNode) \n\n" //$NON-NLS-1$ + ex.getMessage()); return null; } } /** * Ask user how to process the given potential Compendium export data file * and perform the import. * @param file the potential Compendium export file * @return the action selected by the user * @precondition CoreUtilities.isPotentialExportFile(file) */ private UIDropImportPopupMenu.ImportAction processPotentialExportFile(File file, DragAndDropProperties props, int x, int y) { UIDropImportPopupMenu ipm = new UIDropImportPopupMenu( ProjectCompendium.APP, file, props ); ipm.setLocation(x, y); ipm.show(this); if (ipm.selection == UIDropImportPopupMenu.ImportAction.IMPORT) { if (CoreUtilities.isZipFile(file)) { try { UIUtilities.unzipXMLZipFile(file.getAbsolutePath(), true); } catch(IOException io) { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.message3")+":\n\n"+io.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ } } else { ProjectCompendium.APP.onFileXMLImport(file); } } return ipm.selection; } // TRANSFERABLE /** * Returns an array of DataFlavor objects indicating the flavors the data * can be provided in. * @return an array of data flavors in which this data can be transferred */ public DataFlavor[] getTransferDataFlavors() { DataFlavor[] flavs = null; Set<DataFlavor> flavors = new HashSet<DataFlavor>(); for (Enumeration nodes = getSelectedNodes(); nodes.hasMoreElements() ;) { UINode node = (UINode) nodes.nextElement(); flavs = node.getTransferDataFlavors(); for(int i = 0; i < flavs.length; i++) { flavors.add(flavs[i]); } } return (DataFlavor[])flavors.toArray(new DataFlavor[0]); } /** * Returns whether or not the specified data flavor is supported for * this object. * @param flavor the requested flavor for the data * @return boolean indicating whether or not the data flavor is supported */ public boolean isDataFlavorSupported(DataFlavor flavor) { for (Enumeration nodes = getSelectedNodes(); nodes.hasMoreElements() ;) { UINode node = (UINode) nodes.nextElement(); // if one node in the current selection supports this flavor // we can support it too if((node != null) && (node.isDataFlavorSupported(flavor))) return true; } return false; } /** * Returns an object which represents the data to be transferred. The class * of the object returned is defined by the representation class of the flavor. * * @param flavor the requested flavor for the data * @return an object containing the dropped data * @see DataFlavor#getRepresentationClass * @exception IOException if the data is no longer available in the requested flavor. * @exception UnsupportedFlavorException if the requested data flavor is not supported. */ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor.equals(UINode.plainTextFlavor)) { ByteArrayOutputStream outBuf = new ByteArrayOutputStream(); ByteArrayInputStream inBuf; // append the contents of each node for (Enumeration nodes = getSelectedNodes(); nodes.hasMoreElements() ;) { UINode node = (UINode) nodes.nextElement(); inBuf = (ByteArrayInputStream)node.getTransferData(flavor); // prepend newline if multiple nodes were selected if(outBuf.size() > 0) outBuf.write('\n'); while(inBuf.available() > 0) outBuf.write(inBuf.read()); } return new ByteArrayInputStream(outBuf.toByteArray()); } else if(uriListFlavor.equals(flavor) || UINode.localStringFlavor.equals(flavor) || flavor.getHumanPresentableName().equals("UINode")) //$NON-NLS-1$ { StringBuilder builder = new StringBuilder(); for (Enumeration nodes = getSelectedNodes(); nodes.hasMoreElements() ;) { UINode node = (UINode) nodes.nextElement(); if(builder.length() > 0) // prepend newline if multiple nodes were selected builder.append('\n'); builder.append((String)node.getTransferData(flavor)); } return builder.toString(); } else if (DataFlavor.javaFileListFlavor.equals(flavor)) { LinkedList<File> buf = new LinkedList<File>(); for (Enumeration nodes = getSelectedNodes(); nodes.hasMoreElements() ;) { UINode node = (UINode) nodes.nextElement(); buf.addAll((List<File>)node.getTransferData(flavor)); } return buf; } // if everythings else failed, this must be a not supported flavor throw new UnsupportedFlavorException(flavor); } // DRAG AND DROP SOURCE /** * A <code>DragGestureRecognizer</code> has detected * a platform-dependent drag initiating gesture and * is notifying this listener * in order for it to initiate the action for the user. * <P>Currently only used to create links on the Mac platform.</p> * @param e the <code>DragGestureEvent</code> describing the gesture that has just occurred. */ public void dragGestureRecognized(DragGestureEvent e) { InputEvent in = e.getTriggerEvent(); if (in instanceof MouseEvent) { MouseEvent evt = (MouseEvent)in; boolean isLeftMouse = SwingUtilities.isLeftMouseButton(evt); if ((isLeftMouse && evt.getID() == MouseEvent.MOUSE_PRESSED) && ( (ProjectCompendium.isWindows && evt.isAltDown()) || (ProjectCompendium.isLinux && evt.isControlDown())) // only allow dnd if at least one node is selected && (oNode != null)) try { DragSource source = (DragSource)e.getDragSource(); source.startDrag(e, DragSource.DefaultCopyDrop, this, this); } catch(Exception io) { io.printStackTrace(); } } /*if (os.indexOf("windows") != -1) { if (isRightMouse || (isLeftMouse && isAltDown)) { // creating links log.info("In dragGestureRecognized = right mouse click recognised"); DragSource source = (DragSource)e.getDragSource(); source.addDragSourceListener(this); log.info("source = "+source); try { log.info("DragSource.DefaultLinkDrop = "+DragSource.DefaultLinkDrop); source.startDrag(e, DragSource.DefaultLinkDrop, this, this); log.info("After source.startDrag"); } catch(Exception io) { log.info("IN CATCH "+io.getMessage()); io.printStackTrace(); } } } else { */ /*if (ProjectCompendium.isMac) { boolean isLeftMouse = SwingUtilities.isLeftMouseButton(evt); //boolean isRightMouse = SwingUtilities.isRightMouseButton(evt); boolean isAltDown = evt.isAltDown(); //boolean isMiddleMouse = SwingUtilities.isMiddleMouseButton(evt); if (isLeftMouse && isAltDown) { // creating links //if (isRightMouse) { DragSource source = (DragSource)e.getDragSource(); /*DragGestureRecognizer dgr = e.getSourceAsDragGestureRecognizer(); int act = e.getDragAction(); Point ori = e.getDragOrigin(); ArrayList evs = new ArrayList(); for (Iterator it=e.iterator(); it.hasNext();) { Object obj = it.next(); if (obj.equals(evt)) { MouseEvent me = new MouseEvent((Component)evt.getSource(), evt.getID(), evt.getWhen(), 0, evt.getX(), evt.getY(), evt.getClickCount(), false, evt.getButton()); log.info("AFTER CHANGE mouse event "+me.toString()); evs.add(me); } else { evs.add(obj); } } java.util.List evsList = (java.util.List)evs; DragGestureEvent newE = new DragGestureEvent(dgr, act, ori, evsList); */ //log.info("source = "+source); /*try { source.startDrag(e, DragSource.DefaultLinkDrop, this, this); } catch(Exception io) { io.printStackTrace(); } } }*/ //} } /** * This method is invoked to signify that the Drag and Drop * operation is complete. The getDropSuccess() method of * the <code>DragSourceDropEvent</code> can be used to * determine the termination state. The getDropAction() method * returns the operation that the drop site selected * to apply to the Drop operation. Once this method is complete, the * current <code>DragSourceContext</code> and * associated resources become invalid. * <p>Here, clears dummy links draw while creating the new link. </p> * * @param e the <code>DragSourceDropEvent</code> */ public void dragDropEnd(DragSourceDropEvent e) { //getUI().clearDummyLinks(); } /** * Called as the cursor's hotspot enters a platform-dependent drop site. * This method is invoked when all the following conditions are true: * <UL> * <LI>The cursor's hotspot enters the operable part of a platform- * dependent drop site. * <LI>The drop site is active. * <LI>The drop site accepts the drag. * </UL> * HERE THE METHOD DOES NOTHING. * * @param e the <code>DragSourceDragEvent</code> */ public void dragEnter(DragSourceDragEvent e) { //log.info("IN drag Enter on Source"); } /** * Called as the cursor's hotspot exits a platform-dependent drop site. * This method is invoked when any of the following conditions are true: * <UL> * <LI>The cursor's hotspot no longer intersects the operable part * of the drop site associated with the previous dragEnter() invocation. * </UL> * OR * <UL> * <LI>The drop site associated with the previous dragEnter() invocation * is no longer active. * </UL> * OR * <UL> * <LI> The current drop site has rejected the drag. * </UL> * HERE THE METHOD DOES NOTHING. * * @param e the <code>DragSourceEvent</code> */ public void dragExit(DragSourceEvent e) { //log.info("IN drag Exit of Source"); } /** * Called as the cursor's hotspot moves over a platform-dependent drop site. * This method is invoked when all the following conditions are true: * <UL> * <LI>The cursor's hotspot has moved, but still intersects the * operable part of the drop site associated with the previous * dragEnter() invocation. * <LI>The drop site is still active. * <LI>The drop site accepts the drag. * </UL> * <p>Draws the dummy links, while link crateion is in progress.</p> * * @param dsde the <code>DragSourceDragEvent</code> */ public void dragOver(DragSourceDragEvent e) { //log.info("draw dummy links and dragsourcedrag event at "+e.getLocation()); //getUI().drawDummyLinks(e.getLocation()); } /** * Called when the user has modified the drop gesture. * This method is invoked when the state of the input * device(s) that the user is interacting with changes. * Such devices are typically the mouse buttons or keyboard * modifiers that the user is interacting with. * HERE THE METHOD DOES NOTHING. * * @param e the <code>DragSourceDragEvent</code> */ public void dropActionChanged(DragSourceDragEvent e) { //log.info("IN dropActionChanged of Source"); } ///////////////////////////////////////////// /** * Convenience Method to get Containing ViewFrame. * @return UIViewFrame, the parent frame for this view. */ public UIViewFrame getViewFrame() { return oViewFrame; } /** * Returns the L&F object that renders this component. * * @return ViewPaneUI, the object that renders this component. */ public ViewPaneUI getUI() { return oViewPaneUI; } /** * Sets the L&F object that renders this component. * <p>CURRENTLY DOES NOTHING</p> * @param ui, the ViewPaneUI L&F object. */ public void setUI(ViewPaneUI ui) { // if ((ViewPaneUI)this.ui != ui) { // super.setUI(ui); // repaint(); // } } /** * Notification from the UIManager that the L&F has changed. * Replaces the current UI object with the latest version from the * UIManager. * * @see JComponent#updateUI */ public void updateUI() { oViewPaneUI = new ViewPaneUI(this); //setUI(oViewPaneUI); invalidate(); } /** * Returns the name of the L&F class that renders this component. * * @return "ViewPaneUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI */ public String getUIClassID() { return "ViewPaneUI"; //$NON-NLS-1$ } /** * Overridden to always return true. * @return boolean, always returns true. */ public boolean isOpaque() { return true; } /** * Set the view that this view pane represents * * @param view com.compendium.core.datamodel.View, the view represented by this view pane. * @see com.compendium.core.datamodel.IView */ public void setView(View view) { View oldValue = oView; oView = view; firePropertyChange(VIEW_PROPERTY, oldValue, view); repaint(); } /** * Returns the view that this view pane represents. * * @return com.compendium.core.datamodel.View, the represented view * @see com.compendium.core.datamodel.IView */ public View getView() { return oView; } /** * Display popups listing the codes added to all node in this view. * <p>NOT CURRENTLY USED</p> */ public void showCodes() { for(Enumeration e = oView.getPositions();e.hasMoreElements();) { NodePosition nodepos = (NodePosition)e.nextElement(); NodeSummary summary = nodepos.getNode(); try { if (summary.getCodeCount() > 0 ) { int x = nodepos.getXPos(); int y = nodepos.getYPos(); UIHintNodeCodePanel pop = new UIHintNodeCodePanel(summary, x, y); add(pop, HINT_LAYER); pop.setVisible(true); tagPopups.put(summary.getId(), pop); } } catch(Exception ex) { log.info("Error: (UIViewPane.showCodes)\n\n"+ex.getMessage()); //$NON-NLS-1$ } } } /** * Calculate the position for the popup panel passed * @param pop the popup panel * @param realX the starting x * @param realY the starting y * @return the final location for the panel */private Point calculateLocation(JPanel pop, int realX, int realY) { Rectangle rect = getViewFrame().getViewport().getViewRect(); int screenWidth = rect.width; int screenHeight = rect.height; screenWidth = rect.x + screenWidth; screenHeight = rect.y + screenHeight; int endXCoordForPopUpMenu = realX + pop.getWidth(); int endYCoordForPopUpMenu = realY + pop.getHeight(); int offsetX = (screenWidth) - endXCoordForPopUpMenu; int offsetY = (screenHeight) - endYCoordForPopUpMenu; if(offsetX > 0) offsetX = 0; if(offsetY > 0) offsetY = 0; int finalX = realX+offsetX; if (realX+offsetX < rect.x) { finalX = rect.x; } return new Point(finalX, realY+offsetY); } /** * Show tags (codes) rollover popup for the given node. * @param node com.compendium.core.datamodel.NodeSummary, the node to show the tags for. * @param nX, the x position of the trigger event. * @param nY, the y position of the trigger event. */ public void showCodes(NodeSummary node, int nX, int nY) { if (!tagPopups.containsKey(node.getId())) { int realX = nX+hintOffset; int realY = nY+hintOffset; UIHintNodeCodePanel pop = new UIHintNodeCodePanel(node, realX, realY); Point newLoc= calculateLocation(pop, realX, realY); pop.setLocation(newLoc.x, newLoc.y); add(pop, HINT_LAYER); pop.setVisible(true); tagPopups.put(node.getId(), pop); } } /** * Hide all open tag rollover popups. */ public void hideCodes() { for(Enumeration e = tagPopups.elements() ;e.hasMoreElements();) { UIHintNodeCodePanel pop = (UIHintNodeCodePanel)e.nextElement(); remove(getIndexOf(pop)); pop.setVisible(false); pop = null; } tagPopups.clear(); invalidate(); repaint(); } /** * Show parent views rollover popup for the given node. * @param node com.compendium.core.datamodel.NodeSummary, the node to show the parent views for. * @param nX, the x position of the trigger event. * @param nY, the y position of the trigger event. */ public void showViews(NodeSummary node, int nX, int nY) { if (!viewsPopups.containsKey(node.getId())) { hideViews(); int realX = nX+hintOffset; int realY = nY+hintOffset; UIHintNodeViewsPanel pop = new UIHintNodeViewsPanel(node, realX, realY); Point newLoc= calculateLocation(pop, realX, realY); pop.setLocation(newLoc.x, newLoc.y); add(pop, HINT_LAYER); pop.setVisible(true); viewsPopups.put(node.getId(), pop); } } /** * Hide all parent views rollover popups. */ public void hideViews() { for(Enumeration e = viewsPopups.elements(); e.hasMoreElements();) { UIHintNodeViewsPanel pop = (UIHintNodeViewsPanel)e.nextElement(); remove(getIndexOf(pop)); pop.setVisible(false); pop = null; } viewsPopups.clear(); invalidate(); repaint(); } /** * Show node detail rollover popup for the given node. * @param node com.compendium.core.datamodel.NodeSummary, the node to show the detail for. * @param nX, the x position of the trigger event. * @param nY, the y position of the trigger event. */ public void showDetail(NodeSummary node, int nX, int nY) { if (!detailPopups.containsKey(node.getId())) { int realX = nX+hintOffset; int realY = nY+hintOffset; UIHintNodeDetailPanel pop = new UIHintNodeDetailPanel(node, realX, realY); Point newLoc= calculateLocation(pop, realX, realY); pop.setLocation(newLoc.x, newLoc.y); add(pop, HINT_LAYER); pop.setVisible(true); detailPopups.put(node.getId(), pop); } } /** * Hide all node detail rollover popups. */ public void hideDetail() { for(Enumeration e = detailPopups.elements(); e.hasMoreElements();) { UIHintNodeDetailPanel pop = (UIHintNodeDetailPanel)e.nextElement(); remove(getIndexOf(pop)); pop.setVisible(false); pop = null; } detailPopups.clear(); invalidate(); repaint(); } /** * Show node image rollover popup for the given node. * @param node com.compendium.core.datamodel.NodeSummary, the node to show the image for. * @param nX, the x position of the trigger event. * @param nY, the y position of the trigger event. */ public void showImage(NodeSummary node, int nX, int nY) { if (!imagePopups.containsKey(node.getId())) { UIViewFrame frame = getViewFrame(); UIHintNodeImagePanel pop = new UIHintNodeImagePanel(node, 0, 0, frame); int nChildWidth = pop.getSize().width; int nChildHeight = pop.getSize().height; Dimension dim = frame.getViewport().getExtentSize(); int nParentWidth = dim.width; int nParentHeight = dim.height; if (nChildWidth < nParentWidth) { pop.setLocation( ( (nParentWidth - nChildWidth) / 2 )+ frame.getHorizontalScrollBarPosition(), ( (nParentHeight - nChildHeight) / 2 ) + frame.getVerticalScrollBarPosition()); } else { pop.setLocation(0, 0); } add(pop, HINT_LAYER); pop.setVisible(true); imagePopups.put(node.getId(), pop); } } /** * Hide all image rollover poppups. */ public void hideImages() { for(Enumeration e = imagePopups.elements(); e.hasMoreElements();) { UIHintNodeImagePanel pop = (UIHintNodeImagePanel)e.nextElement(); remove(getIndexOf(pop)); pop.setVisible(false); pop = null; } imagePopups.clear(); invalidate(); repaint(); } /** * Return true is there are any open image rollover popups at present. * @return */ public boolean hasImages() { return (imagePopups.size() > 0); } /** * Show list of nodes to move to. * @param NodeSummary the node this list applies to. * @param Vector list list of nodes to move to. * @param nX the x position of the trigger event. * @param nY the y position of the trigger event. */ /*public void showNodeFocusList(UINode node, Vector list, int nX, int nY) { if (!nodeFocusPopups.containsKey(node.getNode().getId())) { UIHintNodeFocusPanel pop = new UIHintNodeFocusPanel(this, node, list, nX+hintOffset, nY+hintOffset); int realX = nX+hintOffset; int realY = nY+hintOffset; Rectangle rect = getViewFrame().getViewport().getViewRect(); int screenWidth = rect.width; int screenHeight = rect.height; screenWidth = rect.x + screenWidth; screenHeight = rect.y + screenHeight; int endXCoordForPopUpMenu = realX + pop.getWidth(); int endYCoordForPopUpMenu = realY + pop.getHeight(); int offsetX = (screenWidth) - endXCoordForPopUpMenu; int offsetY = (screenHeight) - endYCoordForPopUpMenu; if(offsetX > 0) offsetX = 0; if(offsetY > 0) offsetY = 0; //pop.setLocation(realX+offsetX, realY+offsetY); pop.setLocation(0, 0); add(pop, HINT_LAYER); pop.setVisible(true); nodeFocusPopups.put(node.getNode().getId(), pop); pop.focusList(); } }*/ /** * Hide all node focus list rollover popups. */ /*public void hideNodeFocusList() { for(Enumeration e = nodeFocusPopups.elements(); e.hasMoreElements();) { UIHintNodeFocusPanel pop = (UIHintNodeFocusPanel)e.nextElement(); remove(getIndexOf(pop)); pop.setVisible(false); pop = null; } nodeFocusPopups.clear(); invalidate(); repaint(); }*/ /** * Show the label search popup for the given node. * @param node com.compendium.core.datamodel.NodeSummary, the node to show the label search popup for. * @param text, the text to match in the search. */ public void showLabels(UINode node, String text) { if (text == null || text.equals("")) { //$NON-NLS-1$ if (labelPopups.containsKey(node.getNode().getId())) hideLabels(); return; } if (!labelPopups.containsKey(node.getNode().getId())) { Point p = node.getLocation(); Dimension d = node.getSize(); int nX = p.x; int nY = p.y; int realX = nX; int realY = nY+d.height; try { UIHintNodeLabelPanel pop = new UIHintNodeLabelPanel(this, node, realX, realY, text); add(pop, HINT_LAYER); pop.setVisible(true); labelPopups.put(node.getNode().getId(), pop); } catch(Exception ex) {} } else { UIHintNodeLabelPanel pop = (UIHintNodeLabelPanel)labelPopups.get(node.getNode().getId()); if (pop != null) { if (!pop.searchLabel(text, node.getNode().getId())) hideLabels(); } } } /** * Return the node search label panel for the given node id. * @param id, the node id of the node to return the search label panel for. * @return com.compendium.ui.panels.UIHintNodeLabelPanel */ public UIHintNodeLabelPanel getLabelPanel(String id) { if (labelPopups.containsKey(id)) return (UIHintNodeLabelPanel)labelPopups.get(id); return null; } /** * Hide all search label popups open - CURRENTLY ONLY ONE AT A TIME. */ public void hideLabels() { for(Enumeration e = labelPopups.elements() ;e.hasMoreElements();) { UIHintNodeLabelPanel pop = (UIHintNodeLabelPanel)e.nextElement(); remove(getIndexOf(pop)); pop.setVisible(false); pop = null; } labelPopups.clear(); invalidate(); repaint(); } /** * Refresh search label to redraw fonts. */ public void refreshLabels() { for(Enumeration e = labelPopups.elements() ;e.hasMoreElements();) { UIHintNodeLabelPanel pop = (UIHintNodeLabelPanel)e.nextElement(); pop.refresh(); } } /** * Return the scribble pad. */ public UIScribblePad getScribblePad() { return oScribblePad; } /** * Activate the scribble pad layer. */ public void showScribblePad() { if (oScribblePad == null) { oScribblePad = new UIScribblePad(this); oScribblePad.setPreferredSize(getSize()); oScribblePad.setSize(getSize()); ViewLayer viewlayer = oView.getViewLayer(); oScribblePad.processPencilData(viewlayer.getScribble()); oScribblePad.processShapesData(viewlayer.getShapes()); } add(oScribblePad, SCRIBBLE_LAYER); oViewFrame.setTitle(sTitle+ " - Scribble Pad"); //$NON-NLS-1$ oScribblePad.setVisible(true); } /** * Move scribble pad to back. */ public void moveBackScribblePad() { if (oScribblePad == null) { return; } setLayer(oScribblePad, SCRIBBLE_LAYER_BACK.intValue()); } /** * Move scribble pad to front. */ public void moveForwardScribblePad() { if (oScribblePad == null) { return; } setLayer(oScribblePad, SCRIBBLE_LAYER.intValue()); } /** * Is the scribble pad layer at the back of the node and links layers. * @return true if it is, else false; */ public boolean isScribblePadBack() { if (getLayer(oScribblePad) == SCRIBBLE_LAYER_BACK.intValue()) { return true; } return false; } /** * Remove the scribble pad layer. */ public void hideScribblePad() { if (oScribblePad != null) { oScribblePad.setVisible(false); oViewFrame.setTitle(sTitle); remove(getIndexOf(oScribblePad)); } } /** * Clear the scribble pad layer contents. */ public void clearScribblePad() { if (oScribblePad != null) oScribblePad.clearPad(); } /** * Save the scribble pad layer contents. */ public void saveScribblePad() { if (oScribblePad != null) { ProjectCompendium.APP.setWaitCursor(); ProjectCompendium.APP.setWaitCursor(oViewFrame); ViewLayer viewlayer = oView.getViewLayer(); String sScribble = oScribblePad.reversePencilData(); String sShapes = oScribblePad.reverseShapesData(); viewlayer.setShapes(sShapes); viewlayer.setScribble(sScribble); try { oView.updateViewLayer(); } catch(Exception ex) { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIViewPane.errorScribble")+":\n\n"+ex.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ } ProjectCompendium.APP.setDefaultCursor(oViewFrame); ProjectCompendium.APP.setDefaultCursor(); } } /** * Set the background image for this view. * * @param node com.compendium.core.datamodel.NodeSummary, the node to show the detail for. */ public void addBackgroundImage(String sImagePath) { if (lblBackgroundLabel != null) removeBackground(); lblBackgroundLabel = new JLabel(); ImageIcon oIcon = UIImages.createImageIcon(sImagePath); lblBackgroundLabel.setIcon(oIcon); lblBackgroundLabel.setLocation(0,0); lblBackgroundLabel.setSize(lblBackgroundLabel.getPreferredSize()); add(lblBackgroundLabel, BACKGROUNDIMAGE_LAYER); } /** * Set the background image for this view. * * @param node com.compendium.core.datamodel.NodeSummary, the node to show the detail for. */ public void removeBackground() { int index = getIndexOf(lblBackgroundLabel); if (index > -1) remove(index); } // NODE TRAVERSAL /** * Move to the next node upward. */ public void moveUp(UINode oUINode) { Component nodearray[] = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); int i=0; int nParentX = oUINode.getX(); int nParentY = oUINode.getY(); UINode uinode = null; int nChildX = 0; int nChildY = 0; while(i<nodearray.length) { uinode = (UINode)nodearray[i++]; nChildX = uinode.getX(); nChildY = uinode.getY(); } } /** * Move to the next node upward. */ public void moveDown(UINode uinode) { } /** * Move to the next node upward. */ public void moveLeft(UINode uinode) { } /** * Move to the next node upward. */ public void moveRight(UINode uinode) { } /** * Count the number of child node for the given node. * If one, move to that node. * If more than one, display a list to choose from. */ /*public void moveChild(UINode uinode) { String parentID = uinode.getNode().getId(); Vector children = new Vector(); for (Enumeration e = uinode.getLinks(); e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); UINode to = uilink.getToNode(); String toID = to.getNode().getId(); if (toID.equals(parentID)) { children.addElement(to); } } int count = children.size(); if (count == 1) { UINode node = (UINode)children.elementAt(0); uinode.requestFocus(); } else if (count > 1) { showNodeFocusList(uinode, children, uinode.getX(), uinode.getY()); } }*/ /** * Count the number of ancestor node for the given node. * If one, move to that node. * If more than one, display a list to choose from. */ /*public void moveAncestor(UINode uinode) { String parentID = uinode.getNode().getId(); Vector ancestors = new Vector(); for (Enumeration e = uinode.getLinks(); e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); UINode from = uilink.getFromNode(); String fromID = from.getNode().getId(); if (fromID.equals(parentID)) { ancestors.addElement(from); } } int count = ancestors.size(); if (count == 1) { UINode node = (UINode)ancestors.elementAt(0); uinode.requestFocus(); } else if (count > 1) { showNodeFocusList(uinode, ancestors, uinode.getX(), uinode.getY()); } }*/ // NODE SELECTION AND DESELECTION ROUTINES /** * Selects all the child links and nodes for the given node. * @param node com.compendium.ui.UINode, the node to select the children for. */ public void selectAllChildren(UINode node) { setSelectedNode(null, ICoreConstants.DESELECTALL); setSelectedLink(null, ICoreConstants.DESELECTALL); selectChildren(node); } /** * Selects all the child nodes for the given node. * @param node com.compendium.ui.UINode, the node to select the child nodes for. */ private void selectChildren(UINode uinode) { uinode.setSelected(true); setSelectedNode(uinode,ICoreConstants.MULTISELECT); String parentID = uinode.getNode().getId(); for (Enumeration e = uinode.getLinks(); e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); UINode from = uilink.getFromNode(); UINode to = uilink.getToNode(); String toID = to.getNode().getId(); if (toID.equals(parentID)) { uilink.setSelected(true); setSelectedLink(uilink,ICoreConstants.MULTISELECT); selectChildren(from); } } } /** * Delselect all links and nodes then select all the ancestor links and nodes for the given node. * i.e. up the tree, as opposed to down. * @param node com.compendium.ui.UINode, the node to select the ancestor links and nodes for. * @see #selectAllChildren */ public void selectAllAncestors(UINode node) { setSelectedNode(null, ICoreConstants.DESELECTALL); setSelectedLink(null, ICoreConstants.DESELECTALL); selectAncestors(node); } /** * Selects all the ancestor links and nodes the given node. * i.e. up the tree, as opposed to down. * @param node com.compendium.ui.UINode, the node to select the ancestor links and nodes for. * @see #selectAllAncestors * @see #selectAllChildren */ private void selectAncestors(UINode uinode) { uinode.setSelected(true); setSelectedNode(uinode,ICoreConstants.MULTISELECT); String parentID = uinode.getNode().getId(); for (Enumeration e = uinode.getLinks(); e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); UINode from = uilink.getFromNode(); UINode to = uilink.getToNode(); String fromID = from.getNode().getId(); if (fromID.equals(parentID)) { uilink.setSelected(true); setSelectedLink(uilink,ICoreConstants.MULTISELECT); selectAncestors(to); } } } /** * Selects all the links and nodes in the view. */ public void selectAll() { setSelectedNode(null, ICoreConstants.DESELECTALL); setSelectedLink(null, ICoreConstants.DESELECTALL); // get the uinode components in the viewpane layer Component nodearray[] = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); int i=0; UINode uinode = null; while(i<nodearray.length) { uinode = (UINode)nodearray[i++]; uinode.setSelected(true); setSelectedNode(uinode,ICoreConstants.MULTISELECT); } // get the uilink components in the viewpane layer Component linkarray[] = getComponentsInLayer((UIViewPane.LINK_LAYER).intValue()); i=0; UILink uilink = null; while(i<linkarray.length) { uilink = (UILink)linkarray[i++]; uilink.setSelected(true); setSelectedLink(uilink,ICoreConstants.MULTISELECT); } } /** * Sets the given node selection state in this view and signals the aerial view of the event. * * @param node com.compendium.ui.UINode, the node to set the selection state for. * @param mode, the selection state for the given node. */ public void setSelectedNode(UINode node, int mode) { ((UIMapViewFrame)oViewFrame).setAerialSelectedNode(node, mode); processSelectedNode(node, mode); } /** * Sets the given node selection state in this view without updating the aerial view * * @param node com.compendium.ui.UINode, the node to set the selection state for. * @param mode, the selection state for the given node. */ public void processSelectedNode(UINode node, int mode) { if(mode == ICoreConstants.SINGLESELECT) { oNode = node; // and deselect all the previous selected nodes for(Enumeration e = vtNodeSelected.elements();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); uinode.setSelected(false); uinode.setCut(false); } vtNodeSelected.removeAllElements(); addNode(node); ProjectCompendium.APP.setNodeOrLinkSelected(true); ProjectCompendium.APP.setNodeSelected(true); } if(mode == ICoreConstants.MULTISELECT) { oNode = node; addNode(node); ProjectCompendium.APP.setNodeOrLinkSelected(true); ProjectCompendium.APP.setNodeSelected(true); } if(mode == ICoreConstants.DESELECTALL) { if (getNumberOfSelectedLinks() == 0) ProjectCompendium.APP.setNodeOrLinkSelected(false); if(oNode != null) { if(oNode.equals(node)) return; oNode.setSelected(false); oNode.setCut(false); oNode = null; } // and all the previous selected nodes for(Enumeration e = vtNodeSelected.elements();e.hasMoreElements();) { UINode uinode = (UINode)e.nextElement(); if (uinode != null) { uinode.setSelected(false); uinode.setCut(false); } } vtNodeSelected.removeAllElements(); ProjectCompendium.APP.setNodeSelected(false); } } /** * Return the last node selected, if one is selected. * @return com.compendium.ui.UINode, the last currently selected node, else null. */ public UINode getSelectedNode() { return oNode; } /** * Return all the currently selected nodes. * @return Enumeration, all the currently selected nodes. */ public Enumeration getSelectedNodes() { return vtNodeSelected.elements(); } /** * Return a count of the number of nodes currently selected. * @return int, a count of the number of nodes currently selected. */ public int getNumberOfSelectedNodes() { int count = 0; count = vtNodeSelected.size(); return count; } /** * Adds a particular node to the already selected group. * @param node com.compendium.ui.UINode, the node to add the the group of selected nodes. */ public void addNode(UINode node) { if(!vtNodeSelected.contains(node)) vtNodeSelected.addElement(node); } /** * Remove a particular node to from selected group of nodes. * @param node com.compendium.ui.UINode, the node to remove from the group of selected nodes. */ public void removeNode(UINode node) { if(vtNodeSelected.contains(node)) vtNodeSelected.removeElement(node); } /** * Clear all selected nodes from the group list. */ public void emptySelectedNodes() { vtNodeSelected.removeAllElements(); } /////////////////////////// LINK SELECTION AND DESELECTION ROUTINES /////////////////////////// /** * Sets the given link selection state in this view and signals the aerial view of the event. * * @param link com.compendium.ui.UILink, the link to set the selection state for. * @param mode, the selection state for the given link. */ public void setSelectedLink(UILink link, int mode) { ((UIMapViewFrame)oViewFrame).setAerialSelectedLink(link, mode); processSelectedLink(link, mode); } /** * Sets the given link selection state in this view without updating the aerial view * * @param link com.compendium.ui.UILink, the link to set the selection state for. * @param mode, the selection state for the given link. */ public void processSelectedLink(UILink link, int mode) { if(mode == ICoreConstants.SINGLESELECT) { if(oLink != null) { // bz - not sure what this code is here for ... if(oLink.equals(link)) return; //deselect the previous link oLink.setSelected(false); oLink = link; // deselect all the previous selected links for(Enumeration e = vtLinkSelected.elements();e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); uilink.setSelected(false); } vtLinkSelected.removeAllElements(); addLink(link); } else { // bz - not sure what oLink is used here for ... oLink = link; // deselect all the previous selected nodes for(Enumeration e = vtLinkSelected.elements();e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); uilink.setSelected(false); } // add this node vtLinkSelected.removeAllElements(); addLink(link); } ProjectCompendium.APP.setNodeOrLinkSelected(true); } if(mode == ICoreConstants.MULTISELECT) { addLink(link); ProjectCompendium.APP.setNodeOrLinkSelected(true); } if(mode == ICoreConstants.DESELECTALL) { if(oLink != null) { oLink.setSelected(false); oLink = null; } // deselect all the previous selected links for(Enumeration e = vtLinkSelected.elements();e.hasMoreElements();) { UILink uilink = (UILink)e.nextElement(); uilink.setSelected(false); } vtLinkSelected.removeAllElements(); if (getNumberOfSelectedNodes() == 0) ProjectCompendium.APP.setNodeOrLinkSelected(false); } } /** * Return all the currently selected links. * @return Enumeration, all the currently selected links. */ public Enumeration getSelectedLinks() { return vtLinkSelected.elements(); } /** * Return a count of the number of links currently selected. * @return int, a count of the number of links currently selected. */ public int getNumberOfSelectedLinks() { return vtLinkSelected.size(); } /** * Adds a particular link to the already selected group. * @param link com.compendium.ui.UILink, the link to add the the group of selected links. */ public void addLink(UILink link) { if(!vtLinkSelected.contains(link)) vtLinkSelected.addElement(link); } /** * Remove a particular link to from selected group of links. * @param link com.compendium.ui.UILink, the link to remove from the group of selected links. */ public void removeLink(UILink link) { if(vtLinkSelected.contains(link)) vtLinkSelected.removeElement(link); } /** * Clear all selected links from the group list. */ public void emptySelectedLinks() { vtLinkSelected.removeAllElements(); } /** * Delete selected nodes and links in the view. * @param edit, the PCEdit object to add the deleted object to for undo/redo purposes. */ public void deleteSelectedNodesAndLinks(PCEdit edit) { Hashtable links = new Hashtable(51); // delete the NODES selected int i = 0; String sHomeViewID = ProjectCompendium.APP.getHomeView().getId(); String sInBoxID = ProjectCompendium.APP.getInBoxID(); IModel model = ProjectCompendium.APP.getModel(); for(Enumeration e = getSelectedNodes(); e.hasMoreElements(); i++) { UINode uinode = (UINode)e.nextElement(); String sNodeID = uinode.getNode().getId(); if (uinode.getType() != ICoreConstants.TRASHBIN && !sNodeID.equals(sInBoxID)) { NodeUI nodeui = uinode.getUI(); // IF YOU SOMEHOW GET YOUR HOMEVIEW AS A NODE AND TRY AND DELETE IT, // JUST REMOVE FROM VIEW, DO NOT ACTUALLY DELETE IT!!! if (sNodeID.equals(sHomeViewID)) { // StoreLinks being deleted for(Enumeration es = uinode.getLinks();es.hasMoreElements();) { UILink uilink = (UILink)es.nextElement(); links.put(uilink.getLink().getId(), uilink); } nodeui.deleteLinksforNode(uinode, edit); try { model.getViewService().removeMemberNode(model.getSession(), oView.getId() ,sNodeID); model.getViewService().purgeMemberNode(model.getSession(), oView.getId() ,sNodeID); } catch(Exception ex) { log.info("Unable to remove home view node from view = "+oView.getLabel()+" due to\n\n" +ex.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ } nodeui.removeFromUI(uinode); } else { // IF NODE ALREADY DELETED, DON'T TRY AND DELETE CHILDREN AGAIN // NEED TO CATCH NEVERENDING LOOP WHEN NODE CONTAINS ITSELF SOMEWHERE IN CHILDREN TREE boolean wasDeleted = false; try { if (model.getNodeService().isMarkedForDeletion(model.getSession(), uinode.getNode().getId())) { wasDeleted = true; } } catch (SQLException ex) { log.error("Error...", ex); } boolean deleted = nodeui.removeFromDatamodel(uinode); //if (deleted || wasDeleted) { // StoreLinks being deleted for(Enumeration es = uinode.getLinks();es.hasMoreElements();) { UILink uilink = (UILink)es.nextElement(); links.put(uilink.getLink().getId(), uilink); } nodeui.deleteLinksforNode(uinode, edit); edit.AddNodeToEdit(uinode); // IF NODE IS A VIEW AND IF NODE WAS ACTUALLY LAST INSTANCE AND HAS NOT ALREADY BEEN DELETED, DELETE CHILDREN if (uinode.getNode() instanceof View && deleted && !wasDeleted) { View childView = (View)uinode.getNode(); UIViewFrame childViewFrame = ProjectCompendium.APP.getViewFrame(childView, childView.getLabel()); childViewFrame.deleteChildren(childView); // delete from ProjectCompendium.APP opened frame list. ProjectCompendium.APP.removeViewFromHistory(childView); } // NEED TO CALL THIS TO REMOVE NODE nodeui.removeFromUI(uinode); //} } } } // PURGE ALL LINKS NOT ASSOCIATED WITH A NODE (OTHERS WILL ALREADY BE MARK FOR DELETION ABOVE) for(Enumeration et = getSelectedLinks();et.hasMoreElements();) { UILink uilink = (UILink)et.nextElement(); if (!links.containsKey(uilink.getLink().getId())) { LinkUI linkui = (LinkUI)uilink.getUI(); linkui.purgeLink(uilink); // save link in case operation needs to be undone. edit.AddLinkToEdit (uilink); } } setSelectedNode(null, ICoreConstants.DESELECTALL); setSelectedLink(null, ICoreConstants.DESELECTALL); hideImages(); repaint(); } /** * markSelectionSeen() - Marks all the nodes in the current selection as seen/read - mlb */ public void markSelectionSeen() { int i = 0; for(Enumeration e = getSelectedNodes(); e.hasMoreElements(); i++) { UINode uinode = (UINode)e.nextElement(); try { uinode.getNode().setState(ICoreConstants.READSTATE); } catch (SQLException ex) { log.error("Error...", ex); } catch (ModelSessionException ex1) { ex1.printStackTrace(); } } // setSelectedNode(null, ICoreConstants.DESELECTALL); // mlb: Uncomment this to deselect after performing the action // setSelectedLink(null, ICoreConstants.DESELECTALL); repaint(); return; } /** * markSelectionUnseen() - Marks all the nodes in the current selection as unseen/unread - mlb */ public void markSelectionUnseen() { int i = 0; for(Enumeration e = getSelectedNodes(); e.hasMoreElements(); i++) { UINode uinode = (UINode)e.nextElement(); try { uinode.getNode().setState(ICoreConstants.UNREADSTATE); } catch (SQLException ex) { log.error("Error...", ex); } catch (ModelSessionException ex1) { ex1.printStackTrace(); } } // setSelectedNode(null, ICoreConstants.DESELECTALL); // mlb: Uncomment this to deselect after performing the action // setSelectedLink(null, ICoreConstants.DESELECTALL); repaint(); return; } ////////////////////////////////////////////////////////////////////////////// /** * Adds a component to this view. * * @param c the component to be added. * @param constraints an object expressing layout contraints for this component. * @see java.awt.LayoutManager */ public void add(Component c, Object constraints) { if (c instanceof UINode) { UINode node = (UINode)c; UINode oldnode = (UINode)get(node.getNode().getId()); if (oldnode == null) { super.add(c, constraints); } } else if (c instanceof UILink) { UILink link = (UILink)c; if (link.getLink() != null) { UILink oldlink = (UILink)get(link.getLink().getId()); if (oldlink == null) super.add(c, constraints); } else { // DUMMY LINKS super.add(c, constraints); } } else { super.add(c, constraints); } // add drag and drop capabilities for nodes if (c instanceof UINode) { UINode node = (UINode)c; // Fix for Aerial view delete then undo // Was putting node back in main view at aerial view scale scaleNode(node, 1.0); if (currentScale != 1.0) { scaleNode(node, currentScale); } //checkScale(node); checkFont(node); node.addPropertyChangeListener(this); moveToFront(c); } } /** * Removes a component from this view. * * @param c the component to be removed * @see java.awt.LayoutManager */ public void remove(Component c) { super.remove(c); repaint(); } /** * Removes all components from this view, * @see java.awt.LayoutManager */ public void removeAllComponents() { Component [] array = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); for(int i=0;i<array.length;i++) { JComponent object = (JComponent)array[i]; remove(object); } Component [] array1 = getComponentsInLayer((UIViewPane.LINK_LAYER).intValue()); for(int i=0;i<array1.length;i++) { JComponent object = (JComponent)array1[i]; remove(object); } repaint(); } /** * Retrieves a component from this view based on it Id. * * @param id of the component to remove. * @see java.awt.LayoutManager */ public void removeObject(String id) { Component [] array = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); for(int i=0;i<array.length;i++) { JComponent object = (JComponent)array[i]; UINode uinode = (UINode)object; if(uinode.getNode().getId().equals(id)) remove(uinode); } Component [] array1 = getComponentsInLayer((UIViewPane.LINK_LAYER).intValue()); for(int i=0;i<array1.length;i++) { JComponent object = (JComponent)array1[i]; UILink uilink = (UILink)object; if(uilink.getLink().getId().equals(id)) remove(uilink); } } /** * Retrieves a component from this view based on it Id. * * @param id of the component to return. * @return Object, the object with the given id. * @see java.awt.LayoutManager */ public Object get(String id) { Component [] array = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); for(int i=0;i<array.length;i++) { JComponent object = (JComponent)array[i]; UINode uinode = (UINode)object; if(uinode != null && uinode.getNode() != null && uinode.getNode().getId().equals(id)) return uinode; } Component [] array1 = getComponentsInLayer((UIViewPane.LINK_LAYER).intValue()); for(int i=0;i<array1.length;i++) { JComponent object = (JComponent)array1[i]; UILink uilink = (UILink)object; if(uilink != null && uilink.getLink() != null && uilink.getLink().getId().equals(id)) return uilink; } return null; } /** * Update the node icon indicators of the nodes in this view. */ public void refreshIconIndicators() { Component array[] = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); UINode uinode = null; for (int j = 0; j < array.length; j++) { uinode = (UINode)array[j]; uinode.getUI().refreshBounds(); } } /** * Update the icon indicator of the node with the specific sNodeID. */ public void refreshNodeIconIndicators(String sNodeID) { Component array[] = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); UINode uinode = null; for (int j = 0; j < array.length; j++) { uinode = (UINode)array[j]; if ( (uinode.getNode().getId()).equals(sNodeID) ) uinode.getUI().refreshBounds(); } } /** * Go through all layers in this view and repaint their objects. */ public void validateComponents() { repaint(); Component[] array0 = getComponentsInLayer((UIViewPane.BACKGROUNDIMAGE_LAYER).intValue()); for(int i=0;i<array0.length;i++) { JComponent object = (JComponent)array0[i]; object.revalidate(); object.repaint(); } Component [] array = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); for(int i=0;i<array.length;i++) { JComponent object = (JComponent)array[i]; object.revalidate(); object.repaint(); } Component [] array1 = getComponentsInLayer((UIViewPane.LINK_LAYER).intValue()); for(int i=0;i<array1.length;i++) { JComponent object = (JComponent)array1[i]; object.revalidate(); object.repaint(); } } /** * Return an instance of the right-click popup menu for this view. * @return com.compendium.ui.UIViewPopupMenu, the popup menu for this view. */ public UIViewPopupMenu getPopupMenu() { if (viewPopup == null) viewPopup = new UIViewPopupMenu("View Popup menu", getUI()); //$NON-NLS-1$ return viewPopup; } /** * Create and display an instance of the right-click popup menu for this view. * @param com.compendium.ui.plaf.ViewPaneUI, the ui object for this view required as a parameter for the popup. * @param x, the x position of the trigger event for this request. Used to calculate the popup x position. * @param y, the y position of the trigger event for this request. Used to calculate the popup y position. */ public void showPopupMenu(ViewPaneUI viewpaneui, int x, int y) { viewPopup = new UIViewPopupMenu("View Popup Menu", viewpaneui); //$NON-NLS-1$ UIViewFrame viewFrame = oViewFrame; Dimension dim = ProjectCompendium.APP.getScreenSize(); int screenWidth = dim.width - 70; //to accomodate for the scrollbar int screenHeight = dim.height-120; //to accomodate for the menubar... Point point = getViewFrame().getViewPosition(); int realX = Math.abs(point.x - x)+20; int realY = Math.abs(point.y - y)+20; int endXCoordForPopUpMenu = realX + viewPopup.getWidth(); int endYCoordForPopUpMenu = realY + viewPopup.getHeight(); int offsetX = (screenWidth) - endXCoordForPopUpMenu; int offsetY = (screenHeight) - endYCoordForPopUpMenu; if(offsetX > 0) offsetX = 0; if(offsetY > 0) offsetY = 0; viewPopup.setCoordinates(realX+offsetX, realY+offsetY); viewPopup.setViewPane(this); viewPopup.show(viewFrame,realX+offsetX, realY+offsetY); } // PRINT METHODS /** * Caculate the size of the used map area and return this as a Dimension. * @return Dimension, the size of the used map area */ public Dimension calculateSize() { //get all the nodes this UIViewPane contains Component nodes[] = getComponentsInLayer(UIViewPane.NODE_LAYER.intValue()); int maxWidth = 0; int maxHeight = 0; int index = 0; //calculate the area which contains all the nodes in this UIViewPane for subsquent calculating //this should be implemented for only calculating once for a printing job. //at present, every call to this print() will excute this chunk of code again for //every page to be printed in the same printing job. Quite stupid codes. while(index < nodes.length) { UINode node = (UINode) nodes[index]; //log.info("node x coord is: " + node.getX() + "\nnode y coord is: " + node.getY()); int width = node.getX() + node.getWidth(); int height = node.getY() + node.getHeight(); if( width > maxWidth){ maxWidth = width; } if( height > maxHeight){ maxHeight = height; } index ++; } Dimension viewPaneSize = new Dimension( maxWidth, maxHeight); // IF HAS BACKGROUND IMAGE, CHECK IF SIZE GREATER THAN ABOVE AND IF SO, CHANGE. String image = oView.getImage(); if (lblBackgroundLabel != null) { Dimension labelSize = lblBackgroundLabel.getPreferredSize(); if (labelSize.width > viewPaneSize.width) viewPaneSize.width = labelSize.width; if(labelSize.height > viewPaneSize.height) viewPaneSize.height = labelSize.height; } return viewPaneSize; } /** * Print the contents of this maps used area. * @param g, the Graphics object to use for the paint. * @param pageFormat, the format to use for the print. * @param pageIndex, the index of the page being printed. */ public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException{ Graphics2D g2d = (Graphics2D) g; int columnNum = 0;//the number of columns to be printed of current UIViewPane int rowNum = 0;//the number of rows to be printed int totalPageNum = 0;//the number of total pages on current UIViewPane double paperWidth = 0.0; double paperHeight = 0.0; Dimension viewPaneSize = calculateSize(); //the width within which the printer is going to print paperWidth = pageFormat.getImageableWidth(); //the height within which the printer will print paperHeight = pageFormat.getImageableHeight(); columnNum = (int) Math.ceil(viewPaneSize.getWidth()/paperWidth); rowNum = (int) Math.ceil(viewPaneSize.getHeight()/paperHeight); totalPageNum = columnNum * rowNum; //above several line codes for calculating numbers of pages to be printed //they should be excuted once as well, I think //make sure no empty output if(columnNum == 0 || rowNum == 0 || pageIndex >= totalPageNum){ return Printable.NO_SUCH_PAGE; } RepaintManager currentManager = RepaintManager.currentManager(this); currentManager.setDoubleBufferingEnabled(false); //paint the page to be printed paint(preparePage(g2d, pageFormat, pageIndex, columnNum, viewPaneSize)); currentManager.setDoubleBufferingEnabled(true); return Printable.PAGE_EXISTS; } /** * Prepare page to be printed. * It is assumed that the printing area begins at (0, 0) of current UIViewPane. * * @param g, the Graphics object to use for the paint. * @param pageFormat, the format to use for the print. * @param pageIndex, the index of the page being printed. * @param columnNum, the number of the current column being printed. * @param viewPaneSize, the size of the area being printed. */ private Graphics2D preparePage(Graphics2D g2d, PageFormat pf, int pageIndex, int columnNum, Dimension viewPaneSize){ int imageableX = (int) pf.getImageableX(); int imageableY = (int) pf.getImageableY(); int paperWidth = (int) pf.getImageableWidth(); int paperHeight = (int) pf.getImageableHeight(); //move the coordinates to printing starting coordinates g2d.translate(imageableX, imageableY); //caculate which page to render if(columnNum == 1){ //move the coordinates vertically to the page to be printed g2d.translate(0, -pageIndex * paperHeight); //double scale = pf.getImageableWidth() / viewPaneSize.getWidth(); //g2d.scale(scale, scale); //scale to the paper size, could be optional } else{ //calculate which page should be current one int currentRow = pageIndex/columnNum; int currentColumn = pageIndex - currentRow * columnNum; //move the coordinates to the page to be printed g2d.translate( -currentColumn * paperWidth, -currentRow * paperHeight); } return g2d; } // ZOOM METHODS /** * Return the current view scale. */ public double getScale() { return currentScale; } /** * Scale the nodes and links and their locations in this view. */ public void scale() { Component [] array = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); for(int i=0;i<array.length;i++) { UINode node = (UINode)array[i]; scaleNode(node, currentScale); } //scale background image if (lblBackgroundLabel != null && lblBackgroundLabel.isVisible()) { ImageIcon oIcon = UIImages.createImageIcon(oView.getViewLayer().getBackgroundImage()); int imgWidth = oIcon.getIconWidth(); int imgHeight = oIcon.getIconHeight(); if (imgWidth != 0 && imgHeight != 0) { int scaledW = (int)(currentScale*imgWidth); int scaledH = (int)(currentScale*imgHeight); if (scaledW != 0 && scaledH != 0) { ImageFilter filter = new AreaAveragingScaleFilter(scaledW, scaledH); FilteredImageSource filteredSource = new FilteredImageSource((ImageProducer)oIcon.getImage().getSource(), filter); JLabel comp = new JLabel(); Image img = comp.createImage(filteredSource); oIcon = new ImageIcon(img); lblBackgroundLabel.setIcon(oIcon); lblBackgroundLabel.setLocation(0,0); lblBackgroundLabel.setSize(lblBackgroundLabel.getPreferredSize()); repaint(); } } } //repaint scribble layer to cause scale to happen if (oScribblePad != null && oScribblePad.isVisible()) { oScribblePad.repaint(); } } /** * Scale the given node to the given scale. * * @param node, the node to scale. * @param scale, the scale to use. */ public void scaleNode(UINode node, double scale) { NodePosition pos = node.getNodePosition(); if (scale != 0.0 && scale != 1.0) { node.setScale(scale); // SCALE FONT - setFont scales font. node.setFont(node.getFont()); // SCALE ICON - calls setIcon which scales to scale set in node. node.restoreIcon(); // SCALE LOCATION - setLocation scales location node.setLocation(pos.getPos()); // SCALE LINK ARROW HEAD AND TEXT AffineTransform trans=new AffineTransform(); trans.setToScale(scale, scale); node.scaleLinks(trans); } else { node.setScale(1.0); // RESET FONT node.setFont(new Font(pos.getFontFace(), pos.getFontStyle(), pos.getFontSize())); // RESET ICON node.restoreIcon(); // RESTORE LOCATION TO 100% node.setLocation(pos.getPos()); // RESTORE THE LINKS node.scaleLinks(null); } } /** * Used when new node is added to view to check if it needs scaling, and if it does, do it. * @param node com.compendium.ui.UINode, the node to scale. */ public void checkScale(UINode node) { double currentNodeScale = node.getScale(); // ONLY RESCALE IF NECESSARY if (currentNodeScale != currentScale) { node.setScale(currentScale); // SCALE FONT - setFont scales font. node.setFont(node.getFont()); // SCALE ICON - calls setIcon which scales to scale set in node. node.restoreIcon(); //node.setIcon(icon); // SCALE LOCATION - setLocation scales location node.setLocation(node.getNodePosition().getPos()); } } /** * Used when new node is added to view to check if it needs font adjustment, and if it does, do it. * @param node com.compendium.ui.UINode, the node to scale. */ public void checkFont(UINode node) { int fontZoom = ProjectCompendium.APP.getToolBarManager().getTextZoom(); if (fontZoom != 0) { Font font = node.getFont(); node.setFontSize(font.getSize()+fontZoom); } } /** * Return the font size to its default * (To what is stored in the database with current map zoom applied) */ public void onReturnTextToActual() { Component[] nodes = getComponentsInLayer(UIViewPane.NODE_LAYER.intValue()); int count = nodes.length; UINode node = null; UINodeContentDialog dlg = null; for (int i=0; i<count;i++) { node = (UINode)nodes[i]; node.setDefaultFont(); dlg = node.getCurrentContentDialog(); if (dlg != null) { dlg.refreshFont(); } } Component[] links = getComponentsInLayer(UIViewPane.LINK_LAYER.intValue()); count = links.length; UILink link = null; for (int i=0; i<count;i++) { link = (UILink)links[i]; link.setDefaultFont(); } refreshLabels(); } /** * Increase the currently dislayed font size by one point. * (This does not change the stored value in the database) */ public void onIncreaseTextSize() { Component[] nodes = getComponentsInLayer(UIViewPane.NODE_LAYER.intValue()); int count = nodes.length; UINode node = null; UINodeContentDialog dlg = null; for (int i=0; i<count;i++) { node = (UINode)nodes[i]; node.increaseFontSize(); dlg = node.getCurrentContentDialog(); if (dlg != null) { dlg.refreshFont(); } } Component[] links = getComponentsInLayer(UIViewPane.LINK_LAYER.intValue()); count = links.length; UILink link = null; for (int i=0; i<count;i++) { link = (UILink)links[i]; link.increaseFontSize(); } refreshLabels(); } /** * Reduce the currently dislayed font size by one point. * (This does not change the stored value in the database) */ public void onReduceTextSize() { Component[] nodes = getComponentsInLayer(UIViewPane.NODE_LAYER.intValue()); int count = nodes.length; UINode node = null; UINodeContentDialog dlg = null; for (int i=0; i<count;i++) { node = (UINode)nodes[i]; node.decreaseFontSize(); dlg = node.getCurrentContentDialog(); if (dlg != null) { dlg.refreshFont(); } } Component[] links = getComponentsInLayer(UIViewPane.LINK_LAYER.intValue()); count = links.length; UILink link = null; for (int i=0; i<count;i++) { link = (UILink)links[i]; link.decreaseFontSize(); } refreshLabels(); } //*********************** PROPERTY CHANGE LISTENER *************************/ /** * Handles property change events. * @param evt, the associated PropertyChangeEvent object. */ public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); Object source = evt.getSource(); Object oldvalue = evt.getOldValue(); Object newvalue = evt.getNewValue(); if (source instanceof View) { if (prop.equals(View.LINK_ADDED)) { LinkProperties link = (LinkProperties)newvalue; ((UIMapViewFrame)oViewFrame).addAerialLink(link); } else if (prop.equals(View.LINK_REMOVED)) { LinkProperties link = (LinkProperties)newvalue; ((UIMapViewFrame)oViewFrame).removeAerialLink(link.getLink()); } else if (prop.equals(View.NODE_ADDED)) { NodePosition oNodePos = (NodePosition)newvalue; ((UIMapViewFrame)oViewFrame).addAerialNode(oNodePos); } else if (prop.equals(View.NODE_TRANSCLUDED)) { NodePosition oNodePos = (NodePosition)newvalue; ((UIMapViewFrame)oViewFrame).addAerialNode(oNodePos); } else if (prop.equals(View.NODE_REMOVED)) { NodeSummary node = (NodeSummary)newvalue; ((UIMapViewFrame)oViewFrame).removeAerialNode(node); } } else if (source instanceof UINode) { if (prop.equals(UINode.ROLLOVER_PROPERTY)) { UINode node = (UINode)source; ((UIMapViewFrame)oViewFrame).setAerialRolloverNode(node, ((Boolean)newvalue).booleanValue()); } else if (prop.equals(NodePosition.POSITION_PROPERTY)) { UINode uinode = (UINode)source; Point oPoint = (Point)newvalue; Point transPoint = UIUtilities.transformPoint(oPoint.x, oPoint.y, currentScale); // CHECK THAT THIS NODE WAS NOT THE ONE ORIGINATING THE EVENT Point location = uinode.getLocation(); if (location.x != transPoint.x && location.y != transPoint.y) { uinode.setBounds(transPoint.x, transPoint.y, uinode.getWidth(), uinode.getHeight()); uinode.updateLinks(); } } } } /** * Clean up the components and variables used by this class to help with garbage collection. */ public void cleanUp() { Component[] array0 = getComponentsInLayer((UIViewPane.BACKGROUNDIMAGE_LAYER).intValue()); for(int i=0;i<array0.length;i++) { JComponent object = (JComponent)array0[i]; object = null; } Component [] array = getComponentsInLayer((UIViewPane.NODE_LAYER).intValue()); for(int i=0;i<array.length;i++) { JComponent object = (JComponent)array[i]; UINode uinode = (UINode)object; uinode.cleanUp(); uinode = null; } Component [] array1 = getComponentsInLayer((UIViewPane.LINK_LAYER).intValue()); for(int i=0;i<array1.length;i++) { JComponent object = (JComponent)array1[i]; object = null; } if (this.getUI() != null) this.getUI().uninstallUI(this); oView = null; oViewFrame = null; oViewPaneUI = null; oNode = null; oLink = null; dropTarget = null; oScribblePad = null; if (vtNodeSelected != null) vtNodeSelected.removeAllElements(); vtNodeSelected = null; if (vtLinkSelected != null) vtLinkSelected.removeAllElements(); vtLinkSelected = null; if (tagPopups != null) tagPopups.clear(); tagPopups = null; if (detailPopups != null) detailPopups.clear(); detailPopups = null; if (viewsPopups != null) viewsPopups.clear(); viewsPopups = null; } }