X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FDesktop.java;h=b3a82bdf80032adcbda44722581e3d8a8d887fef;hb=79d2d1087d5a8a8242a6bc9ba9e2695059504669;hp=cb3ed95f0572b6741583145c7d0fdbc83795f8ac;hpb=004a35d07335854184fdd335920b7210eebd66d9;p=jalview.git diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index cb3ed95..b3a82bd 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,15 +93,19 @@ 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.JFileChooser; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; @@ -118,6 +122,8 @@ import javax.swing.event.InternalFrameEvent; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; +import org.stackoverflowusers.file.WindowsShortcut; + /** * Jalview Desktop * @@ -188,6 +194,13 @@ public class Desktop extends jalview.jbgui.GDesktop public static MyDesktopPane desktop; + public static MyDesktopPane getDesktop() + { + // BH 2018 could use currentThread() here as a reference to a + // Hashtable in JavaScript + return desktop; + } + static int openFrameCount = 0; static final int xOffset = 30; @@ -362,7 +375,8 @@ public class Desktop extends jalview.jbgui.GDesktop new MyDesktopManager( (Platform.isWindows() ? new DefaultDesktopManager() : Platform.isAMac() - ? new AquaInternalFrameManager() + ? new AquaInternalFrameManager( + desktop.getDesktopManager()) : desktop.getDesktopManager()))); Rectangle dims = getLastKnownDimensions(""); @@ -373,33 +387,83 @@ public class Desktop extends jalview.jbgui.GDesktop else { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2, - 900, 650); + int xPos = Math.max(5, (screenSize.width - 900) / 2); + int yPos = Math.max(5, (screenSize.height - 650) / 2); + setBounds(xPos, yPos, 900, 650); } - jconsole = new Console(this, showjconsole); - // add essential build information - jconsole.setHeader( - "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION") - + "\n" + "Jalview Installation: " - + jalview.bin.Cache.getDefault("INSTALLATION", - "unknown") - + "\n" + "Build Date: " - + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") - + "\n" + "Java version: " - + System.getProperty("java.version") + "\n" - + System.getProperty("os.arch") + " " - + System.getProperty("os.name") + " " - + System.getProperty("os.version")); + /** + * BH 2018 + * + * @j2sNative + */ + { + + jconsole = new Console(this, showjconsole); + // add essential build information + jconsole.setHeader("Jalview Version: " + + jalview.bin.Cache.getProperty("VERSION") + "\n" + + "Jalview Installation: " + + jalview.bin.Cache.getDefault("INSTALLATION", "unknown") + + "\n" + "Build Date: " + + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n" + + "Java version: " + System.getProperty("java.version") + "\n" + + System.getProperty("os.arch") + " " + + System.getProperty("os.name") + " " + + System.getProperty("os.version")); + + showConsole(showjconsole); + + showNews.setVisible(false); + + experimentalFeatures.setSelected(showExperimental()); + + getIdentifiersOrgData(); + + checkURLLinks(); + + // Spawn a thread that shows the splashscreen + + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + new SplashScreen(); + } + }); - showConsole(showjconsole); + // Thread off a new instance of the file chooser - this reduces the time it + // takes to open it later on. + new Thread(new Runnable() + { + @Override + public void run() + { + Cache.log.debug("Filechooser init thread started."); + String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT"); + JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), + fileFormat); + Cache.log.debug("Filechooser init thread finished."); + } + }).start(); + // Add the service change listener + changeSupport.addJalviewPropertyChangeListener("services", + new PropertyChangeListener() + { - showNews.setVisible(false); + @Override + public void propertyChange(PropertyChangeEvent evt) + { + Cache.log.debug("Firing service changed event for " + + evt.getNewValue()); + JalviewServicesChanged(evt); + } - experimentalFeatures.setSelected(showExperimental()); + }); - getIdentifiersOrgData(); + } // end BH 2018 ignore - checkURLLinks(); + this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this)); this.addWindowListener(new WindowAdapter() { @@ -433,63 +497,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() - { - @Override - public void run() - { - new SplashScreen(); - } - }); - - // Thread off a new instance of the file chooser - this reduces the time it - // takes to open it later on. - new Thread(new Runnable() - { - @Override - public void run() - { - Cache.log.debug("Filechooser init thread started."); - String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT"); - JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), - fileFormat); - Cache.log.debug("Filechooser init thread finished."); - } - }).start(); - // Add the service change listener - changeSupport.addJalviewPropertyChangeListener("services", - new PropertyChangeListener() - { - - @Override - public void propertyChange(PropertyChangeEvent evt) - { - Cache.log.debug("Firing service changed event for " - + evt.getNewValue()); - JalviewServicesChanged(evt); - } - - }); } /** @@ -529,20 +536,28 @@ public class Desktop extends jalview.jbgui.GDesktop public void checkForNews() { + + /** + * BH 2018 + * + * @j2sNative + */ + { final Desktop me = this; // Thread off the news reader, in case there are connection problems. addDialogThread(new Runnable() { - @Override - public void run() - { - Cache.log.debug("Starting news thread."); + @Override + public void run() + { + Cache.log.debug("Starting news thread."); - jvnews = new BlogReader(me); - showNews.setVisible(true); - Cache.log.debug("Completed news thread."); - } + jvnews = new BlogReader(me); + showNews.setVisible(true); + Cache.log.debug("Completed news thread."); + } }); + } } public void getIdentifiersOrgData() @@ -576,6 +591,12 @@ public class Desktop extends jalview.jbgui.GDesktop void showNews(boolean visible) { + /** + * BH 2018 + * + * @j2sNative + * + */ { Cache.log.debug((visible ? "Showing" : "Hiding") + " news."); showNews.setSelected(visible); @@ -659,7 +680,8 @@ public class Desktop extends jalview.jbgui.GDesktop private void doVamsasClientCheck() { - if (jalview.bin.Cache.vamsasJarsPresent()) + if (/** @j2sNative false && */ // BH 2018 + jalview.bin.Cache.vamsasJarsPresent()) { setupVamsasDisconnectedGui(); VamsasMenu.setVisible(true); @@ -868,6 +890,8 @@ public class Desktop extends jalview.jbgui.GDesktop frame.setResizable(resizable); frame.setMaximizable(resizable); frame.setIconifiable(resizable); + frame.setOpaque(/** @j2sNative true || */ + false); if (frame.getX() < 1 && frame.getY() < 1) { @@ -888,6 +912,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(); } } @@ -914,16 +942,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(); }; }); @@ -943,6 +961,8 @@ public class Desktop extends jalview.jbgui.GDesktop } }); + setKeyBindings(frame); + desktop.add(frame); windowMenu.add(menuItem); @@ -962,6 +982,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) { @@ -1007,7 +1063,7 @@ public class Desktop extends jalview.jbgui.GDesktop // Java's Transferable for native dnd evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); Transferable t = evt.getTransferable(); - List files = new ArrayList<>(); + List files = new ArrayList<>(); List protocols = new ArrayList<>(); try @@ -1025,13 +1081,15 @@ public class Desktop extends jalview.jbgui.GDesktop { for (int i = 0; i < files.size(); i++) { - String file = files.get(i).toString(); + // BH 2018 File or String + Object file = files.get(i); + String fileName = file.toString(); DataSourceType protocol = (protocols == null) ? DataSourceType.FILE : protocols.get(i); FileFormatI format = null; - if (file.endsWith(".jar")) + if (fileName.endsWith(".jar")) { format = FileFormat.Jalview; @@ -1041,7 +1099,7 @@ public class Desktop extends jalview.jbgui.GDesktop format = new IdentifyFile().identify(file, protocol); } - new FileLoader().LoadFile(file, protocol, format); + new FileLoader().LoadFile(null, file, protocol, format); } } catch (Exception ex) @@ -1071,42 +1129,45 @@ public class Desktop extends jalview.jbgui.GDesktop MessageManager.getString("label.open_local_file")); chooser.setToolTipText(MessageManager.getString("action.open")); - int value = chooser.showOpenDialog(this); - - if (value == JalviewFileChooser.APPROVE_OPTION) + chooser.setCallback(new Runnable() { - String choice = chooser.getSelectedFile().getPath(); - Cache.setProperty("LAST_DIRECTORY", - chooser.getSelectedFile().getParent()); - FileFormatI format = chooser.getSelectedFormat(); - - /* - * Call IdentifyFile to verify the file contains what its extension implies. - * Skip this step for dynamically added file formats, because - * IdentifyFile does not know how to recognise them. - */ - if (FileFormats.getInstance().isIdentifiable(format)) + @Override + public void run() { - try - { - format = new IdentifyFile().identify(choice, DataSourceType.FILE); - } catch (FileFormatException e) + File selectedFile = chooser.getSelectedFile(); + Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent()); + + FileFormatI format = chooser.getSelectedFormat(); + + /* + * Call IdentifyFile to verify the file contains what its extension implies. + * Skip this step for dynamically added file formats, because + * IdentifyFile does not know how to recognise them. + */ + if (FileFormats.getInstance().isIdentifiable(format)) { - // format = null; //?? + try + { + format = new IdentifyFile().identify(selectedFile, + DataSourceType.FILE); + } catch (FileFormatException e) + { + // format = null; //?? + } } - } - if (viewport != null) - { - new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE, - format); - } - else - { - new FileLoader().LoadFile(choice, DataSourceType.FILE, format); + new FileLoader().LoadFile(viewport, selectedFile, + DataSourceType.FILE, format); } + }); + + int value = chooser.showOpenDialog(this); + if (value == JFileChooser.APPROVE_OPTION) + { + chooser.getCallback().run(); } + } /** @@ -1122,8 +1183,8 @@ public class Desktop extends jalview.jbgui.GDesktop // for viewing JLabel label = new JLabel( MessageManager.getString("label.input_file_url")); - final JComboBox history = new JComboBox(); + JComboBox history = new JComboBox(); JPanel panel = new JPanel(new GridLayout(2, 1)); panel.add(label); panel.add(history); @@ -1145,66 +1206,28 @@ public class Desktop extends jalview.jbgui.GDesktop } } - int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel, - MessageManager.getString("label.input_alignment_from_url"), - JvOptionPane.OK_CANCEL_OPTION); - - if (reply != JvOptionPane.OK_OPTION) - { - return; - } - - String url = history.getSelectedItem().toString(); - - if (url.toLowerCase().endsWith(".jar")) - { - if (viewport != null) - { - new FileLoader().LoadFile(viewport, url, DataSourceType.URL, - FileFormat.Jalview); - } - else - { - new FileLoader().LoadFile(url, DataSourceType.URL, - FileFormat.Jalview); - } - } - else - { - FileFormatI format = null; - try - { - format = new IdentifyFile().identify(url, DataSourceType.URL); - } catch (FileFormatException e) - { - // TODO revise error handling, distinguish between - // URL not found and response not valid - } + // BH 2018 -- providing a callback for SwingJS + // dialogOption is just a simple way to provide + // context for the modal-like response. + // The only requirement is that desktop implement + // PropertyChangeListener, which is used already in Java + // for changes in input value and such within the dialogs. - if (format == null) - { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, - MessageManager.formatMessage("label.couldnt_locate", - new Object[] - { url }), - MessageManager.getString("label.url_not_found"), - JvOptionPane.WARNING_MESSAGE); + String dialogOption = "label.input_alignment_from_url"; + desktop.dialogData = new Object[] { dialogOption, viewport, history }; + desktop.onDialogReturn( + JvOptionPane.showInternalConfirmDialog(desktop, panel, + MessageManager.getString(dialogOption), + JvOptionPane.OK_CANCEL_OPTION)); - return; - } + // no code may follow this, as SwingJS will not block + // callback in JavaScript comes via a property change event, + // thus going into desktop.onDialogReturn(int) just the same as + // in Java. - if (viewport != null) - { - new FileLoader().LoadFile(viewport, url, DataSourceType.URL, - format); - } - else - { - new FileLoader().LoadFile(url, DataSourceType.URL, format); - } - } } + /** * Opens the CutAndPaste window for the user to paste an alignment in to * @@ -1411,7 +1434,6 @@ public class Desktop extends jalview.jbgui.GDesktop { ssm.resetAll(); } - System.gc(); } @Override @@ -1481,11 +1503,14 @@ public class Desktop extends jalview.jbgui.GDesktop */ void showConsole(boolean selected) { - showConsole.setSelected(selected); // TODO: decide if we should update properties file - Cache.setProperty("SHOW_JAVA_CONSOLE", - Boolean.valueOf(selected).toString()); - jconsole.setVisible(selected); + if (jconsole != null) // BH 2018 + { + showConsole.setSelected(selected); + Cache.setProperty("SHOW_JAVA_CONSOLE", + Boolean.valueOf(selected).toString()); + jconsole.setVisible(selected); + } } void reorderAssociatedWindows(boolean minimize, boolean close) @@ -1586,6 +1611,8 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void saveState_actionPerformed(ActionEvent e) { + // TODO: JAL-3048 not needed for Jalview-JS + JalviewFileChooser chooser = new JalviewFileChooser("jvp", "Jalview Project"); @@ -1659,6 +1686,8 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void loadState_actionPerformed(ActionEvent e) { + // TODO: JAL-3048 not needed for Jalview-JS + JalviewFileChooser chooser = new JalviewFileChooser( Cache.getProperty("LAST_DIRECTORY"), new String[] { "jvp", "jar" }, @@ -1718,7 +1747,7 @@ public class Desktop extends jalview.jbgui.GDesktop ArrayList fileLoadingPanels = new ArrayList<>(); - public void startLoading(final String fileName) + public void startLoading(final Object fileName) { if (fileLoadingCount == 0) { @@ -1966,6 +1995,8 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void vamsasImport_actionPerformed(ActionEvent e) { + // TODO: JAL-3048 not needed for Jalview-JS + if (v_client == null) { // Load and try to start a session. @@ -2242,6 +2273,8 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void vamsasSave_actionPerformed(ActionEvent e) { + // TODO: JAL-3048 not needed for Jalview-JS + if (v_client != null) { // TODO: VAMSAS DOCUMENT EXTENSION is VDJ @@ -2345,7 +2378,8 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void run() { - if (Cache.getDefault("CHECKURLLINKS", true)) + if (/** @j2sNative false && */ // BH 2018 + Cache.getDefault("CHECKURLLINKS", true)) { // check what the actual links are - if it's just the default don't // bother with the warning @@ -2361,7 +2395,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("|"); @@ -2423,9 +2457,159 @@ public class Desktop extends jalview.jbgui.GDesktop * * @author AMW */ - public class MyDesktopPane extends JDesktopPane implements Runnable + public class MyDesktopPane extends JDesktopPane + implements Runnable, PropertyChangeListener { + public Object[] dialogData; + + // @Override + @Override + public void propertyChange(PropertyChangeEvent event) + { + Object val = event.getNewValue(); + String name = event.getPropertyName(); + System.out.println(name); + switch (event.getSource().getClass().getName()) + { + case "javax.swing.JOptionPane": + switch (name) + { + case "inputValue": + onDialogReturn(val); + return; + case "value": + if (val instanceof Integer) + { + onDialogReturn(((Integer) val).intValue()); + } + else + { + onDialogReturn(val); + } + return; + } + break; + case "javax.swing.ColorChooserDialog": + switch (name) + { + case "SelectedColor": + onDialogReturn(val); + return; + } + break; + case "javax.swing.JFileChooser": + switch (name) + { + case "SelectedFile": + // in JavaScript, this File object will have a _bytes property, + // because the file data has already been loaded + onDialogReturn(new Object[] { (File) val }); + return; + } + break; + } + System.out.println(event.getSource().getClass().getName() + " " + + event.getPropertyName() + ": " + event.getNewValue()); + } + + // JSCOmponent.DialogCaller interface + void onDialogReturn(Object value) + { + switch ((String) dialogData[0]) + { + case "SelectedFile": + case "runnable": + dialogData[0] = value; + ((Runnable) dialogData[1]).run(); + break; + case "label.select_feature_colour": + ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value); + break; + } + } + + // JSCOmponent.DialogCaller interface + void onDialogReturn(int value) + { + if (value != Math.floor(value)) + { + // in JavaScript, this will be NaN, oddly enough + return; + } + + switch ((String) dialogData[0]) + { + case "runnable": + dialogData[0] = Integer.valueOf(value); + ((Runnable) dialogData[1]).run(); + break; + case "label.input_alignment_from_url": + // reconstruct the parameter data + int reply = value; + AlignViewport viewport = (AlignViewport) dialogData[1]; + JComboBox history = (JComboBox) dialogData[2]; + // the rest of this is unchangaed + if (reply != JvOptionPane.OK_OPTION) + { + return; + } + + String url = history.getSelectedItem().toString(); + + if (url.toLowerCase().endsWith(".jar")) + { + if (viewport != null) + { + new FileLoader().LoadFile(viewport, url, DataSourceType.URL, + FileFormat.Jalview); + } + else + { + new FileLoader().LoadFile(url, DataSourceType.URL, + FileFormat.Jalview); + } + } + else + { + FileFormatI format = null; + try + { + format = new IdentifyFile().identify(url, DataSourceType.URL); + } catch (FileFormatException e) + { + // TODO revise error handling, distinguish between + // URL not found and response not valid + } + + if (format == null) + { + JvOptionPane.showInternalMessageDialog(Desktop.desktop, + MessageManager.formatMessage("label.couldnt_locate", + new Object[] + { url }), + MessageManager.getString("label.url_not_found"), + JvOptionPane.WARNING_MESSAGE); + + return; + } + + if (viewport != null) + { + new FileLoader().LoadFile(viewport, url, DataSourceType.URL, + format); + } + else + { + new FileLoader().LoadFile(url, DataSourceType.URL, format); + } + } + + break; + } + + } + private static final float ONE_MB = 1048576f; boolean showMemoryUsage = false; @@ -2514,14 +2698,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. @@ -3324,13 +3500,86 @@ public class Desktop extends jalview.jbgui.GDesktop return groovyConsole; } - public static void transferFromDropTarget(List files, + /** + * 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 { + + // BH 2018 changed List to List to allow for File from SwingJS + +// DataFlavor[] flavors = t.getTransferDataFlavors(); +// for (int i = 0; i < flavors.length; i++) { +// if (flavors[i].isFlavorJavaFileListType()) { +// evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); +// List list = (List) t.getTransferData(flavors[i]); +// for (int j = 0; j < list.size(); j++) { +// File file = (File) list.get(j); +// byte[] data = getDroppedFileBytes(file); +// fileName.setText(file.getName() + " - " + data.length + " " + evt.getLocation()); +// JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent(); +// target.setText(new String(data)); +// } +// dtde.dropComplete(true); +// return; +// } +// 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 @@ -3338,7 +3587,7 @@ public class Desktop extends jalview.jbgui.GDesktop for (Object file : (List) t .getTransferData(DataFlavor.javaFileListFlavor)) { - files.add(((File) file).toString()); + files.add(file); protocols.add(DataSourceType.FILE); } } @@ -3358,63 +3607,113 @@ 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) - { - Cache.log.debug("Retrieves: " + df); - } - else + "Couldn't resolve drop data. Here are the supported flavors:"); + for (DataFlavor fl : t.getTransferDataFlavors()) { - 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).toString().toLowerCase(); + if (protocols.get(f).equals(DataSourceType.FILE) + && (source.endsWith(".lnk") || source.endsWith(".url") + || source.endsWith(".site"))) + { + try { + Object obj = files.get(f); + File lf = (obj instanceof File ? (File) obj : new File((String) obj)); + // 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); + } } } } @@ -3429,4 +3728,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; + } }