/******************************************************************************** * * * (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.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Vector; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.swing.JFileChooser; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.MenuElement; import javax.swing.tree.DefaultMutableTreeNode; 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.LinkedFileCopy; import com.compendium.core.datamodel.LinkedFileDatabase; import com.compendium.core.datamodel.Model; import com.compendium.core.datamodel.NodePosition; import com.compendium.core.datamodel.NodeSummary; import com.compendium.core.datamodel.PCSession; import com.compendium.core.datamodel.UserProfile; import com.compendium.core.datamodel.View; import com.compendium.core.datamodel.services.ILinkedFileService; import com.compendium.core.db.DBNode; import com.compendium.ui.linkgroups.UILinkGroup; import com.compendium.ui.linkgroups.UILinkType; import com.compendium.ui.movie.UIMovieMapViewFrame; import com.compendium.ui.movie.UIMovieMapViewPane; import com.compendium.ui.plaf.ViewPaneUI; import com.compendium.ui.tags.CheckNode; //import com.compendium.core.datamodel.LinkedFile; //import com.compendium.core.datamodel.LinkedFileCopy; //import com.compendium.core.datamodel.LinkedFileDatabase; /** * UIUtilities contains methods to help ui classes * * @author Michelle Bachler */ public class UIUtilities { static final Logger log = LoggerFactory.getLogger(UIUtilities.class); /** Create a new node to the Right of the given one.*/ public static final int DIRECTION_RIGHT = 0; /** Create a new node to the Left of the given one.*/ public static final int DIRECTION_LEFT = 1; /** Create a new node to the Up from the given one.*/ public static final int DIRECTION_UP = 2; /** Create a new node to the Down from the given one.*/ public static final int DIRECTION_DOWN = 3; /** A FontRenderContext that can be used to measure Strings */ private static FontRenderContext frc=null; /** * Get the current GraphicsConfiguration for this machine. * @author DrLaszloJamf (Sun Developer Forum) * @return GraphicsConfiguration the current graphics configuration. */ public static GraphicsConfiguration getDefaultConfiguration() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = ge.getDefaultScreenDevice(); return gd.getDefaultConfiguration(); } /** * This method returns the FontRenderContext * for the default Screen-device. * @author FahleE (Sun Developer Forum) * @return FontRenderContext the FontRenderContext that is used for the screen-device */ private static void createFontRenderContext() { GraphicsConfiguration gc=getDefaultConfiguration(); BufferedImage bi=gc.createCompatibleImage(1,1); //we need at least one pixel Graphics2D g2=bi.createGraphics(); frc=g2.getFontRenderContext(); } /** * Gets the FontRenderContext for the default screen-device. * The FontRenderContext returned here, can be used to measure * for instance the visual size of Strings that are to be painted by a component * that is not realized yet. * The FontRenderContext is mapped to the defaultScreenDevice * of the JVM. The returned here FontRenderContext can only to be used for * components that are painted onto the screen if you need a FontRenderContex * for printing this will probably not work. * For performance reasons we return only a reference * to a static FontRenderContext-object that is created in this class. * You should take care NOT to set the object returned here to null. * If you do this method will have to create a new one next time it is called. * So just use the returned FontRenderContext for obtaining the * metrics of a font and than leave it alone. * @author FahleE (Sun Developer Forum) * @return FontRenderContext a FontRenderContext for the * default screen. */ public static synchronized FontRenderContext getDefaultFontRenderContext() { if(frc==null) createFontRenderContext(); return frc; } /** * Center the given child component on the given parent component. * @param child, the component to center. * @param parent, the component to center the child component on. */ public static void centerComponent(Component child, Component parent) { int nChildWidth = child.getSize().width; int nChildHeight = child.getSize().height; int nParentWidth = parent.getWidth(); int nParentHeight = parent.getHeight(); int nParentX = parent.getX(); int nParentY = parent.getY(); int x = (nParentWidth - nChildWidth) / 2 + nParentX; int y = (nParentHeight - nChildHeight) / 2 + nParentY; if (x < 0) x = 0; if (y < 0) y = 0; child.setLocation(x, y); } /** * Determine the file location of the current given path and relocate as appropriate. * If in the database move to linkedFiles. * If in LinkedFiles move to database. * @param path the path of the file to move * @return the new path of the file once moved. */ public static String processLocation(String path) { ProjectCompendium.APP.setWaitCursor(); String sNewPath = path; try { if (LinkedFileDatabase.isDatabaseURI(path)) { Model oModel = (Model)ProjectCompendium.APP.getModel(); PCSession oSession = oModel.getSession(); LinkedFile linked = new LinkedFileDatabase(new URI(path)); linked.initialize(oSession, oModel); File file = linked.getFile(ProjectCompendium.temporaryDirectory); LinkedFile lFile = UIUtilities.copyDnDFileToFolder(file); sNewPath = lFile.getSourcePath(); } else { if (CoreUtilities.isFile(path)) { LinkedFile lFile = UIUtilities.copyDnDFileToDB(new File(path)); sNewPath = lFile.getSourcePath(); } } } catch(Exception io) { log.info("Failed to extract file from database: "+io.getLocalizedMessage()); //$NON-NLS-1$ } ProjectCompendium.APP.setDefaultCursor(); return sNewPath; } /** * Unzip the passed zip file and extract the XML. * * @param sFilePath the path to the zip file to import. * @param bGiveUserXMLDialog true means give the user the XML Import dialog, else use defaults. * Defaults are: import with translcusion, preserve node ids, * overwrite node contents and preserve author and date in detail. * @return true if completely successful. * @exception IOException if there is an IO or Zip error. */ public static boolean unzipXMLZipFile(String sFilePath, boolean bGiveUserXMLDialog) throws IOException { ProjectCompendium.APP.setWaitCursor(); ZipFile zipFile = new ZipFile(sFilePath); Enumeration entries = zipFile.entries(); // Progress bar zipFile.size(); ZipEntry entry = null; String sXMLFile = ""; //$NON-NLS-1$ String sTemp = ""; //$NON-NLS-1$ while(entries.hasMoreElements()) { entry = (ZipEntry)entries.nextElement(); sTemp = entry.getName(); if (sTemp.endsWith(".xml") && sTemp.startsWith("Exports")) { //$NON-NLS-1$ //$NON-NLS-2$ sXMLFile = sTemp; } // AVOID Thumbs.db files if (sTemp.endsWith(".db")) { //$NON-NLS-1$ continue; } int len = 0; byte[] buffer = new byte[1024]; InputStream in = zipFile.getInputStream(entry); String sFileName = entry.getName(); File file = new File(sFileName); if (file.getParentFile() != null) { file.getParentFile().mkdirs(); } OutputStream out = new BufferedOutputStream(new FileOutputStream(sFileName)); while((len = in.read(buffer)) >=0) { out.write(buffer, 0, len); } in.close(); out.close(); } zipFile.close(); // IMPORT THE XML if (!sXMLFile.equals("")) { //$NON-NLS-1$ File oXMLFile = new File(sXMLFile); if (oXMLFile.exists()) { if (bGiveUserXMLDialog) { ProjectCompendium.APP.onFileXMLImport(oXMLFile); return true; } else { boolean importAuthorAndDate = true; boolean includeOriginalAuthorDate = true; boolean preserveIDs = true; boolean transclude = true; boolean updateTranscludedNodes = true; boolean markSeen = true; File oXMLFile2 = new File(sXMLFile); if (oXMLFile2.exists()) { DBNode.setImportAsTranscluded(transclude); DBNode.setPreserveImportedIds(preserveIDs); DBNode.setUpdateTranscludedNodes(updateTranscludedNodes); DBNode.setNodesMarkedSeen(markSeen); UIViewFrame frame = ProjectCompendium.APP.getCurrentFrame(); if (frame instanceof UIMapViewFrame) { UIMapViewFrame mapFrame = (UIMapViewFrame)frame; UIViewPane oViewPane = mapFrame.getViewPane(); ViewPaneUI oViewPaneUI = oViewPane.getUI(); if (oViewPaneUI != null) { oViewPaneUI.setSmartImport(importAuthorAndDate); oViewPaneUI.onImportXMLFile(sXMLFile, includeOriginalAuthorDate); } } else if (frame instanceof UIListViewFrame){ UIListViewFrame listFrame = (UIListViewFrame)frame; UIList uiList = listFrame.getUIList(); if (uiList != null) { uiList.getListUI().setSmartImport(importAuthorAndDate); uiList.getListUI().onImportXMLFile(sXMLFile, includeOriginalAuthorDate); } } return true; } } } } else { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.noXMLFileFound")); //$NON-NLS-1$ } ProjectCompendium.APP.setDefaultCursor(); return false; } /** * Return the location to store DnD files. Create the directory if necessary. * * @return string - The PATH */ public static String sGetLinkedFilesLocation() { String sDatabaseName = ProjectCompendium.APP.sFriendlyName; UserProfile oUser = ProjectCompendium.APP.getModel().getUserProfile(); String sUserDir = CoreUtilities.cleanFileName(oUser.getUserName())+"_"+oUser.getId(); //$NON-NLS-1$ String sLinkedFilesPath = ProjectCompendium.APP.getModel().getlinkedFilesPath(); Boolean bLinkedFilesFlat = ProjectCompendium.APP.getModel().getlinkedFilesFlat(); if (sLinkedFilesPath == "") { //$NON-NLS-1$ sLinkedFilesPath = "Linked Files"; //$NON-NLS-1$ } String sFullPath = sLinkedFilesPath; if (!bLinkedFilesFlat) { sFullPath = sFullPath + ProjectCompendium.sFS+CoreUtilities.cleanFileName(sDatabaseName)+ProjectCompendium.sFS+sUserDir; } File directory = new File(sFullPath); if (!directory.isDirectory()) { directory.mkdirs(); } int len = sFullPath.length(); if (!sFullPath.substring(len-1).equals(ProjectCompendium.sFS)) { sFullPath = sFullPath + ProjectCompendium.sFS; } return sFullPath; } /** * Check whether the user has asked to copy DnD files to the Linked Files folder or database or not. * If they have, copy the file. * * @param File file, the file to copy to the Linked Files folder/database. */ /*public static File checkCopyLinkedFile(File file) { String path = file.getPath(); if (path.startsWith("www.") || path.startsWith("http:") || path.startsWith("https:")) return null; if (DragAndDropProperties.dndFilePrompt) { String sMessage = ""; if (DragAndDropProperties.dndFileCopy) { sMessage = "Do you want Compendium to copy\n\n"+file.getAbsolutePath()+"\n\ninto the 'Linked Files' directory?\n\n" } else if (DragAndDropProperties.dndFileCopyDatabase) { sMessage = "Do you want Compendium to copy\n\n"+file.getAbsolutePath()+"\n\ninto the 'Linked Files' directory?\n\n" } int response = JOptionPane.showConfirmDialog(ProjectCompendium.APP, sMessage, "External Drag and Drop", JOptionPane.YES_NO_OPTION); if (response == JOptionPane.YES_OPTION) { if (DragAndDropProperties.dndFileCopy) { return copyDnDFile(file); } else if (DragAndDropProperties.dndFileCopyDatabase) { } } } return file; }*/ /** * Copies a dropped file either to linked Files folder or the the database depending on prefs. * @param File file, the file to copy. * @param props the drag and drop properties for this file * @return the newly created LinkedFile object, or <code>null</code> * if the copy could not be created */ public static LinkedFile copyDnDFile(File file, DragAndDropProperties props) { if (props == null) { props = FormatProperties.dndProperties.clone(); // do not alter default settings } assert(props.dndFileCopy); String path = file.getPath(); // should have been checked before if necessary: assert(!(path.startsWith("www.") || path.startsWith("http:") || path.startsWith("https:"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ if (props.dndFileCopyDatabase) { return copyDnDFileToDB(file); } else { return copyDnDFileToFolder(file); } } /** * Copy the given file into the database. * * @param file the file to copy into the database. */ public static LinkedFile copyDnDFileToDB(File file) { IModel model = ProjectCompendium.APP.getModel(); PCSession session = model.getSession(); ILinkedFileService lfs = model.getLinkedFileService(); LinkedFile lf = null; try { lf = lfs.addFile(session, model.getUniqueID(), file); } catch (IOException e) { ProjectCompendium.APP .displayError("Exception: (UIUtilities.copyDnDFileToDB)\n\n" //$NON-NLS-1$ + e.getMessage()); log.error("Error...", e); } return lf; } /** * Copy the given file to the Linked Files folder, into a subfolder with the current database name. * * @param File file, the file to copy to the Linked Files folder. */ public static LinkedFile copyDnDFileToFolder(File file) { File newFile = null; String sPATH = sGetLinkedFilesLocation(); // Fix for Linux sent in by: Matthieu Nu� if (ProjectCompendium.isLinux){ String sFile=file.getAbsolutePath(); sFile = sFile.substring(0, sFile.length() -1); file = new File(sFile); } ////////////////////////////////////////// try { FileInputStream stream = new FileInputStream(file); byte b[] = new byte[stream.available()]; stream.read(b); stream.close(); String sTargetName = file.getName(); sTargetName = sTargetName.replace("#", ""); // Windows ref node launch fails of target filename //$NON-NLS-1$ //$NON-NLS-2$ sTargetName = sTargetName.replaceAll(" *", " "); // has double spaces or a pound sign //$NON-NLS-1$ //$NON-NLS-2$ newFile = new File(sPATH+sTargetName); if (newFile.exists()) { int response = JOptionPane.showConfirmDialog(ProjectCompendium.APP, LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.fileExistsA")+"\n"+ //$NON-NLS-1$ //$NON-NLS-2$ LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.fileExistsB")+"\n\n"+ //$NON-NLS-1$ //$NON-NLS-2$ LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.fileExistsC")+"\n\n", //$NON-NLS-1$ //$NON-NLS-2$ LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.externalDnd"), //$NON-NLS-1$ JOptionPane.YES_NO_OPTION); //$NON-NLS-1$ if (response == JOptionPane.YES_OPTION) { UIFileChooser fileDialog = new UIFileChooser(); fileDialog.setDialogTitle(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.changeName")); //$NON-NLS-1$ fileDialog.setApproveButtonText(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.saveButton")); //$NON-NLS-1$ fileDialog.setApproveButtonMnemonic(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.saveButtonMnemonic").charAt(0)); //$NON-NLS-1$ File file2 = new File(sPATH+file.getName()); if (file2.exists()) { fileDialog.setCurrentDirectory(new File(file2.getParent()+ProjectCompendium.sFS)); fileDialog.setSelectedFile(file2); } UIUtilities.centerComponent(fileDialog, ProjectCompendium.APP); int retval = fileDialog.showDialog(ProjectCompendium.APP, LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.saveButton")); if (retval == JFileChooser.APPROVE_OPTION) { if ((fileDialog.getSelectedFile()) != null) { fileDialog.setVisible(true); String fileName = fileDialog.getSelectedFile().getAbsolutePath(); if (fileName != null) { newFile = new File(fileName); } } } } } FileOutputStream output = new FileOutputStream(newFile); output.write(b); output.flush(); output.close(); } catch (SecurityException e) { log.error("Error...", e); ProjectCompendium.APP.displayError("Error: (UIUtilities.copyDnDFileToFolder)\n\n"+LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.error1")+"\n\n" + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } catch (IOException e) { log.error("Error...", e); ProjectCompendium.APP.displayError("Error: (UIUtilities.copyDnDFileToFolder)\n\n" + e.getMessage()); //$NON-NLS-1$ } LinkedFile lf = new LinkedFileCopy(newFile.getPath()); return lf; } /** * Sort the given Vector of objects, depending on the object type. * Types currently accepted are: UINode, DefaultMutlableTreeNode - CheckNode. * * @param Vector unsortedVector, the vector of Objects to sort. * @return Vector, or sorted objects. */ public static Vector sortList(Vector unsortedVector) { Vector sortedVector = new Vector(); Vector unsortedVector2 = new Vector(); if(unsortedVector.size() > 0) { if(unsortedVector.elementAt(0) instanceof UINode) { for(Enumeration e = unsortedVector.elements();e.hasMoreElements();) { Object obj = (Object)e.nextElement(); if (obj != null && obj instanceof UINode) { String text = ((UINode)obj).getText(); unsortedVector2.addElement(text); } } } else if(unsortedVector.elementAt(0) instanceof DefaultMutableTreeNode) { // FOR CODE GROUP TREE for(Enumeration e = unsortedVector.elements();e.hasMoreElements();) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement(); Object obj = node.getUserObject(); if (obj instanceof CheckNode) { CheckNode check = (CheckNode)obj; Object data = check.getData(); if (data instanceof Code) unsortedVector2.addElement( ((Code)data).getName() ); else if (data instanceof Vector) { Vector checkdata = (Vector)data; unsortedVector2.addElement((String)checkdata.elementAt(1)); } } } } else { return unsortedVector; } } else { return unsortedVector; } Object[] sa = new Object[unsortedVector2.size()]; unsortedVector2.copyInto(sa); java.util.List l = Arrays.asList(sa); Collections.sort(l, new Comparator() { public int compare(Object o1, Object o2) { String s1 = (String)o1; if (s1 == null) s1 = ""; //$NON-NLS-1$ String s2 = (String)o2; if (s2 == null) s2 = ""; //$NON-NLS-1$ String s1L = s1.toLowerCase(); String s2L = s2.toLowerCase(); return (s1L.compareTo(s2L)); } }); // add sorted elements from list to vector for (Iterator it = l.iterator(); it.hasNext(); ) { String sortedElement = (String) it.next(); // add it to vector rearranged with the objects for(Enumeration e = unsortedVector.elements();e.hasMoreElements();) { Object pcobject = (Object)e.nextElement(); String text = ""; //$NON-NLS-1$ if (pcobject instanceof UINode) { text = ((UINode)pcobject).getText(); } else if (pcobject instanceof DefaultMutableTreeNode) { // FOR CODE GROUP TREE DefaultMutableTreeNode node = (DefaultMutableTreeNode)pcobject; Object obj = node.getUserObject(); if (obj instanceof CheckNode) { CheckNode check = (CheckNode)obj; Object data = check.getData(); if (data instanceof Code) text = ((Code)data).getName(); else if (data instanceof Vector) { Vector checkdata = (Vector)data; text = (String)checkdata.elementAt(1); } } } if (text.equals(sortedElement)) { sortedVector.addElement(pcobject); //remove this element so it can't be found again in case there //is more than one object with the same text. unsortedVector.removeElement(pcobject); break; } } } return sortedVector; } /** * Sort the passed Vector of references Nodes into type order and * create a JMenuItem for each node which will launch the given external reference. * * @param Vector refNode, a Vector of reference NodeSummary objects. * @return a Vector of JMenuItems sorted by reference type. */ public static Vector sortReferences(Vector refNodes) { Vector sortedRefs = new Vector(51); Vector group = null; Hashtable groups = new Hashtable(51); int count = refNodes.size(); int i=0; for (i=0; i<count; i++) { NodeSummary node = (NodeSummary)refNodes.elementAt(i); String source = node.getSource(); if (source != null && !source.equals("")) { //$NON-NLS-1$ String label = source; if (CoreUtilities.isFile(source)) { File file = new File(source); label = file.getName(); } final String path = source; JMenuItem miMenuItem = new JMenuItem(label, UIImages.getSmallReferenceIcon(source)); miMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if (path.startsWith("http:") || path.startsWith("https:") || path.startsWith("www.")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ExecuteControl.launch( path ); } else if (path.startsWith(ICoreConstants.sINTERNAL_REFERENCE)) { String sPath = path.substring(ICoreConstants.sINTERNAL_REFERENCE.length()); int ind = sPath.indexOf("/"); //$NON-NLS-1$ if (ind != -1) { String sGoToViewID = sPath.substring(0, ind); String sGoToNodeID = sPath.substring(ind+1); UIViewFrame frame = ProjectCompendium.APP.getCurrentFrame(); Vector history = frame.getNavigationHistory(); UIUtilities.jumpToNode(sGoToViewID, sGoToNodeID, history); } } else { File file = new File(path); String sPath = path; if (file.exists()) { sPath = file.getAbsolutePath(); } // It the reference is not a file, just pass the path as is, as it is probably a special type of url. ExecuteControl.launch( sPath ); } } }); String sType = LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.unknown"); //$NON-NLS-1$ if (source != null) { sType = UIReferenceNodeManager.getReferenceTypeName(source); if (groups.containsKey(sType)) { group = (Vector)groups.get(sType); group.addElement(miMenuItem); groups.put(sType, group); } else { group = new Vector(); group.addElement(miMenuItem); groups.put(sType, group); } } } } int counti = 0; String sKey = ""; //$NON-NLS-1$ for (Enumeration e = groups.elements(); e.hasMoreElements();) { group = (Vector)e.nextElement(); counti = group.size(); for (i=0; i<counti;i++) { sortedRefs.addElement(group.elementAt(i)); } } return sortedRefs; } /** * Remove the menu shortcut Mnemonics from the given MenuElement and its sub MenuElements. */ public static void removeMenuMnemonics(MenuElement[] elements) { for (int i=0; i<elements.length; i++) { MenuElement element = elements[i]; if (element instanceof JMenuItem) { JMenuItem item = (JMenuItem)element; item.setMnemonic(-1); } removeMenuMnemonics(element.getSubElements()); } } /** * Return a SimpleDateFormat instance for the given pattern * @param pattern, the pattern to return the SimpleDateFormat for. * @return SimpleDateFormat. */ public static SimpleDateFormat getSimpleDateFormat(String pattern) { Calendar cal = Calendar.getInstance(); java.util.Date date = cal.getTime(); SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); sdf.applyPattern(pattern); String result = sdf.format(date); return sdf; } /** * Create a new node of the given type, offset to the right of the given node. * * @param UINode uinode, the node to create the new node to the right of. * This node must be in a view so that a call to getViewPane works. * @param int nType, the type of the new node to create. * @param int offSet, the offset the new node should be to the right of the current node. * @param String sText, the text to put in the label of the new node. * @param String sAuthor, the author of this node. * * @return the new uinode object, or null if something failed. */ public static UINode createNodeAndLinkRight(UINode uinode, int nType, int offSet, String sText, String sAuthor) { return createNodeAndLink(DIRECTION_RIGHT, uinode, nType, offSet, sText, sAuthor, getLinkType(nType)); } /** * Create a new node of the given type, offset to the left of the given node. * * @param uinode the node to create the new node to the right of. * This node must be in a view so that a call to getViewPane works. * @param nType the type of the new node to create. * @param offSet the offset the new node should be to the right of the current node. * @param sText the text to put in the label of the new node. * @param sAuthor the author of this node. * * @return the new uinode object, or null if something failed. */ public static UINode createNodeAndLinkLeft(UINode uinode, int nType, int offSet, String sText, String sAuthor) { return createNodeAndLink(DIRECTION_LEFT, uinode, nType, offSet, sText, sAuthor, getLinkType(nType)); } /** * Create a new node of the given type, offset up from the given node. * * @param uinode the node to create the new node to the right of. * This node must be in a view so that a call to getViewPane works. * @param nType the type of the new node to create. * @param offSet the offset the new node should be to the right of the current node. * @param sText the text to put in the label of the new node. * @param sAuthor the author of this node. * * @return the new uinode object, or null if something failed. */ public static UINode createNodeAndLinkUp(UINode uinode, int nType, int offSet, String sText, String sAuthor) { return createNodeAndLink(DIRECTION_UP, uinode, nType, offSet, sText, sAuthor, getLinkType(nType)); } /** * Create a new node of the given type, offset down from the given node. * * @param uinode the node to create the new node to the right of. * This node must be in a view so that a call to getViewPane works. * @param nType the type of the new node to create. * @param offSet the offset the new node should be to the right of the current node. * @param sText the text to put in the label of the new node. * @param sAuthor the author of this node. * * @return the new uinode object, or null if something failed. */ public static UINode createNodeAndLinkDown(UINode uinode, int nType, int offSet, String sText, String sAuthor) { return createNodeAndLink(DIRECTION_DOWN, uinode, nType, offSet, sText, sAuthor, getLinkType(nType)); } /** * Create a new node of the given type, offset in the direction specified, * by the amount specified, from the given node. * * @param iDirection the direction to create the node and link * (DIRECTION_RIGHT,DIRECITON_LEFT, DIRECTION_UP, DIRECTION_DOWN) * @param uinode the node to create the new node to the right of. * This node must be in a view so that a call to getViewPane works. * @param nType the type of the new node to create. * @param offSet the offset the new node should be to the right of the current node. * @param sText the text to put in the label of the new node. * @param sAuthor the author of this node. * @param sLinkType the link type to use for the link. * * @return the new uinode object, or null if something failed. */ public static UINode createNodeAndLink(int iDirection, UINode uinode, int nType, int offSet, String sText, String sAuthor, String sLinkType) { UINode newNode = null; UIViewPane oViewPane = uinode.getViewPane(); if (oViewPane != null) { ViewPaneUI oViewPaneUI = oViewPane.getUI(); if (oViewPaneUI != null) { Point loc = uinode.getNodePosition().getPos(); // CREATE NEW NODE RIGHT OF THE GIVEN NODE WITH THE GIVEN LABEL newNode = oViewPaneUI.createNode(nType, "", //$NON-NLS-1$ sAuthor, sText, "", //$NON-NLS-1$ loc.x, loc.y ); newNode.requestFocus(); int parentHeight = uinode.getBounds().height; int parentWidth = uinode.getBounds().width; int newWidth = newNode.getBounds().width; int newHeight = newNode.getBounds().height; int newX = loc.x; int newY = loc.y; if (parentWidth > newWidth) { newX = loc.x+((parentWidth-newWidth)/2); } else if (parentWidth < newWidth) { newX = loc.x-((newWidth-parentWidth)/2); } if (parentHeight > newHeight) { newY = loc.y+((parentHeight-newHeight)/2); } else if (parentWidth < newWidth) { newY = loc.y-((newHeight-parentHeight)/2); } if (iDirection == DIRECTION_RIGHT) { loc.x = loc.x + parentWidth + offSet; loc.y = newY; } else if (iDirection == DIRECTION_LEFT) { if (loc.x < (offSet+newWidth)) { loc.x=0; } else { loc.x -= (offSet+newWidth); } loc.y = newY; } else if (iDirection == DIRECTION_UP) { if (loc.y < (offSet+newHeight)) { loc.y=0; } else { loc.y = loc.y-(offSet+newHeight); } loc.x = newX; } else if (iDirection == DIRECTION_DOWN) { loc.y = loc.y+parentHeight+offSet; loc.x = newX; } (newNode.getNodePosition()).setPos(loc); try { oViewPane.getView().setNodePosition(newNode.getNode().getId(), loc); } catch(Exception ex) { log.info(ex.getMessage()); } newNode.setLocation(loc); LinkProperties props = getLinkProperties(sLinkType); props.setArrowType(ICoreConstants.ARROW_TO); oViewPaneUI.createLink(newNode, uinode, sLinkType, props); } } return newNode; } /** * Work out the link type from the node type (and for Argument nodes the drag start position->type). * @param uinode com.compendium.ui.UINode, the node to work out the link type for. */ public static String getLinkType(UINode uinode) { int nodeType = uinode.getType(); UILinkGroup group = ProjectCompendium.APP.oLinkGroupManager.getLinkGroup(ProjectCompendium.APP.getActiveLinkGroup()); if (group == null || group.getID().equals("1")) { //$NON-NLS-1$ if ( nodeType == ICoreConstants.CON || nodeType == ICoreConstants.CON_SHORTCUT) { return ICoreConstants.OBJECTS_TO_LINK; } else if (nodeType == ICoreConstants.PRO || nodeType == ICoreConstants.PRO) { return ICoreConstants.SUPPORTS_LINK; } else if (nodeType == ICoreConstants.ARGUMENT || nodeType == ICoreConstants.ARGUMENT_SHORTCUT) { if (uinode.getUI().isPlus) return ICoreConstants.SUPPORTS_LINK; else if (uinode.getUI().isMinus) return ICoreConstants.OBJECTS_TO_LINK; else { if (group != null) { String sDefaultLinkType = group.getDefaultLinkTypeID(); if (!sDefaultLinkType.equals("")) { //$NON-NLS-1$ return sDefaultLinkType; } } } } else { if (group != null) { String sDefaultLinkType = group.getDefaultLinkTypeID(); if (!sDefaultLinkType.equals("")) { //$NON-NLS-1$ return sDefaultLinkType; } } } } else { String sDefaultLinkType = group.getDefaultLinkTypeID(); if (!sDefaultLinkType.equals("")) { //$NON-NLS-1$ return sDefaultLinkType; } } return ICoreConstants.DEFAULT_LINK; } /** * Work out the link type from the node type. * @param uinode com.compendium.ui.UINode, the node to work out the link type for. */ public static String getLinkType(int nodeType) { UILinkGroup group = ProjectCompendium.APP.oLinkGroupManager.getLinkGroup(ProjectCompendium.APP.getActiveLinkGroup()); if (group == null || group.getID().equals("1")) { //$NON-NLS-1$ if ( nodeType == ICoreConstants.CON || nodeType == ICoreConstants.CON_SHORTCUT) { return ICoreConstants.OBJECTS_TO_LINK; } else if (nodeType == ICoreConstants.PRO || nodeType == ICoreConstants.PRO) { return ICoreConstants.SUPPORTS_LINK; } else { if (group != null) { String sDefaultLinkType = group.getDefaultLinkTypeID(); if (!sDefaultLinkType.equals("")) { //$NON-NLS-1$ return sDefaultLinkType; } } } } else { String sDefaultLinkType = group.getDefaultLinkTypeID(); if (!sDefaultLinkType.equals("")) { //$NON-NLS-1$ return sDefaultLinkType; } } return ICoreConstants.DEFAULT_LINK; } /** * Work out the default link formatting properties from the passed link type. * @param LinkProperties the default link properties for the given. */ public static LinkProperties getLinkProperties(String sLinkType) { LinkProperties props = new LinkProperties(); UILinkType oLinkType = ProjectCompendium.APP.oLinkGroupManager.getLinkType(sLinkType); // If no default link set, use model defaults. if (oLinkType == null) { props.setArrowType(ICoreConstants.ARROW_TO); props.setLinkStyle(ICoreConstants.STRAIGHT_LINK); props.setLinkDashed(ICoreConstants.PLAIN_LINE); props.setLinkColour((UILink.getLinkColor(sLinkType)).getRGB()); props.setLinkWeight(1); props.setBackground((Model.BACKGROUND_DEFAULT).getRGB()); props.setForeground((Model.FOREGROUND_DEFAULT).getRGB()); props.setFontFace(Model.FONTFACE_DEFAULT); props.setFontStyle(Model.FONTSTYLE_DEFAULT); props.setFontSize(Model.FONTSIZE_DEFAULT); props.setLabelWrapWidth(Model.LABEL_WRAP_WIDTH_DEFAULT); } else { props.setArrowType(oLinkType.getArrowType()); props.setLinkStyle(oLinkType.getLinkStyle()); props.setLinkDashed(oLinkType.getLinkDashed()); props.setLinkColour(oLinkType.getColour().getRGB()); props.setLinkWeight(oLinkType.getLinkWeight()); props.setBackground(oLinkType.getLinkLabelBackground()); props.setForeground(oLinkType.getLinkLabelForeground()); props.setFontFace(oLinkType.getFontFace()); props.setFontStyle(oLinkType.getFontStyle()); props.setFontSize(oLinkType.getFontSize()); props.setLabelWrapWidth(oLinkType.getLabelWrapWidth()); } return props; } /** * Transform the given x and y positions to the given scale and return them as a Point. * @param x the x position to scale. * @param y the y position to scale. * @param scale the scale to use. * @return Point the scaled version of the given x and y positions. */ public static Point transformPoint(int x, int y, double scale) { Point p1=new Point(x, y); if ( (scale == 0.0 && scale == 1.0) ) return p1; Point p2=new Point(0, 0); AffineTransform af=new AffineTransform(); af.setToScale(scale, scale); try { p2=(Point)af.transform(p1, p2); } catch (Exception excp) { log.info("UIUtilites.transformPoint:failed to transform"); //$NON-NLS-1$ } return p2; } /** * Scale (inverse transform), the given x and y positions and return them as a Point. * @param x the x position to scale. * @param y the y position to scale. * @param scale the scale to use. * @return Point the scaled version of the given x and y positions. */ public static Point scalePoint(int x, int y, double scale) { Point p1=new Point(x, y); if ( (scale == 0.0 && scale == 1.0) ) return p1; Point p2=new Point(0, 0); AffineTransform af=new AffineTransform(); af.setToScale(scale, scale); try { p2=(Point)af.inverseTransform(p1, p2); } catch (Exception excp) { log.info("UIUtilites.scaleCoordinates:failed to inverse transform"); //$NON-NLS-1$ } return p2; } /** * Jump to the Given Node in the Given View and focus it. * * @param sViewID the id of the view to opne. * @param sNodeID the id of the node to focus on. */ public static void jumpToNode(String sViewID, String sNodeID, String sNavigationHistory) { Vector history = new Vector(); history.addElement(sNavigationHistory); jumpToNode(sViewID, sNodeID, history); } /** * Jump to the Given Node in the Given View and focus it. * * @param sViewID the id of the view to opne. * @param sNodeID the id of the node to focus on. */ public static void jumpToNode(String sViewID, String sNodeID, Vector vtNavigationHistory) { IModel model = ProjectCompendium.APP.getModel(); View view = null; try { view = (View)model.getNodeService().getView(model.getSession(), sViewID); } catch (Exception ex) {} if (view == null) { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.viewNotFound")); //$NON-NLS-1$ return; } view.initialize(model.getSession(), model); UIViewFrame oViewFrame = ProjectCompendium.APP.addViewToDesktop(view, view.getLabel()); oViewFrame.setNavigationHistory(vtNavigationHistory); NodeSummary node = null; if (oViewFrame instanceof UIMapViewFrame) { UINode uinode = (UINode)((UIMapViewFrame)oViewFrame).getViewPane().get(sNodeID); if (uinode != null) { node = uinode.getNode(); focusNodeAndScroll(node, oViewFrame); //if(UIViewOutline.me != null){ //UIViewOutline.me.expandPath(view, node); //} } else { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.errorMessage1a")+"\n"+ //$NON-NLS-1$ //$NON-NLS-2$ LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.errorMessage1b")+"\n\n" + //$NON-NLS-1$ //$NON-NLS-2$ LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.errorMessage1c")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ } } else { UIListViewFrame oListViewFrame = (UIListViewFrame)oViewFrame; UIList oUIList = oListViewFrame.getUIList(); NodePosition pos = oUIList.getNode(sNodeID); if (pos != null) { node = pos.getNode(); focusNodeAndScroll(node, oViewFrame); //if(UIViewOutline.me != null) { //UIViewOutline.me.expandPath(view, node); //} } else { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.errorMessage1a")+"\n"+ //$NON-NLS-1$ //$NON-NLS-2$ LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.errorMessage1b")+"\n\n" + //$NON-NLS-1$ //$NON-NLS-2$ LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIUtilities.errorMessage1c")+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ } } } /** * Focus the given node in the given view and scroll so it is visible * @param oNode the node to focus in the view. * @param oViewFrame the view to focus the node in. */ public static void focusNodeAndScroll(NodeSummary oNode, UIViewFrame oViewFrame) { if (oViewFrame instanceof UIMovieMapViewFrame) { UIMovieMapViewFrame frame = (UIMovieMapViewFrame)oViewFrame; frame.jumpToNode(oNode.getId()); UIMovieMapViewPane oPane = (UIMovieMapViewPane)frame.getViewPane(); UINode oUINode = (UINode) oPane.get(oNode.getId()); if (oUINode != null) { Rectangle rect = frame.getVisibleRect(); //pane has height of 4 at this point so using frame. //divider at 75% of pane - so guessing 70% of frame is about the same int newheight = new Float(rect.height * 0.70f).intValue(); rect.height = newheight; Rectangle noderect = oUINode.getBounds(); if (!rect.contains(noderect)) { oUINode.scrollRectToVisible(new Rectangle(0,0, noderect.width, noderect.height)); } oPane.setSelectedNode(null, ICoreConstants.DESELECTALL); oUINode.setRollover(false); oUINode.setSelected(true); oPane.setSelectedNode(oUINode,ICoreConstants.SINGLESELECT); oUINode.moveToFront(); } } else if (oViewFrame instanceof UIMapViewFrame) { UIViewPane oPane = ((UIMapViewFrame)oViewFrame).getViewPane(); UINode oUINode = (UINode) oPane.get(oNode.getId()); if (oUINode != null) { oPane.scrollRectToVisible( oUINode.getBounds() ); oPane.setSelectedNode(null, ICoreConstants.DESELECTALL); oUINode.setRollover(false); oUINode.setSelected(true); oPane.setSelectedNode(oUINode,ICoreConstants.SINGLESELECT); oUINode.moveToFront(); } } else { UIListViewFrame oListViewFrame = (UIListViewFrame)oViewFrame; UIList oUIList = oListViewFrame.getUIList(); oUIList.selectNode(oUIList.getIndexOf(oNode), ICoreConstants.SINGLESELECT); } } /** * Modify a given path so that file:// and linkedFile:// URIs are * handled correctly * @author Sebastian Ehrich * @param path * @return the modified path */ public static String modifyPath(String path) { if (!ProjectCompendium.isWindows) return path; if (LinkedFileDatabase.isDatabaseURI(path)) { return path; } else if (path.startsWith("file:")) //$NON-NLS-1$ { // Windows does not execute file:// ... and filenames with %20 in it // via 'start' - so replace that String newPath = path.replaceFirst("file:/*", ""); //$NON-NLS-1$ //$NON-NLS-2$ newPath = newPath.replace("/", ProjectCompendium.sFS); //$NON-NLS-1$ newPath = newPath.replace("%20", " "); //$NON-NLS-1$ //$NON-NLS-2$ return newPath; } else return path; } /*private void applyOptionPaneBackground(JOptionPane optionPane, Color color) { optionPane.setBackground(color); for (Iterator i = getComponents(optionPane).iterator(); i.hasNext(); ) { Component comp = (Component)i.next(); if (comp instanceof JPanel) { comp.setBackground(color); } } } private Collection getComponents(Container container) { Collection components = new Vector(); Component[] comp = container.getComponents(); for (int i = 0, n = comp.length; i < n; i++) { components.add(comp[i]); if (comp[i] instanceof Container) { components.addAll(getComponents((Container) comp[i])); } } return components; }*/ }