/********************************************************************************
* *
* (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.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
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.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AreaAveragingScaleFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
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.ICoreConstants;
import com.compendium.core.datamodel.IModel;
import com.compendium.core.datamodel.LinkedFile;
import com.compendium.core.datamodel.LinkedFileDatabase;
import com.compendium.core.datamodel.Model;
import com.compendium.core.datamodel.ModelSessionException;
import com.compendium.core.datamodel.MovieMapView;
import com.compendium.core.datamodel.NodeDetailPage;
import com.compendium.core.datamodel.NodePosition;
import com.compendium.core.datamodel.NodePositionTime;
import com.compendium.core.datamodel.NodeSummary;
import com.compendium.core.datamodel.TimeMapView;
import com.compendium.core.datamodel.View;
import com.compendium.ui.dialogs.UINodeContentDialog;
import com.compendium.ui.linkgroups.UILinkGroup;
import com.compendium.ui.plaf.NodeUI;
import com.compendium.ui.popups.UINodePopupMenu;
/**
* Holds the data for and handles the events of a node in a map.
*
* @author Mohammed Sajid Ali / Michelle Bachler
*/
public class UINode extends JComponent implements PropertyChangeListener, SwingConstants,
Transferable, DropTargetListener, DragSourceListener, DragGestureListener {
/**
* class's own logger
*/
final Logger log = LoggerFactory.getLogger(getClass());
/** A reference to the text property for PropertyChangeEvents.*/
public static final String TEXT_PROPERTY = "text"; //$NON-NLS-1$
/** A reference to the icon property for PropertyChangeEvents.*/
public static final String ICON_PROPERTY = "icon"; //$NON-NLS-1$
/** A reference to the children property for PropertyChangeEvents.*/
public final static String CHILDREN_PROPERTY = "children"; //$NON-NLS-1$
/** A reference to the rollover property for PropertyChangeEvents.*/
public final static String ROLLOVER_PROPERTY = "rollover"; //$NON-NLS-1$
/** A reference to the node type property for PropertyChangeEvents.*/
public final static String TYPE_PROPERTY = "nodetype"; //$NON-NLS-1$
/** A reference to the selected property for PropertyChangeEvents.*/
public static final String SELECTED_PROPERTY = "selected"; //$NON-NLS-1$
/** The default font to use for node labels.*/
private static final Font NODE_FONT = new Font("Sans Serif", Font.PLAIN, 12); //$NON-NLS-1$
/** The DataFlavour for external string based drag and drop operations.*/
public static final DataFlavor plainTextFlavor = DataFlavor.plainTextFlavor;
/** The DataFlavour for internal string based drag and drop operations.*/
public static final DataFlavor localStringFlavor = DataFlavor.stringFlavor;
/** The DataFlavour for external drag and drop of file reference nodes **/
public static final DataFlavor fileListFlavor = DataFlavor.javaFileListFlavor;
/** 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;
/** The DataFlavour for internal object based drag and drop operations.*/
public static DataFlavor nodeFlavor = null;
/** The deafult node icon for this node.*/
private ImageIcon oDefaultIcon = null;
/** The current node icon for this node.*/
private ImageIcon oCurrentIcon = null;
/** Is this node currently selected?*/
private boolean bSelected = false;
/** Has this node been cut?*/
private boolean bCut = false;
/** Has this node been rolloved over?*/
private boolean bRollover = false;
/** Indicates if the image has been scaled.*/
private boolean bIsImageScaled = false;
/** The label text for this node.*/
private String sText = ""; //$NON-NLS-1$
/** The distance for the gap between the node icon and its text.*/
private int nIconTextGap = 4;
/** The current font to use for the node label text.*/
protected Font oFont = null;
/** A List of the Link objects associated with this node.*/
private Hashtable htLinks = new Hashtable();
/** The drag source object associated with this node.*/
private DragSource dragSource = null;
/** The drop target object associated with this node.*/
private DropTarget dropTarget = null;
/** The node right-click popup menu associated with this node - null if one has not been opened yet.*/
private UINodePopupMenu nodePopup = null;
/** The node contents dialog associated with this node - null if one has not been opened yet.*/
private UINodeContentDialog contentDialog = null;
/** The node data object associated with this UINode.*/
private NodeSummary oNode = null;
/** The NodePosition object associated with this node.*/
private NodePosition oPos = null;
/** The node type of this node.*/
private int oNodeType = -1;
/** The current scale factor for this node in its parent view.*/
private double scale = 1.0;
/** A local reference to the name of the current computer platform.*/
//private String os = "";
private Date focusGainedDate = null;
private String originalLabel = null;
/** The user author name of the current user */
private String sAuthor = ""; //$NON-NLS-1$
/**
* Create a new UINode instance with the given NodePosition object for data.
* @param nodePos the object with the node data for this UINode.
* @param sAuthor the author name of the current user.
* @param sUserID the id of the current user.
*/
public UINode(NodePosition nodePos, String sAuthor) {
//os = ProjectCompendium.platform.toLowerCase();
/* 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);
dropTarget = new DropTarget(this, this);
nodeFlavor = new DataFlavor(this.getClass(), "UINode"); //$NON-NLS-1$
oPos = nodePos;
setDefaultFont();
this.setCursor(new Cursor(java.awt.Cursor.HAND_CURSOR));
this.sAuthor = sAuthor;
addFocusListener( new FocusListener() {
public void focusGained(FocusEvent e) {
focusGainedDate = new Date();
originalLabel = oPos.getNode().getLabel();
repaint();
}
public void focusLost(FocusEvent e) {
if (oNode == null) {
oNode = oPos.getNode();
}
String sUserName="Unknown";
Model oModel = (Model)ProjectCompendium.APP.getModel();
if (oModel != null) {
sUserName = ProjectCompendium.APP.getModel().getUserProfile().getUserName();
}
try {
if (oNode.flushLabel(sUserName)) {
NodeUI nodeui = getUI(); // Label length changed, so update node's view position
nodeui.flushPosition();
}
} catch (SQLException e1) {
e1.printStackTrace();
log.info("Error: (UINode.showContentDialog) \n\n"+e1.getMessage()); //$NON-NLS-1$
} catch (ModelSessionException e2) {
e2.printStackTrace();
log.info("Error: (UINode.showContentDialog) \n\n"+e2.getMessage()); //$NON-NLS-1$
}
getUI().resetEditing();
repaint();
}
});
NodeSummary node = nodePos.getNode();
setNode(node);
updateUI();
}
/**
* 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;
if (getType() == ICoreConstants.REFERENCE) {
flavs = new DataFlavor[] { DataFlavor.javaFileListFlavor, uriListFlavor };
}
else {
flavs = new DataFlavor[] { UINode.nodeFlavor,
UINode.plainTextFlavor,
UINode.localStringFlavor};
}
return flavs;
}
/**
* 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) {
if ((flavor == UINode.fileListFlavor)
&& (getType() == ICoreConstants.REFERENCE))
return true;
// for Linux uriListFlavor is supported for drag and drop for reference nodes
if ((flavor == uriListFlavor)
&& (getType() == ICoreConstants.REFERENCE))
return true;
if (flavor.getHumanPresentableName().equals("UINode") || //$NON-NLS-1$
flavor == UINode.plainTextFlavor ||
flavor == UINode.localStringFlavor) {
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
* @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 {
//log.info("in getTransferData flavour = "+flavor.getHumanPresentableName());
if (flavor.equals(UINode.plainTextFlavor)) {
String charset = flavor.getParameter("charset").trim(); //$NON-NLS-1$
if(charset.equalsIgnoreCase("unicode")) { //$NON-NLS-1$
return new ByteArrayInputStream(oNode.getId().getBytes("Unicode")); //$NON-NLS-1$
}
else {
return new ByteArrayInputStream(oNode.getId().getBytes("iso8859-1")); //$NON-NLS-1$
}
}
else if(uriListFlavor.equals(flavor))
{
// Linux dnd uses URI as file://, http://, ...
try {
URI nodeSource = new URI(getNode().getSource());
if(LinkedFileDatabase.isDatabaseURI(nodeSource))
{
LinkedFile lf = new LinkedFileDatabase(nodeSource);
// create temporary file to dnd
File tempFile = lf.getFile(ProjectCompendium.temporaryDirectory);
// delete the temporary file when the jvm exits
// any Drag and Drop operations should be completed by then
tempFile.deleteOnExit();
return tempFile.toURI().toString();
}
else
{
// if it is a file:// URI return a string representation of it
return nodeSource.toString();
}
}
catch (Exception e) {
log.error("Error...", e);
throw new UnsupportedFlavorException(flavor);
}
}
else if (UINode.localStringFlavor.equals(flavor)) {
return oNode.getId();
}
else if (DataFlavor.javaFileListFlavor.equals(flavor)) {
try {
URI nodeSource = new URI(getNode().getSource());
if(LinkedFileDatabase.isDatabaseURI(nodeSource))
{
LinkedFile lf = new LinkedFileDatabase(nodeSource);
// create temporary file to dnd
File tempFile = lf.getFile(ProjectCompendium.temporaryDirectory);
// delete the temporary file when the jvm exits
// any Drag and Drop operations should be completed by then
tempFile.deleteOnExit();
return Collections.singletonList(tempFile);
}
else
{
File f = new File(nodeSource);
return Collections.singletonList(f);
}
}
catch (Exception e) {
log.error("Error...", e);
throw new UnsupportedFlavorException(flavor);
}
}
else if (flavor.getHumanPresentableName().equals("UINode")) { //$NON-NLS-1$
return (Object)new String(oPos.getView().getId()+"/"+oNode.getId()); //$NON-NLS-1$
}
else
throw new UnsupportedFlavorException(flavor);
}
//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())
)) {
try {
DragSource source = (DragSource)e.getDragSource();
source.startDrag(e, DragSource.DefaultCopyDrop, getViewPane(), getViewPane());
}
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");
}
// TARGET
/**
* Called if the user has modified
* the current drop gesture.
* <P>HERE DOES NOTHING</P>
* @param e the <code>DropTargetDragEvent</code>
*/
public void dropActionChanged(DropTargetDragEvent e) {
//log.info("IN dropActionChanged of Target");
}
/**
* 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 DOES NOTHING</P>
* @param e the <code>DropTargetDragEvent</code>
*/
public void dragOver(DropTargetDragEvent e) {
//log.info("dragtargetdrag event at "+e.getLocation());
}
/**
* 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 DOES NOTHING</P>
* @param e the <code>DropTargetEvent</code>
*/
public void dragExit(DropTargetEvent e) {
log.debug("In drag exit of Target");
}
/**
* 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 DOES NOTHING</P>
* @param e the <code>DropTargetDragEvent</code>
*/
public void dragEnter(DropTargetDragEvent e) {
log.debug("dragEnter - about to accept DnDConstants.ACTION_LINK");
//e.acceptDrag(DnDConstants.ACTION_LINK);
//e.acceptDrag(DnDConstants.ACTION_MOVE);
}
/**
* 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>
* Process a drop for createing links - CURRENTLY ONLY ON THE MAC (WINDOW/LINUX use mouse events).
* <P>
* @param e the <code>DropTargetDropEvent</code>
*/
public void drop(DropTargetDropEvent e) {
}
/**
* Set the help context for this node depending on node type.
* @param type, the node type to set the help string for.
*/
private void setHelp(int type) {
UINodeTypeManager.setHelp(this, type);
}
/**
* Return the standard size icon for the given node type.
* @param type, the node type to return the icon for.
* @return ImageIcon, the icon for the given node type.
*/
public static ImageIcon getNodeImage(int type, boolean isSmall) {
return UINodeTypeManager.getNodeImage(type, isSmall);
}
/**
* Return the small size icon for the given node type.
* @param type, the node type to return the icon for.
* @return ImageIcon, the icon for the given node type.
*/
public static ImageIcon getNodeImageSmall(int type) {
return UINodeTypeManager.getNodeImageSmall(type);
}
/**
* Return the small size icon for the given reference string for file types (not images).
* @param sRefString the reference string to get an icon for.
* @return ImageIcon the icon for the given node type.
*/
public static ImageIcon getReferenceImageSmall(String sRefString) {
return UIReferenceNodeManager.getSmallReferenceIcon(sRefString);
}
/**
* Return the small size icon for the given reference string for file types (not images).
* @param sRefString the reference string to get an icon for.
* @return ImageIcon the icon for the given node type.
*/
public static ImageIcon getReferenceImage(String sRefString) {
return UIReferenceNodeManager.getReferenceIcon(sRefString);
}
/**
* Returns the L&F object that renders this component.
*
* @return NodeUI object.
*/
public NodeUI getUI() {
return (NodeUI)ui;
}
/**
* Sets the L&F object that renders this component.
*
* @param ui the NodeUI L&F object
* @see UIDefaults#getUI
*/
public void setUI(NodeUI ui) {
super.setUI(ui);
}
/**
* Notification from the UIFactory that the L&F has changed.
*
* @see JComponent#updateUI
*/
public void updateUI() {
NodeUI newNodeUI = (NodeUI)NodeUI.createUI(this);
setUI(newNodeUI);
invalidate();
}
/**
* Returns a string that specifies the name of the l&f class
* that renders this component.
*
* @return String "NodeUI"
*
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return "NodeUI"; //$NON-NLS-1$
}
/**
* Returns the type of this node.
*
* @return int, the type of this node.
* @see #setType
*/
public int getType() {
return oNode.getType();
}
/**
* Change the type of this node to the given type.
* Return if type changed.
*
* @param nNewType, the new type for this node.
* @return boolean, true of the type was changed, else false.
* @see #getType
*/
public boolean setType( int nNewType ) {
return setType(nNewType, false, -1);
}
/**
* Change the type of this node to the given type.
* Return if type changed.
*
* @param newtype, the new type for this node.
* @param focus, indicates whether to focus the node after type change.
* @param position, indicaes to focus node label for editing after type change at the given point. -1 indicates not to focus label.
* @return boolean, true of the type was changed, else false.
* @see #getType
*/
public boolean setType( int nNewType, boolean focus, int position ) {
int nOldType = oNode.getType();
if (nOldType == nNewType)
return false;
boolean changeType = true;
// IF NODE WAS A VIEW AND IS CHANGING TO NOT BE A VIEW
// WARN USER CONTENTS WILL BE LOST
if ( View.isViewType(nOldType) && !View.isViewType(nNewType) ) {
int response = JOptionPane.showConfirmDialog(ProjectCompendium.APP,
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage1a")+"\n"+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage1b")+"\n\n"+//$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage1c")+"\n", //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.changeType")+oNode.getLabel(), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$
if (response == JOptionPane.NO_OPTION || response == JOptionPane.CLOSED_OPTION) {
return false;
}
else {
try {
View view = (View)oNode;
view.clearViewForTypeChange();
ProjectCompendium.APP.setTrashBinIcon();
ProjectCompendium.APP.removeView((View)view);
oNode.setType(nNewType, sAuthor);
}
catch(Exception io) {
io.printStackTrace();
return false;
}
}
}
// IF NODE IS CHANING FROM A VIEW TO ANOTHER VIEW, CHECK TYPES AND WARN AS APPROPRIATE
else if ( View.isViewType(nNewType) ) {
if (View.isViewType(nOldType)) {
try {
boolean proceed = false;
boolean purgeLinks = false;
if (nOldType == ICoreConstants.MOVIEMAPVIEW && View.isListType(nNewType)) {
int response = JOptionPane.showConfirmDialog(ProjectCompendium.APP,
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage4a") +"\n\n"+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage1c") +"\n", //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.changeType")+oNode.getLabel(), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$
if (response == JOptionPane.NO_OPTION || response == JOptionPane.CLOSED_OPTION) {
return false;
}
else {
proceed = true;
purgeLinks = true;
}
} else if (nOldType == ICoreConstants.MOVIEMAPVIEW && View.isMapType(nNewType)) {
int response = JOptionPane.showConfirmDialog(ProjectCompendium.APP,
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage5a") +"\n\n"+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage1c") +"\n", //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.changeType")+oNode.getLabel(), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$
if (response == JOptionPane.NO_OPTION || response == JOptionPane.CLOSED_OPTION) {
return false;
}
else {
proceed = true;
purgeLinks = false;
}
} else if (View.isMapType(nOldType) && View.isListType(nNewType)) {
int response = JOptionPane.showConfirmDialog(ProjectCompendium.APP,
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage2a") +"\n\n"+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage1c") +"\n", //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.changeType")+oNode.getLabel(), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$
if (response == JOptionPane.NO_OPTION || response == JOptionPane.CLOSED_OPTION) {
return false;
}
else {
proceed = true;
purgeLinks = true;
}
} else {
proceed = true;
purgeLinks = false;
}
if (proceed) {
if (purgeLinks) {
View view = (View)oNode;
view.purgeAllLinks();
}
if (oNode instanceof TimeMapView) {
TimeMapView timeview = (TimeMapView)oNode;
timeview.clearTimes();
}
if (oNode instanceof MovieMapView) {
MovieMapView movieview = (MovieMapView)oNode;
movieview.clearMovies();
}
ProjectCompendium.APP.removeView((View)oNode);
oNode.setType(nNewType, sAuthor);
}
}
catch(Exception io){
io.printStackTrace();
return false;
}
}
else {
try {
oNode.setType(nNewType, sAuthor);
}
catch(Exception io) {
return false;
}
}
}
// IF NODE IS CHANING FROM A REFERENCE NODE TO ANOTHER TYPE
// WARN USER REFERENCE WILL BE LOST.
else if (nOldType == ICoreConstants.REFERENCE && nNewType != ICoreConstants.REFERENCE) {
String source = oNode.getSource();
String image = oNode.getImage();
if (!image.equals("") || !source.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
int response = JOptionPane.showConfirmDialog(ProjectCompendium.APP,
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage3b")+"\n"+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage3b")+"\n\n"+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.warningMessage1c")+"\n", //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.changeType")+" - "+oNode.getLabel(), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$ //$NON-NLS-2$
if (response == JOptionPane.NO_OPTION || response == JOptionPane.CLOSED_OPTION)
changeType = false;
else
changeType = true;
}
if (changeType) {
try {
// ONLY CLEAR THE REFERENCE AND IMAGE IF NOT CHANING TO A VIEW AS VIEW'S CAN HAVE IMAGES.
if (!View.isViewType(nNewType))
oNode.setSource("", "", sAuthor); //$NON-NLS-1$ //$NON-NLS-2$
else {
// if there is a reference to an image and no existing image,
// move to image field so node image draws when a view.
if (UIImages.isImage(source) && image.equals("")) {
image = source;
}
oNode.setSource("", image, sAuthor);
}
oNode.setType(nNewType, sAuthor);
}
catch(Exception io) {
return false;
}
}
}
else {
try {
oNode.setType(nNewType, sAuthor);
}
catch(Exception ex) {
return false;
}
}
return changeType;
}
/**
* Update the link colours as appropriate after a node type change.
* @param type, the type of the node to update the link color for.
* @param oldType, the previous node type of this node.
*/
private void changeLinkColour(int type, int oldType) {
UILinkGroup group = ProjectCompendium.APP.oLinkGroupManager.getLinkGroup(ProjectCompendium.APP.getActiveLinkGroup());
if (group == null || (group.getID()).equals("1") ) { //$NON-NLS-1$
if ( type == ICoreConstants.PRO ) {
for(Enumeration e = htLinks.elements();e.hasMoreElements();) {
UILink link = (UILink)e.nextElement();
if ( (link.getFromNode().getNode().getId()).equals(getNode().getId()) )
link.setLinkType(new Integer(ICoreConstants.SUPPORTS_LINK).toString());
}
}
else if ( type == ICoreConstants.CON ) {
for(Enumeration e = htLinks.elements();e.hasMoreElements();) {
UILink link = (UILink)e.nextElement();
if ( (link.getFromNode().getNode().getId()).equals(getNode().getId()) )
link.setLinkType(new Integer(ICoreConstants.OBJECTS_TO_LINK).toString());
}
}
else if (oldType == ICoreConstants.PRO || oldType == ICoreConstants.CON) {
for(Enumeration e = htLinks.elements();e.hasMoreElements();) {
UILink link = (UILink)e.nextElement();
if ( (link.getFromNode().getNode().getId()).equals(getNode().getId()) ) {
link.setLinkType(new Integer(ICoreConstants.DEFAULT_LINK).toString());
}
}
}
}
}
/**
* Move first page of detail text into label.
*/
public void onMoveDetails() {
String details = oNode.getDetail();
if (details.equals(ICoreConstants.NODETAIL_STRING))
details = ""; //$NON-NLS-1$
String label = getText();
if (label.equals(ICoreConstants.NOLABEL_STRING))
label = ""; //$NON-NLS-1$
if (!details.equals("") && !label.equals("")) //$NON-NLS-1$ //$NON-NLS-2$
label = label+" "+details; //$NON-NLS-1$
else if (label.equals("") && !details.equals("")) //$NON-NLS-1$ //$NON-NLS-2$
label = details;
label = label.replace('\n',' ');
label = label.replace('\r',' ');
label = label.replace('\t',' ');
setText(label);
try {
// shuffle detail pages.
Vector pages = oNode.getDetailPages(sAuthor);
if (pages.size() > 1) {
pages.removeElementAt(0);
NodeDetailPage page = null;
int count = pages.size();
for (int i=0; i<count; i++) {
page = (NodeDetailPage)pages.elementAt(i);
page.setPageNo(i+1);
}
}
else {
NodeDetailPage page = (NodeDetailPage)pages.elementAt(0);
page.setText(""); //$NON-NLS-1$
pages.setElementAt(page, 0);
}
oNode.setDetailPages(pages, sAuthor, sAuthor);
}
catch(Exception ex) {
log.info("Error: (UINode.onMoveDetails) \n\n"+ex.getMessage()); //$NON-NLS-1$
}
ProjectCompendium.APP.refreshNodeIconIndicators(oNode.getId());
}
/**
* Move label text into the first page of detail.
*/
public void onMoveLabel() {
String label = getText();
if (label.equals(ICoreConstants.NOLABEL_STRING))
label = ""; //$NON-NLS-1$
String details = oNode.getDetail();
if (details.equals(ICoreConstants.NODETAIL_STRING))
details = ""; //$NON-NLS-1$
if (!label.equals("") && !details.equals("")) //$NON-NLS-1$ //$NON-NLS-2$
details = label+" "+details; //$NON-NLS-1$
else if (details.equals("") && !label.equals("")) //$NON-NLS-1$ //$NON-NLS-2$
details = label;
try {
oNode.setDetail(details, sAuthor, sAuthor);
setText(""); //$NON-NLS-1$
}
catch(Exception ex) {
log.error("Error...", ex);
log.info("Error: (UINode.onMoveLabel) \n\n"+ex.getMessage()); //$NON-NLS-1$
}
ProjectCompendium.APP.refreshNodeIconIndicators(oNode.getId());
}
/**
* Increase the font size displayed by one point.
* This does not change the setting in the database.
* @return the new size.
*/
public int increaseFontSize() {
Font font = getFont();
int newSize = font.getSize()+1;
Font newFont = new Font(font.getName(), font.getStyle(), font.getSize()+1);
super.setFont(newFont);
getUI().refreshBounds();
return newSize;
}
/**
* Decrease the font size displayed by one point.
* This does not change the setting in the database.
* @return the new size.
*/
public int decreaseFontSize() {
Font font = getFont();
int newSize = font.getSize()-1;
Font newFont = new Font(font.getName(), font.getStyle(), font.getSize()-1);
super.setFont(newFont);
getUI().refreshBounds();
return newSize;
}
/**
* Sets the font used to display the node's text to the given font without scaling
*
* @param size The size to set the font.
*/
public void setFontSize(int size) {
Font font = getFont();
Font newFont = new Font(font.getName(), font.getStyle(), size);
super.setFont(newFont);
getUI().refreshBounds();
}
/**
* Restore the font to the default settings.
*
*/
public void setDefaultFont() {
Font labelFont = new Font(oPos.getFontFace(), oPos.getFontStyle(), oPos.getFontSize());
setFont(labelFont);
if (getUI() != null) {
getUI().refreshBounds();
}
}
/**
* Sets the font used to display the node's text.
* Scales if required.
*
* @param font The font to use.
*/
public void setFont(Font font) {
if (scale != 0.0 && scale != 1.0) {
if (oPos != null) {
String sFontFace = oPos.getFontFace();
int nFontSize = oPos.getFontSize();
int nFontStyle = oPos.getFontStyle();
Font font2 = new Font(sFontFace, nFontStyle, nFontSize);
Point p1 = UIUtilities.transformPoint(font2.getSize(), font2.getSize(), scale);
font = new Font(font2.getName() , font2.getStyle(), p1.x);
}
}
super.setFont(font);
repaint(10);
}
/**
* Returns the text string that the node displays.
*
* @return String, the text string that the node displays.
* @see #setText
*/
public String getText() {
return sText;
}
/**
* Defines the single line of text this component will display.
* <p>
* @param text, the new text to diaply as the node label.
* @see #setIcon
*/
public void setText(String text) {
String oldValue = sText;
//set thte label of the model nodesummary object
try {
if (oNode != null) {
oNode.setLabel(text, sAuthor);
sText = text;
firePropertyChange(TEXT_PROPERTY, oldValue, sText);
repaint();
}
}
catch(Exception io) {
io.printStackTrace();
ProjectCompendium.APP.displayError("Error: (UINode.setText) "+LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.errorUpdateLabel")+"\n\n"+io.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
/**
* Defines the single line of text this component will display. This method (with the bDefer param)
* is used only by NodeUI.addChartoLabel() - this is a performance mod to speed up typing when
* entering node labels (otherwise, each character typed generated 6 DB interactions). Going this
* route, the DB update for the label is deferred until the node loses focus.
*
* @param text, the new text to display as the node label.
* @param bDefer,
*/
public void setText(String text, Boolean bDefer) {
String oldValue = sText;
try {
if (oNode != null) {
oNode.setLabelLocal(text);
sText = text;
firePropertyChange(TEXT_PROPERTY, oldValue, sText);
repaint();
}
}
catch(Exception io) {
io.printStackTrace();
ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UINode.errorUpdateLabel")+io.getMessage()); //$NON-NLS-1$
}
}
/**
* Sets the current scaling value for this node.
* @param scale, the scaling value to apply to this node.
*/
public void setScale(double scale) {
this.scale = scale;
}
/**
* Gets the current scaling value for this node.
* @return double, the current scaling value for this node.
*/
public double getScale() {
return scale;
}
/**
* Returns the graphic image (glyph, icon) that the node displays.
*
* @return ImageIocn, the icon displayed by this node.
* @see #setIcon
*/
public ImageIcon getIcon() {
if (oDefaultIcon == null || oDefaultIcon.getImageLoadStatus() == MediaTracker.ERRORED) {
return null;
}
return oDefaultIcon;
}
/**
* Defines the icon this component will display. Fires a PropertyChangeEvent.
* <p>
* @param icon, the icon for this node to display.
* @see #getIcon
*/
public void setIcon(ImageIcon icon) {
if (scale != 1.0) {
icon = scaleIcon(icon);
}
ImageIcon oldValue = oDefaultIcon;
oDefaultIcon = icon;
firePropertyChange(ICON_PROPERTY, oldValue, oDefaultIcon);
repaint();
}
/**
* Refreshes the icon this component will display. Forces the firing of a PropertyChangeEvent.
* <p>
* @param icon, the icon for this node to display.
* @see #getIcon
*/
public void refreshIcon(ImageIcon icon) {
if (scale != 1.0)
icon = scaleIcon(icon);
ImageIcon oldValue = oDefaultIcon;
oDefaultIcon = icon;
// FORCE A PROPERTY CHANGE
oldValue = null;
firePropertyChange(ICON_PROPERTY, oldValue, oDefaultIcon);
repaint();
}
/**
* Scale the given icon to the current scaling factor and return.
* @param icon, the icon to scale.
* @return ImageIcon, the scaled version of the icon, or the original if something went wrong.
*/
public ImageIcon scaleIcon(ImageIcon icon) {
if (icon == null)
return icon;
int imgWidth = icon.getIconWidth();
int imgHeight = icon.getIconHeight();
if (imgWidth == 0 || imgHeight == 0)
return icon;
int scaledW = (int)(scale*imgWidth);
int scaledH = (int)(scale*imgHeight);
if (scaledW == 0 || scaledH == 0)
return null;
ImageFilter filter = new AreaAveragingScaleFilter(scaledW, scaledH);
FilteredImageSource filteredSource = new FilteredImageSource((ImageProducer)icon.getImage().getSource(), filter);
JLabel comp = new JLabel();
Image img = comp.createImage(filteredSource);
icon = new ImageIcon(img);
return icon;
}
/**
* Restore the icon on this node to its original type specific icon.
*/
public ImageIcon restoreIcon() {
int type = oNode.getType();
if (type == ICoreConstants.TRASHBIN) {
ImageIcon icon = ProjectCompendium.APP.setTrashBinIcon();
if (icon != null) {
setIcon(icon);
}
}
else if (type == ICoreConstants.REFERENCE || type == ICoreConstants.REFERENCE_SHORTCUT) {
String refString = oNode.getImage();
if (refString == null || refString.equals("")) //$NON-NLS-1$
refString = oNode.getSource();
setReferenceIcon(refString);
}
else if(View.isViewType(type) || View.isShortcutViewType(type)) {
String refString = oNode.getImage();
if (refString != null && !refString.equals("")) //$NON-NLS-1$
setReferenceIcon(refString);
else
setIcon(getNodeImage(type, oPos.getShowSmallIcon()));
}
else {
setIcon(getNodeImage(type, oPos.getShowSmallIcon()));
}
return oDefaultIcon;
}
/**
* return if the image on this node has been scaled,
* and therefore can be enlarge on rollover.
*/
public boolean hasImageBeenScaled() {
return bIsImageScaled;
}
/**
* Set the correct reference icon for the given file path or url.
*
* @param refString, the string for the file path or url for this reference node.
*/
public void setReferenceIcon(String refString) {
final String imageRef = refString;
//Thread thread = new Thread("UINode.setReferenceIcon") {
// public void run() {
ImageIcon icon = null;
if (imageRef != null) {
if ( UIImages.isImage(imageRef) ) {
ImageIcon originalSizeImage = UIImages.createImageIcon(imageRef);
if (originalSizeImage == null) {
setIcon(UIImages.get(IUIConstants.BROKEN_IMAGE_ICON));
return;
}
Image originalIcon = originalSizeImage.getImage();
int originalWidth = originalIcon.getWidth(null);
int originalHeight = originalIcon.getHeight(null);
Dimension specifiedSize = getNode().getImageSize();
if (specifiedSize.width == 0 && specifiedSize.height == 0) {
icon = UIImages.thumbnailIcon(originalSizeImage);
Image newIcon = icon.getImage();
int newWidth = newIcon.getWidth(null);
int newHeight = newIcon.getHeight(null);
if (newWidth < originalWidth || newHeight < originalHeight) {
bIsImageScaled = true;
}
} else if (specifiedSize.width == originalWidth && specifiedSize.height == originalHeight) {
icon = originalSizeImage;
bIsImageScaled = false;
} else {
icon = UIImages.scaleIcon(originalSizeImage, specifiedSize);
Image newIcon = icon.getImage();
int newWidth = newIcon.getWidth(null);
int newHeight = newIcon.getHeight(null);
if (newWidth < originalWidth || newHeight < originalHeight) {
bIsImageScaled = true;
}
}
}
else {
// IF USING SMALL ICON MODE, LOAD SMALL VERSION
if (oPos.getShowSmallIcon()) {
icon = getReferenceImageSmall(imageRef);
}
else {
icon = getReferenceImage(imageRef);
}
}
}
setIcon(icon);
}
/**
* Check if the file path or url given is a recognised type for reference nodes.
* @param sRefString the string to check.
* @return boolean true if the file path or url given is a recognised type, else false.
*/
public static boolean isReferenceNode(String sRefString) {
return UIReferenceNodeManager.isReferenceNode(sRefString);
}
/**
* Returns the nodedata object that this UINode represents.
*
* @return com.compendium.core.datamodel.NodeSummary, the associated node.
* @see #setNode
*/
public NodeSummary getNode() {
return oNode;
}
/**
* Returns the node pos that the node represents.
*
* @return com.compendium.core.datamodel.NodePosition, the associated node position object.
*/
public NodePosition getNodePosition() {
return oPos;
}
/**
* Set the NodePosition of this node
* @param x, the x position of this node in the map.
* @param y, the y position of this node in the map.
*/
public void setNodePosition(int x, int y) {
oPos.setPos(x, y);
}
/**
* Set the NodeSummary data object for this node.
* <p>
* @param node com.compendium.core.datamodel.NodeSummary, the node data object for this UINode.
*/
public void setNode(NodeSummary node) {
oNode = node;
oNodeType = node.getType();
oNode.addPropertyChangeListener(this);
oPos.addPropertyChangeListener(this);
setHelp(oNode.getType());
//remove all returns and tabs which show up in the GUI as evil black char
String label = ""; //$NON-NLS-1$
label = oNode.getLabel();
if (label.equals(ICoreConstants.NOLABEL_STRING))
label = ""; //$NON-NLS-1$
label = label.replace('\n',' ');
label = label.replace('\r',' ');
label = label.replace('\t',' ');
setText(label);
int type = oNode.getType();
//if the default icon has not already been set, then set it here.
//otherwise leave the icon image alone since it may have been changed.
ImageIcon icon = null;
if (oDefaultIcon == null) {
if (type == ICoreConstants.REFERENCE || type == ICoreConstants.REFERENCE_SHORTCUT) {
String refString = oNode.getImage();
if (refString == null || refString.equals("")) //$NON-NLS-1$
refString = oNode.getSource();
if (refString == null || refString.equals("")) { //$NON-NLS-1$
setIcon(getNodeImage(type, oPos.getShowSmallIcon()));
} else {
setReferenceIcon(refString);
}
}
else if(View.isViewType(type) || View.isShortcutViewType(type)) {
String refString = oNode.getImage();
if (refString == null || refString.equals("") || refString.endsWith("meeting_big.gif")) //$NON-NLS-1$ //$NON-NLS-2$
setIcon(getNodeImage(type, oPos.getShowSmallIcon()));
else
setReferenceIcon(refString);
}
else {
setIcon(getNodeImage(type, oPos.getShowSmallIcon()));
}
}
oNode.updateMultipleViews();
}
/**
* Returns the selected state of the node.
*
* @return boolean, the selected state of the node
*/
public boolean isSelected() {
return bSelected;
}
/**
* Sets the selected state of the node.
* <p>
* @param selected, the selected state
*/
public void setSelected(boolean selected) {
boolean oldValue = bSelected;
bSelected = selected;
firePropertyChange(SELECTED_PROPERTY, oldValue, bSelected);
repaint();
}
/**
* Returns the state of the cut node.
*
* @return boolean, true if the node has been cut, else false.
*/
public boolean isCut() {
return bCut;
}
/**
* Sets the state of the node to cut.
*
* @param cut, has this node been cut.
*/
public void setCut(boolean cut) {
boolean oldValue = bCut;
bCut = cut;
firePropertyChange("selected", oldValue, bSelected); //$NON-NLS-1$
repaint();
}
/**
* Returns the roll-over state of the node.
*
* @return boolean, true if the node is currently rolled over, else false.
*/
public boolean isRollover() {
return bRollover;
}
/**
* Sets the roll over state of the node.
* <p>
* @param rollover, the roll over state of the node.
*/
public void setRollover(boolean rollover) {
boolean oldValue = bRollover;
bRollover = rollover;
firePropertyChange(ROLLOVER_PROPERTY, new Boolean(oldValue), new Boolean(bRollover));
repaint();
}
/**
* Adds a reference to a link this node is linked to.
*
* @param link com.compendium.ui.UILink, the link this node is linked to.
*/
public void addLink(UILink link) {
if(!htLinks.containsKey((link.getLink()).getId()))
htLinks.put((link.getLink()).getId(),link);
}
/**
* Removes a reference to a link this node is linked to.
*
* @param link com.compenduim.ui.UILink, the link to be removed.
*/
public void removeLink(UILink link) {
if(htLinks.containsKey((link.getLink()).getId()))
htLinks.remove((link.getLink()).getId());
}
/**
* Removes references to all links this node is linked to.
*/
public void removeAllLinks() {
for(Enumeration keys = htLinks.keys();keys.hasMoreElements();) {
String key = (String)keys.nextElement();
htLinks.remove(key);;
}
}
/**
* Updates the connection points of the links.
*/
public void updateLinks() {
if (htLinks != null && htLinks.size() > 0) {
for(Enumeration e = htLinks.elements();e.hasMoreElements();) {
UILink link = (UILink)e.nextElement();
if (link != null)
link.updateConnectionPoints();
}
}
}
/**
* Scale links and update the connection points of the links.
*/
public void scaleLinks(AffineTransform trans) {
for(Enumeration e = htLinks.elements();e.hasMoreElements();) {
UILink link = (UILink)e.nextElement();
link.scaleLink(trans);
link.updateConnectionPoints();
}
}
/**
* Returns the enumeration of UILinks to this node.
* @return Enumeration, the enumeration of UILinks to this node.
*/
public Enumeration getLinks() {
return htLinks.elements();
}
/**
* Checks whether this node is linked to the given node.
*
* @param to com.compendium.ui.UINode, the node to test for.
* @return boolean, true if this node is linked to the given node, false otherwise.
*/
public boolean containsLink(UINode to) {
for(Enumeration e = htLinks.elements();e.hasMoreElements();) {
UILink link = (UILink)e.nextElement();
if (link.getFromNode() == to || link.getToNode() == to)
return true;
}
return false;
}
/**
* Return the link associated with the given node or null.
*
* @param to com.compendium.ui.UINode, the node to return the link for.
* @return com.compendium.ui.UILink, the link of found else null.
*/
public UILink getLink(UINode to) {
for(Enumeration e = htLinks.elements();e.hasMoreElements();) {
UILink link = (UILink)e.nextElement();
if (link.getFromNode() == to || link.getToNode() == to)
return link;
}
return null;
}
/**
* Convenience method that moves this component to position 0 if it's
* parent is a JLayeredPane.
*/
public void moveToFront() {
if (getParent() != null && getParent() instanceof JLayeredPane) {
JLayeredPane l = (JLayeredPane)getParent();
l.moveToFront(this);
}
}
/**
* Convenience method that moves this component to position -1 if it's
* parent is a JLayeredPane.
*/
public void moveToBack() {
if (getParent() != null && getParent() instanceof JLayeredPane) {
JLayeredPane l = (JLayeredPane)getParent();
l.moveToBack(this);
}
}
/**
* Returns the amount of space between the text and the icon
* displayed in this node.
*
* @return int, an int equal to the number of pixels between the text and the icon.
* @see #setIconTextGap
*/
public int getIconTextGap() {
return nIconTextGap;
}
/**
* If both the icon and text properties are set, this property
* defines the space between them.
* <p>
* The default value of this property is 4 pixels.
* <p>
*
* @see #getIconTextGap
*/
public void setIconTextGap(int iconTextGap) {
int oldValue = nIconTextGap;
nIconTextGap = iconTextGap;
firePropertyChange("iconTextGap", oldValue, nIconTextGap); //$NON-NLS-1$
invalidate();
repaint(10);
}
/**
* Set the location of this node, scaling if required.
* Location must be passed in at the original 100% scale value.
*/
public void setLocation(Point loc) {
if (scale != 0.0 && scale != 1.0) {
loc = UIUtilities.transformPoint(loc.x, loc.y, scale);
}
super.setLocation(loc);
}
/**
* Sets the font used to display the node's text. Fires a PropertyChangeEvent.
*
* @param font, The font to use.
*/
public void setLabelFont(Font font) {
super.setFont(font);
firePropertyChange(TEXT_PROPERTY, "", sText); //$NON-NLS-1$
repaint();
}
/**
* Return the current reference to the content dialog for this node or null.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
public UINodeContentDialog getCurrentContentDialog() {
return contentDialog;
}
/**
* Return the current reference to the content dialog for this node.
* If the content dialog is null, create a new one, but don't show it.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
public UINodeContentDialog getContentDialog() {
if(getNode().getType() == ICoreConstants.TRASHBIN ||
getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) {
return null;
}
if (contentDialog == null)
contentDialog = new UINodeContentDialog(ProjectCompendium.APP, oPos.getView(), this, UINodeContentDialog.CONTENTS_TAB);
return contentDialog;
}
/**
* Open and return the content dialog and select the Edit/Contents tab.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
public UINodeContentDialog showEditDialog() {
return showContentDialog(UINodeContentDialog.CONTENTS_TAB);
}
/**
* Open and return the content dialog and select the Properties tab.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
public UINodeContentDialog showPropertiesDialog() {
return showContentDialog(UINodeContentDialog.PROPERTIES_TAB);
}
/**
* Open and return the content dialog and select the View tab.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
public UINodeContentDialog showViewsDialog() {
return showContentDialog(UINodeContentDialog.VIEW_TAB);
}
/**
* Open and return the content dialog and select the Time tab.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
public UINodeContentDialog showTimeDialog() {
return showContentDialog(UINodeContentDialog.TIME_TAB);
}
/**
* If the dialog is open, refresh the time tab.
*/
public void refreshTimeDialog() {
if (contentDialog != null) {
contentDialog.refreshTimes();
}
}
/**
* Open and return the content dialog and select the Time tab.
* @param span the timespan the user was on when calling this dialog.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
public UINodeContentDialog showTimeDialog(NodePositionTime span) {
if(getNode().getType() == ICoreConstants.TRASHBIN ||
getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) {
return null;
}
if (contentDialog != null && contentDialog.isVisible())
return contentDialog;
contentDialog = new UINodeContentDialog(ProjectCompendium.APP, oPos.getView(), this, UINodeContentDialog.TIME_TAB, span);
contentDialog.setVisible(true);
int state = this.getNode().getState();
if(state != ICoreConstants.READSTATE){
try {
this.getNode().setState(ICoreConstants.READSTATE);
} catch (SQLException e) {
log.error("Error...", e);
log.info("Error: (UINode.showContentDialog) \n\n"+e.getMessage());//$NON-NLS-1$
} catch (ModelSessionException e) {
log.error("Error...", e);
log.info("Error: (UINode.showContentDialog) \n\n"+e.getMessage());//$NON-NLS-1$
}
}
return contentDialog;
}
/**
* Open and return the content dialog and select the given tab.
*
* @param int tab, the tab on the dialog to select.
* @return com.compendium.ui.dialogs.UINodeContentDialog, the content dialog for this node.
*/
private UINodeContentDialog showContentDialog(int tab) {
if(getNode().getType() == ICoreConstants.TRASHBIN ||
getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) {
return null;
}
if (contentDialog != null && contentDialog.isVisible())
return contentDialog;
contentDialog = new UINodeContentDialog(ProjectCompendium.APP, oPos.getView(), this, tab);
contentDialog.setVisible(true);
//Lakshmi (4/19/06) - if the contents dialog is opened set state as read in NodeUserState DB
int state = this.getNode().getState();
if(state != ICoreConstants.READSTATE){
try {
this.getNode().setState(ICoreConstants.READSTATE);
} catch (SQLException e) {
log.error("Error...", e);
log.info("Error: (UINode.showContentDialog) \n\n"+e.getMessage()); //$NON-NLS-1$
} catch (ModelSessionException e) {
log.error("Error...", e);
log.info("Error: (UINode.showContentDialog) \n\n"+e.getMessage()); //$NON-NLS-1$
}
}
return contentDialog;
}
/**
* Return the right-click node menu for this node.
* @return com.compendium.ui.popups.UINodePopupMenu, the right-click node menu for this node.
*/
public UINodePopupMenu getPopupMenu() {
if(getNode().getType() == ICoreConstants.TRASHBIN ||
getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) {
return null;
}
if (nodePopup == null)
nodePopup = new UINodePopupMenu("Popup menu", getUI()); //$NON-NLS-1$
return nodePopup;
}
/**
* Create and hosw the right-click node popup menu for the given nodeui.
* @param nodeui com.compendium.ui.plad.NodeUI, the node to create the popup for.
* @param x, the x position of the mouse event that triggered this request.
* @param y, the y position of the mouse event that triggered this request.
*/
public UINodePopupMenu showPopupMenu(NodeUI nodeui, int x, int y) {
if(getNode().getType() == ICoreConstants.TRASHBIN ||
getNode().getId().equals(ProjectCompendium.APP.getInBoxID())) {
return null;
}
nodePopup = new UINodePopupMenu("Popup menu", nodeui); //$NON-NLS-1$
UIViewFrame viewFrame = getViewPane().getViewFrame();
Dimension dim = ProjectCompendium.APP.getScreenSize();
int screenWidth = dim.width - 50; //to accomodate for the scrollbar
int screenHeight = dim.height -200; //to accomodate for the menubar...
Point point = viewFrame.getViewPosition();
int realX = Math.abs(point.x - getX())+50;
int realY = Math.abs(point.y - getY())+50;
int endXCoordForPopUpMenu = realX + nodePopup.getWidth();
int endYCoordForPopUpMenu = realY + nodePopup.getHeight();
int offsetX = (screenWidth) - endXCoordForPopUpMenu;
int offsetY = (screenHeight) - endYCoordForPopUpMenu;
if(offsetX > 0)
offsetX = 0;
if(offsetY > 0)
offsetY = 0;
nodePopup.setCoordinates(realX+offsetX, realY+offsetY);
nodePopup.setViewPane(getViewPane());
nodePopup.show(viewFrame, realX+offsetX, realY+offsetY);
return nodePopup;
}
/**
* Convenience method that searchs the anscestor heirarchy for a UIViewPane instance.
* @return com.compendium.ui.UIViewPane, the parent pane for this node.
*/
public UIViewPane getViewPane() {
Container p;
// Search upward for viewpane
p = getParent();
while (p != null && !(p instanceof UIViewPane)) {
p = p.getParent();
}
return (UIViewPane)p;
}
/**
* Handle a PropertyChangeEvent.
* @param evt, the associated PropertyChangeEvent to handle.
*/
public void propertyChange(PropertyChangeEvent evt) {
String prop = evt.getPropertyName();
Object source = evt.getSource();
Object oldvalue = evt.getOldValue();
Object newvalue = evt.getNewValue();
if (source instanceof NodePosition) {
if (prop.equals(NodePosition.POSITION_PROPERTY)) {
firePropertyChange(NodePosition.POSITION_PROPERTY, oldvalue, newvalue);
repaint();
}
else if (prop.equals(NodePosition.FONTFACE_PROPERTY)) {
Font font = getFont();
Font newFont = new Font((String)newvalue, font.getStyle(), font.getSize());
setFont(newFont);
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.FONTSTYLE_PROPERTY)) {
Font font = getFont();
Font newFont = new Font(font.getName(), ((Integer)newvalue).intValue(), font.getSize());
setFont(newFont);
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.FONTSIZE_PROPERTY)) {
Font font = getFont();
int newsize = ((Integer)newvalue).intValue();
Font newFont = new Font(font.getName(), font.getStyle(), newsize);
setFont(newFont); //scales
int adjustment = ProjectCompendium.APP.getToolBarManager().getTextZoom();
font = getFont();
Font adjustedFont = new Font(font.getName(), font.getStyle(), font.getSize()+adjustment);
super.setFont(adjustedFont);
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.TEXT_FOREGROUND_PROPERTY)) {
//setForeground(new Color( ((Integer)newvalue).intValue() ));
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.TEXT_BACKGROUND_PROPERTY)) {
//setBackground(new Color( ((Integer)newvalue).intValue() ));
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.TAGS_INDICATOR_PROPERTY)) {
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.TEXT_INDICATOR_PROPERTY)) {
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.TRANS_INDICATOR_PROPERTY)) {
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.WEIGHT_INDICATOR_PROPERTY)) {
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.HIDE_ICON_PROPERTY)) {
getUI().refreshBounds();
repaint();
}
else if (prop.equals(NodePosition.SMALL_ICON_PROPERTY)) {
int nType = oNode.getType();
ImageIcon icon = null;
if (nType == ICoreConstants.REFERENCE || nType == ICoreConstants.REFERENCE_SHORTCUT) {
String image = oNode.getImage();
if ( image != null && !image.equals("")) //$NON-NLS-1$
setReferenceIcon( image );
else {
setReferenceIcon( oNode.getSource() );
}
}
else if(View.isViewType(nType) || View.isShortcutViewType(nType)) {
String image = oNode.getImage();
if ( image != null && !image.equals("")) //$NON-NLS-1$
setReferenceIcon( image );
else {
icon = getNodeImage(oNode.getType(), oPos.getShowSmallIcon());
refreshIcon( icon );
}
}
else {
icon = getNodeImage(oNode.getType(), oPos.getShowSmallIcon());
refreshIcon( icon );
}
updateLinks();
repaint();
}
else if (prop.equals(NodePosition.WRAP_WIDTH_PROPERTY)) {
getUI().refreshBounds();
repaint();
}
}
else if (source instanceof NodeSummary) {
if (prop.equals(NodeSummary.LABEL_PROPERTY)) {
//Update as could have come from another uinode instance,
//like transclusion in another open map or outline view or aerial view
setText((String)newvalue);
updateLinks();
repaint();
}
else if (prop.equals(NodeSummary.TAG_PROPERTY)) {
firePropertyChange(NodeSummary.TAG_PROPERTY, oldvalue, newvalue);
repaint();
}
else if (prop.equals(NodeSummary.DETAIL_PROPERTY)) {
firePropertyChange(NodeSummary.DETAIL_PROPERTY, oldvalue, newvalue);
repaint();
}
else if (prop.equals(NodeSummary.NODE_TYPE_PROPERTY)) {
NodeSummary oldnode = oNode;
NodeSummary newnode = NodeSummary.getNodeSummary(oldnode.getId());
int nNewType = ((Integer)newvalue).intValue();
int nOldType = ((Integer)oldvalue).intValue();
// IF THE NODE SHOULD CHANGE CLASS AND HAS NOT YET, CHANGE IT.
// ONLY WANT THE DATABASE READ TO HAPPEN ONCE.
// AFTER THAT, THE NEW OBJECT CAN BE RETRIEVED FROM CACHE
String oldClassName = oldnode.getClass().getName();
String newClassName = newnode.getClass().getName();
IModel model = oNode.getModel();
if ( (nOldType > ICoreConstants.PARENT_SHORTCUT_DISPLACEMENT && nNewType <=
ICoreConstants.PARENT_SHORTCUT_DISPLACEMENT)
|| ( View.isViewType(nOldType) && !View.isViewType(nNewType))
|| ( !View.isViewType(nOldType) && View.isViewType(nNewType)) ) {
// IF NOT BEEN RECREATED YET, DO IT.
if (oldClassName.equals(newClassName)) {
try {
newnode = model.getNodeService().getNodeSummary(model.getSession(), oNode.getId());
}
catch(Exception ex) {
log.error("Error...", ex);
log.info("Exception (UINode.propertyChange)\n\n"+ex.getMessage()); //$NON-NLS-1$
}
}
}
if (View.isViewType(nOldType)) {
if (oldnode instanceof View) {
ProjectCompendium.APP.removeViewFromHistory((View) oldnode);
}
}
// IF THE NODE OBJECT HAS BEEN CHANGED e.g to/from View, ShortcutNodeSummary, ReferenceNode
if (!oNode.equals(newnode)) {
newnode.addPropertyChangeListener(this);
}
newnode.initialize(model.getSession(), model);
oPos.setNode(newnode);
oNode = newnode;
oNodeType = newnode.getType();
setHelp(newnode.getType());
restoreIcon();
changeLinkColour(nNewType, nOldType);
UIViewPane pane = getViewPane();
if (pane != null) {
pane.validateComponents();
pane.repaint();
}
repaint();
}
else if (prop.equals(NodeSummary.VIEW_NUM_PROPERTY)) {
firePropertyChange(NodeSummary.VIEW_NUM_PROPERTY, oldvalue, newvalue);
repaint();
}
else if (prop.equals(NodeSummary.STATE_PROPERTY)) {
firePropertyChange(NodeSummary.STATE_PROPERTY, oldvalue, newvalue);
repaint();
}
else if (prop.equals(NodeSummary.IMAGE_PROPERTY)) {
}
else if (prop.equals(NodeSummary.SOURCE_PROPERTY)) {
}
else if (prop.equals(View.CHILDREN_PROPERTY)) {
firePropertyChange(CHILDREN_PROPERTY, oldvalue, newvalue);
//this.paintImmediately(this.getBounds());
}
}
}
/**
* Clean up class variables to help with garbage collection.
*/
public void cleanUp() {
NodeUI nodeui = getUI();
nodeui.uninstallUI(this);
sText = null;
oDefaultIcon = null;
oNode = null;
oPos = null;
dragSource = null;
dropTarget = null;
if (htLinks != null)
htLinks.clear();
htLinks = null;
}
}