X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FDesktop.java;h=647971e7ac8dfd21a4968128b42e6ea37feb125e;hb=b9bde68b87a581a1f21e47cb19839791a192134a;hp=36bf55197ff51eade05a074a9ec65fa1dea4c1f0;hpb=6481f37ec5a68050d4dab8aebdfcb99a3dc15d86;p=jalview.git diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 36bf551..647971e 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -20,8 +20,6 @@ */ package jalview.gui; -import static jalview.util.UrlConstants.SEQUENCE_ID; - import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.bin.Cache; @@ -32,6 +30,7 @@ import jalview.io.FileFormatException; import jalview.io.FileFormatI; import jalview.io.FileFormats; import jalview.io.FileLoader; +import jalview.io.FormatAdapter; import jalview.io.IdentifyFile; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; @@ -61,6 +60,13 @@ import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; +import java.awt.desktop.AboutEvent; +import java.awt.desktop.AboutHandler; +import java.awt.desktop.PreferencesEvent; +import java.awt.desktop.PreferencesHandler; +import java.awt.desktop.QuitEvent; +import java.awt.desktop.QuitHandler; +import java.awt.desktop.QuitResponse; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; @@ -79,9 +85,11 @@ import java.beans.PropertyChangeListener; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.IOException; import java.net.URL; import java.util.ArrayList; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.ListIterator; @@ -92,19 +100,22 @@ import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.DefaultDesktopManager; import javax.swing.DesktopManager; +import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDesktopPane; -import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JProgressBar; @@ -117,6 +128,8 @@ import javax.swing.event.InternalFrameEvent; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; +import org.stackoverflowusers.file.WindowsShortcut; + /** * Jalview Desktop * @@ -138,6 +151,8 @@ public class Desktop extends jalview.jbgui.GDesktop private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES"; + public static HashMap savingFiles = new HashMap<>(); + private JalviewChangeSupport changeSupport = new JalviewChangeSupport(); /** @@ -339,14 +354,83 @@ public class Desktop extends jalview.jbgui.GDesktop doConfigureStructurePrefs(); setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION")); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* comments + * galore + * to + * change the line numbers + */ + + /* + if (!Platform.isAMac()) + { + // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + } + else + */ + // { + // this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop(); + + hdesktop.setAboutHandler(new AboutHandler() + { + @Override + public void handleAbout(AboutEvent e) + { + aboutMenuItem_actionPerformed(null); + } + }); + hdesktop.setPreferencesHandler(new PreferencesHandler() + { + @Override + public void handlePreferences(PreferencesEvent e) + { + preferences_actionPerformed(null); + } + }); + hdesktop.setQuitHandler(new QuitHandler() + { + @Override + public void handleQuitRequestWith(QuitEvent e, QuitResponse r) + { + int n = JOptionPane.showConfirmDialog(null, + MessageManager.getString("label.quit_jalview"), + MessageManager.getString("action.quit"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, + null); + if (n == JOptionPane.OK_OPTION) + { + System.out.println("Shortcut Quit confirmed by user"); + quit(); + } + else + { + System.out.println("Shortcut Quit cancelled by user"); + } + } + }); + + // } + + addWindowListener(new WindowAdapter() + { + + @Override + public void windowClosing(WindowEvent ev) + { + quit(); + } + }); + boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE", false); + boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE", false); desktop = new MyDesktopPane(selmemusage); showMemusage.setSelected(selmemusage); desktop.setBackground(Color.white); + getContentPane().setLayout(new BorderLayout()); // alternate config - have scrollbars - see notes in JAL-153 // JScrollPane sp = new JScrollPane(); @@ -357,13 +441,12 @@ public class Desktop extends jalview.jbgui.GDesktop // This line prevents Windows Look&Feel resizing all new windows to maximum // if previous window was maximised - desktop.setDesktopManager( - new MyDesktopManager( - (Platform.isWindows() ? new DefaultDesktopManager() - : Platform.isAMac() - ? new AquaInternalFrameManager( - desktop.getDesktopManager()) - : desktop.getDesktopManager()))); + desktop.setDesktopManager(new MyDesktopManager( + (Platform.isWindows() ? new DefaultDesktopManager() + : Platform.isAMac() + ? new AquaInternalFrameManager( + desktop.getDesktopManager()) + : desktop.getDesktopManager()))); Rectangle dims = getLastKnownDimensions(""); if (dims != null) @@ -513,7 +596,7 @@ public class Desktop extends jalview.jbgui.GDesktop { final Desktop me = this; // Thread off the news reader, in case there are connection problems. - addDialogThread(new Runnable() + new Thread(new Runnable() { @Override public void run() @@ -524,13 +607,13 @@ public class Desktop extends jalview.jbgui.GDesktop showNews.setVisible(true); Cache.log.debug("Completed news thread."); } - }); + }).start(); } public void getIdentifiersOrgData() { // Thread off the identifiers fetcher - addDialogThread(new Runnable() + new Thread(new Runnable() { @Override public void run() @@ -547,7 +630,8 @@ public class Desktop extends jalview.jbgui.GDesktop + e.getMessage()); } } - }); + }).start(); + ; } @Override @@ -850,6 +934,7 @@ public class Desktop extends jalview.jbgui.GDesktop frame.setResizable(resizable); frame.setMaximizable(resizable); frame.setIconifiable(resizable); + frame.setOpaque(false); if (frame.getX() < 1 && frame.getY() < 1) { @@ -900,8 +985,6 @@ public class Desktop extends jalview.jbgui.GDesktop menuItem.removeActionListener(menuItem.getActionListeners()[0]); } windowMenu.remove(menuItem); - - System.gc(); }; }); @@ -943,42 +1026,39 @@ public class Desktop extends jalview.jbgui.GDesktop } /** - * Add key bindings to a JInternalFrame so that ctrl-W and cmd-W will close + * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close * the window * * @param frame - * the JInternalFrame to set the key bindings for */ private static void setKeyBindings(JInternalFrame frame) { - // create a close action - class CloseAction extends AbstractAction + @SuppressWarnings("serial") + final Action closeAction = new AbstractAction() { - private JInternalFrame frame; - - CloseAction(JInternalFrame frame) - { - this.frame = frame; - } - @Override public void actionPerformed(ActionEvent e) { frame.dispose(); } - } - - final CloseAction closeAction = new CloseAction(frame); + }; - // set up keybindings for ctrl-W and cmd-W + /* + * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action + */ KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK); KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); - frame.getInputMap().put(ctrlWKey, ctrlWKey.toString()); - frame.getActionMap().put(ctrlWKey.toString(), closeAction); - frame.getInputMap().put(cmdWKey, ctrlWKey.toString()); - frame.getActionMap().put(cmdWKey.toString(), closeAction); + + InputMap inputMap = frame + .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + String ctrlW = ctrlWKey.toString(); + inputMap.put(ctrlWKey, ctrlW); + inputMap.put(cmdWKey, ctrlW); + + ActionMap actionMap = frame.getActionMap(); + actionMap.put(ctrlW, closeAction); } @Override @@ -1248,6 +1328,8 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void quit() { + System.out.println("********** Desktop.quit()"); + System.out.println(savingFiles.toString()); Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + ""); @@ -1430,7 +1512,6 @@ public class Desktop extends jalview.jbgui.GDesktop { ssm.resetAll(); } - System.gc(); } @Override @@ -2379,7 +2460,7 @@ public class Desktop extends jalview.jbgui.GDesktop while (li.hasNext()) { String link = li.next(); - if (link.contains(SEQUENCE_ID) + if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID) && !UrlConstants.isDefaultString(link)) { check = true; @@ -2533,7 +2614,6 @@ public class Desktop extends jalview.jbgui.GDesktop } } - /** * Accessor method to quickly get all the AlignmentFrames loaded. * @@ -3335,13 +3415,67 @@ public class Desktop extends jalview.jbgui.GDesktop return groovyConsole; } + /** + * handles the payload of a drag and drop event. + * + * TODO refactor to desktop utilities class + * + * @param files + * - Data source strings extracted from the drop event + * @param protocols + * - protocol for each data source extracted from the drop event + * @param evt + * - the drop event + * @param t + * - the payload from the drop event + * @throws Exception + */ public static void transferFromDropTarget(List files, List protocols, DropTargetDropEvent evt, Transferable t) throws Exception { DataFlavor uriListFlavor = new DataFlavor( - "text/uri-list;class=java.lang.String"); + "text/uri-list;class=java.lang.String"), urlFlavour = null; + try + { + urlFlavour = new DataFlavor( + "application/x-java-url; class=java.net.URL"); + } catch (ClassNotFoundException cfe) + { + Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe); + } + + if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour)) + { + + try + { + java.net.URL url = (URL) t.getTransferData(urlFlavour); + // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099 + // means url may be null. + if (url != null) + { + protocols.add(DataSourceType.URL); + files.add(url.toString()); + Cache.log.debug("Drop handled as URL dataflavor " + + files.get(files.size() - 1)); + return; + } + else + { + if (Platform.isAMac()) + { + System.err.println( + "Please ignore plist error - occurs due to problem with java 8 on OSX"); + } + ; + } + } catch (Throwable ex) + { + Cache.log.debug("URL drop handler failed.", ex); + } + } if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { // Works on Windows and MacOSX @@ -3369,63 +3503,114 @@ public class Desktop extends jalview.jbgui.GDesktop // fallback to text: workaround - on OSX where there's a JVM bug Cache.log.debug("standard URIListFlavor failed. Trying text"); // try text fallback - data = (String) t.getTransferData( - new DataFlavor("text/plain;class=java.lang.String")); - if (Cache.log.isDebugEnabled()) + DataFlavor textDf = new DataFlavor( + "text/plain;class=java.lang.String"); + if (t.isDataFlavorSupported(textDf)) { - Cache.log.debug("fallback returned " + data); + data = (String) t.getTransferData(textDf); } + + Cache.log.debug("Plain text drop content returned " + + (data == null ? "Null - failed" : data)); + } - while (protocols.size() < files.size()) - { - Cache.log.debug("Adding missing FILE protocol for " - + files.get(protocols.size())); - protocols.add(DataSourceType.FILE); - } - for (java.util.StringTokenizer st = new java.util.StringTokenizer( - data, "\r\n"); st.hasMoreTokens();) + if (data != null) { - added = true; - String s = st.nextToken(); - if (s.startsWith("#")) + while (protocols.size() < files.size()) { - // the line is a comment (as per the RFC 2483) - continue; - } - java.net.URI uri = new java.net.URI(s); - if (uri.getScheme().toLowerCase().startsWith("http")) - { - protocols.add(DataSourceType.URL); - files.add(uri.toString()); + Cache.log.debug("Adding missing FILE protocol for " + + files.get(protocols.size())); + protocols.add(DataSourceType.FILE); } - else + for (java.util.StringTokenizer st = new java.util.StringTokenizer( + data, "\r\n"); st.hasMoreTokens();) { - // otherwise preserve old behaviour: catch all for file objects - java.io.File file = new java.io.File(uri); - protocols.add(DataSourceType.FILE); - files.add(file.toString()); + added = true; + String s = st.nextToken(); + if (s.startsWith("#")) + { + // the line is a comment (as per the RFC 2483) + continue; + } + java.net.URI uri = new java.net.URI(s); + if (uri.getScheme().toLowerCase().startsWith("http")) + { + protocols.add(DataSourceType.URL); + files.add(uri.toString()); + } + else + { + // otherwise preserve old behaviour: catch all for file objects + java.io.File file = new java.io.File(uri); + protocols.add(DataSourceType.FILE); + files.add(file.toString()); + } } } + if (Cache.log.isDebugEnabled()) { if (data == null || !added) { - Cache.log.debug( - "Couldn't resolve drop data. Here are the supported flavors:"); - for (DataFlavor fl : t.getTransferDataFlavors()) + + if (t.getTransferDataFlavors() != null + && t.getTransferDataFlavors().length > 0) { Cache.log.debug( - "Supported transfer dataflavor: " + fl.toString()); - Object df = t.getTransferData(fl); - if (df != null) + "Couldn't resolve drop data. Here are the supported flavors:"); + for (DataFlavor fl : t.getTransferDataFlavors()) { - Cache.log.debug("Retrieves: " + df); - } - else - { - Cache.log.debug("Retrieved nothing"); + Cache.log.debug( + "Supported transfer dataflavor: " + fl.toString()); + Object df = t.getTransferData(fl); + if (df != null) + { + Cache.log.debug("Retrieves: " + df); + } + else + { + Cache.log.debug("Retrieved nothing"); + } } } + else + { + Cache.log.debug("Couldn't resolve dataflavor for drop: " + + t.toString()); + } + } + } + } + if (Platform.isWindows()) + + { + Cache.log.debug("Scanning dropped content for Windows Link Files"); + + // resolve any .lnk files in the file drop + for (int f = 0; f < files.size(); f++) + { + String source = files.get(f).toLowerCase(); + if (protocols.get(f).equals(DataSourceType.FILE) + && (source.endsWith(".lnk") || source.endsWith(".url") + || source.endsWith(".site"))) + { + try + { + File lf = new File(files.get(f)); + // process link file to get a URL + Cache.log.debug("Found potential link file: " + lf); + WindowsShortcut wscfile = new WindowsShortcut(lf); + String fullname = wscfile.getRealFilename(); + protocols.set(f, FormatAdapter.checkProtocol(fullname)); + files.set(f, fullname); + Cache.log.debug("Parsed real filename " + fullname + + " to extract protocol: " + protocols.get(f)); + } catch (Exception ex) + { + Cache.log.error( + "Couldn't parse " + files.get(f) + " as a link file.", + ex); + } } } } @@ -3440,4 +3625,41 @@ public class Desktop extends jalview.jbgui.GDesktop { Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected)); } + + /** + * Answers a (possibly empty) list of any structure viewer frames (currently + * for either Jmol or Chimera) which are currently open. This may optionally + * be restricted to viewers of a specified class, or viewers linked to a + * specified alignment panel. + * + * @param apanel + * if not null, only return viewers linked to this panel + * @param structureViewerClass + * if not null, only return viewers of this class + * @return + */ + public List getStructureViewers( + AlignmentPanel apanel, + Class structureViewerClass) + { + List result = new ArrayList<>(); + JInternalFrame[] frames = Desktop.instance.getAllFrames(); + + for (JInternalFrame frame : frames) + { + if (frame instanceof StructureViewerBase) + { + if (structureViewerClass == null + || structureViewerClass.isInstance(frame)) + { + if (apanel == null + || ((StructureViewerBase) frame).isLinkedWith(apanel)) + { + result.add((StructureViewerBase) frame); + } + } + } + } + return result; + } }