X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FDesktop.java;h=8d9e366a62227deb6fd0652e913260f0540be384;hb=20a4d7ddb86ee996f2b6617a0470922b83354c35;hp=c60537855c716dae2a14ac86eea9cd73e738f23f;hpb=8ef535b690c1f7225d3b4f8a5814009d046882a7;p=jalview.git diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index c605378..8d9e366 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -32,6 +32,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; @@ -68,8 +69,7 @@ import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -93,10 +93,13 @@ 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; @@ -118,6 +121,8 @@ import javax.swing.event.InternalFrameEvent; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; +import org.stackoverflowusers.file.WindowsShortcut; + /** * Jalview Desktop * @@ -346,10 +351,6 @@ public class Desktop extends jalview.jbgui.GDesktop boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE", false); desktop = new MyDesktopPane(selmemusage); - if (Platform.isAMac()) - { - desktop.setDoubleBuffered(false); - } showMemusage.setSelected(selmemusage); desktop.setBackground(Color.white); getContentPane().setLayout(new BorderLayout()); @@ -363,7 +364,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(new DefaultDesktopManager())); + new MyDesktopManager( + (Platform.isWindows() ? new DefaultDesktopManager() + : Platform.isAMac() + ? new AquaInternalFrameManager( + desktop.getDesktopManager()) + : desktop.getDesktopManager()))); Rectangle dims = getLastKnownDimensions(""); if (dims != null) @@ -433,24 +439,6 @@ public class Desktop extends jalview.jbgui.GDesktop }); desktop.addMouseListener(ma); - this.addFocusListener(new FocusListener() - { - - @Override - public void focusLost(FocusEvent e) - { - // TODO Auto-generated method stub - - } - - @Override - public void focusGained(FocusEvent e) - { - Cache.log.debug("Relaying windows after focus gain"); - // make sure that we sort windows properly after we gain focus - instance.relayerWindows(); - } - }); this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this)); // Spawn a thread that shows the splashscreen SwingUtilities.invokeLater(new Runnable() @@ -531,7 +519,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() @@ -542,13 +530,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() @@ -565,7 +553,8 @@ public class Desktop extends jalview.jbgui.GDesktop + e.getMessage()); } } - }); + }).start(); + ; } @Override @@ -868,13 +857,8 @@ public class Desktop extends jalview.jbgui.GDesktop frame.setResizable(resizable); frame.setMaximizable(resizable); frame.setIconifiable(resizable); - if (Platform.isAMac()) - { - frame.setIconifiable(false); - frame.setFrameIcon(null); - // frame.setDesktopIcon(null); - frame.setDoubleBuffered(false); - } + frame.setOpaque(false); + if (frame.getX() < 1 && frame.getY() < 1) { frame.setLocation(xOffset * openFrameCount, @@ -894,6 +878,10 @@ public class Desktop extends jalview.jbgui.GDesktop JInternalFrame itf = desktop.getSelectedFrame(); if (itf != null) { + if (itf instanceof AlignFrame) + { + Jalview.setCurrentAlignFrame((AlignFrame) itf); + } itf.requestFocus(); } } @@ -920,16 +908,6 @@ public class Desktop extends jalview.jbgui.GDesktop menuItem.removeActionListener(menuItem.getActionListeners()[0]); } windowMenu.remove(menuItem); - JInternalFrame itf = desktop.getSelectedFrame(); - if (itf != null) - { - itf.requestFocus(); - if (itf instanceof AlignFrame) - { - Jalview.setCurrentAlignFrame((AlignFrame) itf); - } - } - System.gc(); }; }); @@ -949,6 +927,8 @@ public class Desktop extends jalview.jbgui.GDesktop } }); + setKeyBindings(frame); + desktop.add(frame); windowMenu.add(menuItem); @@ -968,6 +948,42 @@ public class Desktop extends jalview.jbgui.GDesktop } } + /** + * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close + * the window + * + * @param frame + */ + private static void setKeyBindings(JInternalFrame frame) + { + @SuppressWarnings("serial") + final Action closeAction = new AbstractAction() + { + @Override + public void actionPerformed(ActionEvent e) + { + frame.dispose(); + } + }; + + /* + * 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()); + + 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 public void lostOwnership(Clipboard clipboard, Transferable contents) { @@ -1417,7 +1433,6 @@ public class Desktop extends jalview.jbgui.GDesktop { ssm.resetAll(); } - System.gc(); } @Override @@ -2367,7 +2382,7 @@ public class Desktop extends jalview.jbgui.GDesktop { String link = li.next(); if (link.contains(SEQUENCE_ID) - && !link.equals(UrlConstants.DEFAULT_STRING)) + && !UrlConstants.isDefaultString(link)) { check = true; int barPos = link.indexOf("|"); @@ -2456,6 +2471,7 @@ public class Desktop extends jalview.jbgui.GDesktop Thread worker = new Thread(this); worker.start(); } + repaint(); } public boolean isShowMemoryUsage() @@ -2519,14 +2535,6 @@ public class Desktop extends jalview.jbgui.GDesktop } } - /** - * fixes stacking order after a modal dialog to ensure windows that should be - * on top actually are - */ - public void relayerWindows() - { - - } /** * Accessor method to quickly get all the AlignmentFrames loaded. @@ -3329,13 +3337,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 @@ -3363,63 +3425,112 @@ 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; + Cache.log.debug("Adding missing FILE protocol for " + + files.get(protocols.size())); + protocols.add(DataSourceType.FILE); } - java.net.URI uri = new java.net.URI(s); - if (uri.getScheme().toLowerCase().startsWith("http")) + for (java.util.StringTokenizer st = new java.util.StringTokenizer( + data, "\r\n"); st.hasMoreTokens();) { - 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()); + 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); + } } } } @@ -3434,4 +3545,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; + } }