2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.AlignViewportI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.bin.Cache;
26 import jalview.bin.Jalview;
27 import jalview.io.BackupFiles;
28 import jalview.io.DataSourceType;
29 import jalview.io.FileFormat;
30 import jalview.io.FileFormatException;
31 import jalview.io.FileFormatI;
32 import jalview.io.FileFormats;
33 import jalview.io.FileLoader;
34 import jalview.io.FormatAdapter;
35 import jalview.io.IdentifyFile;
36 import jalview.io.JalviewFileChooser;
37 import jalview.io.JalviewFileView;
38 import jalview.jbgui.GSplitFrame;
39 import jalview.jbgui.GStructureViewer;
40 import jalview.project.Jalview2XML;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.viewmodel.AlignmentViewport;
48 import jalview.ws.WSDiscovererI;
49 import jalview.ws.params.ParamManager;
50 import jalview.ws.utils.UrlDownloadClient;
52 import java.awt.BorderLayout;
53 import java.awt.Color;
54 import java.awt.Dimension;
55 import java.awt.FontMetrics;
56 import java.awt.Graphics;
57 import java.awt.GridLayout;
58 import java.awt.Point;
59 import java.awt.Rectangle;
60 import java.awt.Toolkit;
61 import java.awt.Window;
62 import java.awt.datatransfer.Clipboard;
63 import java.awt.datatransfer.ClipboardOwner;
64 import java.awt.datatransfer.DataFlavor;
65 import java.awt.datatransfer.Transferable;
66 import java.awt.dnd.DnDConstants;
67 import java.awt.dnd.DropTargetDragEvent;
68 import java.awt.dnd.DropTargetDropEvent;
69 import java.awt.dnd.DropTargetEvent;
70 import java.awt.dnd.DropTargetListener;
71 import java.awt.event.ActionEvent;
72 import java.awt.event.ActionListener;
73 import java.awt.event.InputEvent;
74 import java.awt.event.KeyEvent;
75 import java.awt.event.MouseAdapter;
76 import java.awt.event.MouseEvent;
77 import java.awt.event.WindowAdapter;
78 import java.awt.event.WindowEvent;
79 import java.beans.PropertyChangeEvent;
80 import java.beans.PropertyChangeListener;
82 import java.io.FileWriter;
83 import java.io.IOException;
85 import java.util.ArrayList;
86 import java.util.HashMap;
87 import java.util.Hashtable;
88 import java.util.List;
89 import java.util.ListIterator;
90 import java.util.StringTokenizer;
91 import java.util.Vector;
92 import java.util.concurrent.ExecutorService;
93 import java.util.concurrent.Executors;
94 import java.util.concurrent.Semaphore;
96 import javax.swing.AbstractAction;
97 import javax.swing.Action;
98 import javax.swing.ActionMap;
99 import javax.swing.Box;
100 import javax.swing.BoxLayout;
101 import javax.swing.DefaultDesktopManager;
102 import javax.swing.DesktopManager;
103 import javax.swing.InputMap;
104 import javax.swing.JButton;
105 import javax.swing.JCheckBox;
106 import javax.swing.JComboBox;
107 import javax.swing.JComponent;
108 import javax.swing.JDesktopPane;
109 import javax.swing.JInternalFrame;
110 import javax.swing.JLabel;
111 import javax.swing.JMenuItem;
112 import javax.swing.JPanel;
113 import javax.swing.JPopupMenu;
114 import javax.swing.JProgressBar;
115 import javax.swing.KeyStroke;
116 import javax.swing.SwingUtilities;
117 import javax.swing.event.HyperlinkEvent;
118 import javax.swing.event.HyperlinkEvent.EventType;
119 import javax.swing.event.InternalFrameAdapter;
120 import javax.swing.event.InternalFrameEvent;
122 import org.stackoverflowusers.file.WindowsShortcut;
129 * @version $Revision: 1.155 $
131 public class Desktop extends jalview.jbgui.GDesktop
132 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
133 jalview.api.StructureSelectionManagerProvider
135 private static int DEFAULT_MIN_WIDTH = 300;
137 private static int DEFAULT_MIN_HEIGHT = 250;
139 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
141 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
143 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
145 protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
147 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
149 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
152 * news reader - null if it was never started.
154 private BlogReader jvnews = null;
156 private File projectFile;
160 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
162 public void addJalviewPropertyChangeListener(
163 PropertyChangeListener listener)
165 changeSupport.addJalviewPropertyChangeListener(listener);
169 * @param propertyName
171 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
172 * java.beans.PropertyChangeListener)
174 public void addJalviewPropertyChangeListener(String propertyName,
175 PropertyChangeListener listener)
177 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
181 * @param propertyName
183 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
184 * java.beans.PropertyChangeListener)
186 public void removeJalviewPropertyChangeListener(String propertyName,
187 PropertyChangeListener listener)
189 changeSupport.removeJalviewPropertyChangeListener(propertyName,
193 /** Singleton Desktop instance */
194 public static Desktop instance;
196 public static MyDesktopPane desktop;
198 static int openFrameCount = 0;
200 static final int xOffset = 30;
202 static final int yOffset = 30;
204 public static jalview.ws.jws1.Discoverer discoverer;
206 public static Object[] jalviewClipboard;
208 public static boolean internalCopy = false;
210 static int fileLoadingCount = 0;
212 class MyDesktopManager implements DesktopManager
215 private DesktopManager delegate;
217 public MyDesktopManager(DesktopManager delegate)
219 this.delegate = delegate;
223 public void activateFrame(JInternalFrame f)
227 delegate.activateFrame(f);
228 } catch (NullPointerException npe)
230 Point p = getMousePosition();
231 instance.showPasteMenu(p.x, p.y);
236 public void beginDraggingFrame(JComponent f)
238 delegate.beginDraggingFrame(f);
242 public void beginResizingFrame(JComponent f, int direction)
244 delegate.beginResizingFrame(f, direction);
248 public void closeFrame(JInternalFrame f)
250 delegate.closeFrame(f);
254 public void deactivateFrame(JInternalFrame f)
256 delegate.deactivateFrame(f);
260 public void deiconifyFrame(JInternalFrame f)
262 delegate.deiconifyFrame(f);
266 public void dragFrame(JComponent f, int newX, int newY)
272 delegate.dragFrame(f, newX, newY);
276 public void endDraggingFrame(JComponent f)
278 delegate.endDraggingFrame(f);
283 public void endResizingFrame(JComponent f)
285 delegate.endResizingFrame(f);
290 public void iconifyFrame(JInternalFrame f)
292 delegate.iconifyFrame(f);
296 public void maximizeFrame(JInternalFrame f)
298 delegate.maximizeFrame(f);
302 public void minimizeFrame(JInternalFrame f)
304 delegate.minimizeFrame(f);
308 public void openFrame(JInternalFrame f)
310 delegate.openFrame(f);
314 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
321 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
325 public void setBoundsForFrame(JComponent f, int newX, int newY,
326 int newWidth, int newHeight)
328 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
331 // All other methods, simply delegate
336 * Creates a new Desktop object.
341 * A note to implementors. It is ESSENTIAL that any activities that might
342 * block are spawned off as threads rather than waited for during this
347 doConfigureStructurePrefs();
348 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
350 if (!Platform.isAMac())
352 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
356 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
362 APQHandlers.setAPQHandlers(this);
363 } catch (Exception e)
365 System.out.println("Cannot set APQHandlers");
366 // e.printStackTrace();
367 } catch (Throwable t)
369 System.out.println("Cannot set APQHandlers");
370 // t.printStackTrace();
374 addWindowListener(new WindowAdapter()
378 public void windowClosing(WindowEvent ev)
384 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
387 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
389 desktop = new MyDesktopPane(selmemusage);
390 showMemusage.setSelected(selmemusage);
391 desktop.setBackground(Color.white);
393 getContentPane().setLayout(new BorderLayout());
394 // alternate config - have scrollbars - see notes in JAL-153
395 // JScrollPane sp = new JScrollPane();
396 // sp.getViewport().setView(desktop);
397 // getContentPane().add(sp, BorderLayout.CENTER);
398 getContentPane().add(desktop, BorderLayout.CENTER);
399 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
401 // This line prevents Windows Look&Feel resizing all new windows to maximum
402 // if previous window was maximised
403 desktop.setDesktopManager(new MyDesktopManager(
404 (Platform.isWindows() ? new DefaultDesktopManager()
406 ? new AquaInternalFrameManager(
407 desktop.getDesktopManager())
408 : desktop.getDesktopManager())));
410 Rectangle dims = getLastKnownDimensions("");
417 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
418 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
421 jconsole = new Console(this, showjconsole);
422 // add essential build information
423 jconsole.setHeader(jalview.bin.Cache.getVersionDetailsForConsole());
425 showConsole(showjconsole);
427 showNews.setVisible(false);
429 experimentalFeatures.setSelected(showExperimental());
431 getIdentifiersOrgData();
435 this.addWindowListener(new WindowAdapter()
438 public void windowClosing(WindowEvent evt)
445 this.addMouseListener(ma = new MouseAdapter()
448 public void mousePressed(MouseEvent evt)
450 if (evt.isPopupTrigger()) // Mac
452 showPasteMenu(evt.getX(), evt.getY());
457 public void mouseReleased(MouseEvent evt)
459 if (evt.isPopupTrigger()) // Windows
461 showPasteMenu(evt.getX(), evt.getY());
465 desktop.addMouseListener(ma);
467 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
468 // Spawn a thread that shows the splashscreen
469 SwingUtilities.invokeLater(new Runnable()
478 // Thread off a new instance of the file chooser - this reduces the time it
479 // takes to open it later on.
480 new Thread(new Runnable()
485 Cache.log.debug("Filechooser init thread started.");
486 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
487 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
489 Cache.log.debug("Filechooser init thread finished.");
492 // Add the service change listener
493 changeSupport.addJalviewPropertyChangeListener("services",
494 new PropertyChangeListener()
498 public void propertyChange(PropertyChangeEvent evt)
500 Cache.log.debug("Firing service changed event for "
501 + evt.getNewValue());
502 JalviewServicesChanged(evt);
509 * Answers true if user preferences to enable experimental features is True
514 public boolean showExperimental()
516 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
517 Boolean.FALSE.toString());
518 return Boolean.valueOf(experimental).booleanValue();
521 public void doConfigureStructurePrefs()
523 // configure services
524 StructureSelectionManager ssm = StructureSelectionManager
525 .getStructureSelectionManager(this);
526 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
528 ssm.setAddTempFacAnnot(jalview.bin.Cache
529 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
530 ssm.setProcessSecondaryStructure(jalview.bin.Cache
531 .getDefault(Preferences.STRUCT_FROM_PDB, true));
532 ssm.setSecStructServices(
533 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
537 ssm.setAddTempFacAnnot(false);
538 ssm.setProcessSecondaryStructure(false);
539 ssm.setSecStructServices(false);
543 public void checkForNews()
545 final Desktop me = this;
546 // Thread off the news reader, in case there are connection problems.
547 new Thread(new Runnable()
552 Cache.log.debug("Starting news thread.");
554 jvnews = new BlogReader(me);
555 showNews.setVisible(true);
556 Cache.log.debug("Completed news thread.");
561 public void getIdentifiersOrgData()
563 // Thread off the identifiers fetcher
564 new Thread(new Runnable()
569 Cache.log.debug("Downloading data from identifiers.org");
570 UrlDownloadClient client = new UrlDownloadClient();
573 client.download(IdOrgSettings.getUrl(),
574 IdOrgSettings.getDownloadLocation());
575 } catch (IOException e)
577 Cache.log.debug("Exception downloading identifiers.org data"
586 protected void showNews_actionPerformed(ActionEvent e)
588 showNews(showNews.isSelected());
591 void showNews(boolean visible)
594 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
595 showNews.setSelected(visible);
596 if (visible && !jvnews.isVisible())
598 new Thread(new Runnable()
603 long now = System.currentTimeMillis();
604 Desktop.instance.setProgressBar(
605 MessageManager.getString("status.refreshing_news"),
607 jvnews.refreshNews();
608 Desktop.instance.setProgressBar(null, now);
617 * recover the last known dimensions for a jalview window
620 * - empty string is desktop, all other windows have unique prefix
621 * @return null or last known dimensions scaled to current geometry (if last
622 * window geom was known)
624 Rectangle getLastKnownDimensions(String windowName)
626 // TODO: lock aspect ratio for scaling desktop Bug #0058199
627 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
628 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
629 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
630 String width = jalview.bin.Cache
631 .getProperty(windowName + "SCREEN_WIDTH");
632 String height = jalview.bin.Cache
633 .getProperty(windowName + "SCREEN_HEIGHT");
634 if ((x != null) && (y != null) && (width != null) && (height != null))
636 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
637 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
638 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
640 // attempt #1 - try to cope with change in screen geometry - this
641 // version doesn't preserve original jv aspect ratio.
642 // take ratio of current screen size vs original screen size.
643 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
644 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
645 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
646 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
647 // rescale the bounds depending upon the current screen geometry.
648 ix = (int) (ix * sw);
649 iw = (int) (iw * sw);
650 iy = (int) (iy * sh);
651 ih = (int) (ih * sh);
652 while (ix >= screenSize.width)
654 jalview.bin.Cache.log.debug(
655 "Window geometry location recall error: shifting horizontal to within screenbounds.");
656 ix -= screenSize.width;
658 while (iy >= screenSize.height)
660 jalview.bin.Cache.log.debug(
661 "Window geometry location recall error: shifting vertical to within screenbounds.");
662 iy -= screenSize.height;
664 jalview.bin.Cache.log.debug(
665 "Got last known dimensions for " + windowName + ": x:" + ix
666 + " y:" + iy + " width:" + iw + " height:" + ih);
668 // return dimensions for new instance
669 return new Rectangle(ix, iy, iw, ih);
674 void showPasteMenu(int x, int y)
676 JPopupMenu popup = new JPopupMenu();
677 JMenuItem item = new JMenuItem(
678 MessageManager.getString("label.paste_new_window"));
679 item.addActionListener(new ActionListener()
682 public void actionPerformed(ActionEvent evt)
689 popup.show(this, x, y);
696 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
697 Transferable contents = c.getContents(this);
699 if (contents != null)
701 String file = (String) contents
702 .getTransferData(DataFlavor.stringFlavor);
704 FileFormatI format = new IdentifyFile().identify(file,
705 DataSourceType.PASTE);
707 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
710 } catch (Exception ex)
713 "Unable to paste alignment from system clipboard:\n" + ex);
718 * Adds and opens the given frame to the desktop
729 public static synchronized void addInternalFrame(
730 final JInternalFrame frame, String title, int w, int h)
732 addInternalFrame(frame, title, true, w, h, true, false);
736 * Add an internal frame to the Jalview desktop
743 * When true, display frame immediately, otherwise, caller must call
744 * setVisible themselves.
750 public static synchronized void addInternalFrame(
751 final JInternalFrame frame, String title, boolean makeVisible,
754 addInternalFrame(frame, title, makeVisible, w, h, true, false);
758 * Add an internal frame to the Jalview desktop and make it visible
771 public static synchronized void addInternalFrame(
772 final JInternalFrame frame, String title, int w, int h,
775 addInternalFrame(frame, title, true, w, h, resizable, false);
779 * Add an internal frame to the Jalview desktop
786 * When true, display frame immediately, otherwise, caller must call
787 * setVisible themselves.
794 * @param ignoreMinSize
795 * Do not set the default minimum size for frame
797 public static synchronized void addInternalFrame(
798 final JInternalFrame frame, String title, boolean makeVisible,
799 int w, int h, boolean resizable, boolean ignoreMinSize)
802 // TODO: allow callers to determine X and Y position of frame (eg. via
804 // TODO: consider fixing method to update entries in the window submenu with
805 // the current window title
807 frame.setTitle(title);
808 if (frame.getWidth() < 1 || frame.getHeight() < 1)
812 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
813 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
814 // IF JALVIEW IS RUNNING HEADLESS
815 // ///////////////////////////////////////////////
816 if (instance == null || (System.getProperty("java.awt.headless") != null
817 && System.getProperty("java.awt.headless").equals("true")))
826 frame.setMinimumSize(
827 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
829 // Set default dimension for Alignment Frame window.
830 // The Alignment Frame window could be added from a number of places,
832 // I did this here in order not to miss out on any Alignment frame.
833 if (frame instanceof AlignFrame)
835 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
836 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
840 frame.setVisible(makeVisible);
841 frame.setClosable(true);
842 frame.setResizable(resizable);
843 frame.setMaximizable(resizable);
844 frame.setIconifiable(resizable);
845 frame.setOpaque(false);
847 if (frame.getX() < 1 && frame.getY() < 1)
849 frame.setLocation(xOffset * openFrameCount,
850 yOffset * ((openFrameCount - 1) % 10) + yOffset);
854 * add an entry for the new frame in the Window menu
855 * (and remove it when the frame is closed)
857 final JMenuItem menuItem = new JMenuItem(title);
858 frame.addInternalFrameListener(new InternalFrameAdapter()
861 public void internalFrameActivated(InternalFrameEvent evt)
863 JInternalFrame itf = desktop.getSelectedFrame();
866 if (itf instanceof AlignFrame)
868 Jalview.setCurrentAlignFrame((AlignFrame) itf);
875 public void internalFrameClosed(InternalFrameEvent evt)
877 PaintRefresher.RemoveComponent(frame);
880 * defensive check to prevent frames being
881 * added half off the window
883 if (openFrameCount > 0)
889 * ensure no reference to alignFrame retained by menu item listener
891 if (menuItem.getActionListeners().length > 0)
893 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
895 windowMenu.remove(menuItem);
899 menuItem.addActionListener(new ActionListener()
902 public void actionPerformed(ActionEvent e)
906 frame.setSelected(true);
907 frame.setIcon(false);
908 } catch (java.beans.PropertyVetoException ex)
915 setKeyBindings(frame);
919 windowMenu.add(menuItem);
924 frame.setSelected(true);
925 frame.requestFocus();
926 } catch (java.beans.PropertyVetoException ve)
928 } catch (java.lang.ClassCastException cex)
931 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
937 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
942 private static void setKeyBindings(JInternalFrame frame)
944 @SuppressWarnings("serial")
945 final Action closeAction = new AbstractAction()
948 public void actionPerformed(ActionEvent e)
955 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
957 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
958 InputEvent.CTRL_DOWN_MASK);
959 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
960 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
962 InputMap inputMap = frame
963 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
964 String ctrlW = ctrlWKey.toString();
965 inputMap.put(ctrlWKey, ctrlW);
966 inputMap.put(cmdWKey, ctrlW);
968 ActionMap actionMap = frame.getActionMap();
969 actionMap.put(ctrlW, closeAction);
973 public void lostOwnership(Clipboard clipboard, Transferable contents)
977 Desktop.jalviewClipboard = null;
980 internalCopy = false;
984 public void dragEnter(DropTargetDragEvent evt)
989 public void dragExit(DropTargetEvent evt)
994 public void dragOver(DropTargetDragEvent evt)
999 public void dropActionChanged(DropTargetDragEvent evt)
1010 public void drop(DropTargetDropEvent evt)
1012 boolean success = true;
1013 // JAL-1552 - acceptDrop required before getTransferable call for
1014 // Java's Transferable for native dnd
1015 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1016 Transferable t = evt.getTransferable();
1017 List<String> files = new ArrayList<>();
1018 List<DataSourceType> protocols = new ArrayList<>();
1022 Desktop.transferFromDropTarget(files, protocols, evt, t);
1023 } catch (Exception e)
1025 e.printStackTrace();
1033 for (int i = 0; i < files.size(); i++)
1035 String file = files.get(i).toString();
1036 DataSourceType protocol = (protocols == null)
1037 ? DataSourceType.FILE
1039 FileFormatI format = null;
1041 if (file.endsWith(".jar"))
1043 format = FileFormat.Jalview;
1048 format = new IdentifyFile().identify(file, protocol);
1051 new FileLoader().LoadFile(file, protocol, format);
1054 } catch (Exception ex)
1059 evt.dropComplete(success); // need this to ensure input focus is properly
1060 // transfered to any new windows created
1070 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1072 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1073 JalviewFileChooser chooser = JalviewFileChooser
1074 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, BackupFiles.getEnabled());
1076 chooser.setFileView(new JalviewFileView());
1077 chooser.setDialogTitle(
1078 MessageManager.getString("label.open_local_file"));
1079 chooser.setToolTipText(MessageManager.getString("action.open"));
1081 int value = chooser.showOpenDialog(this);
1083 if (value == JalviewFileChooser.APPROVE_OPTION)
1085 String choice = chooser.getSelectedFile().getPath();
1086 Cache.setProperty("LAST_DIRECTORY",
1087 chooser.getSelectedFile().getParent());
1089 FileFormatI format = chooser.getSelectedFormat();
1092 * Call IdentifyFile to verify the file contains what its extension implies.
1093 * Skip this step for dynamically added file formats, because
1094 * IdentifyFile does not know how to recognise them.
1096 if (FileFormats.getInstance().isIdentifiable(format))
1100 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1101 } catch (FileFormatException e)
1103 // format = null; //??
1107 if (viewport != null)
1109 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1114 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1126 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1128 // This construct allows us to have a wider textfield
1130 JLabel label = new JLabel(
1131 MessageManager.getString("label.input_file_url"));
1132 final JComboBox history = new JComboBox();
1134 JPanel panel = new JPanel(new GridLayout(2, 1));
1137 history.setPreferredSize(new Dimension(400, 20));
1138 history.setEditable(true);
1139 history.addItem("http://www.");
1141 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1145 if (historyItems != null)
1147 st = new StringTokenizer(historyItems, "\t");
1149 while (st.hasMoreTokens())
1151 history.addItem(st.nextElement());
1155 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1156 MessageManager.getString("label.input_alignment_from_url"),
1157 JvOptionPane.OK_CANCEL_OPTION);
1159 if (reply != JvOptionPane.OK_OPTION)
1164 String url = history.getSelectedItem().toString();
1166 if (url.toLowerCase().endsWith(".jar"))
1168 if (viewport != null)
1170 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1171 FileFormat.Jalview);
1175 new FileLoader().LoadFile(url, DataSourceType.URL,
1176 FileFormat.Jalview);
1181 FileFormatI format = null;
1184 format = new IdentifyFile().identify(url, DataSourceType.URL);
1185 } catch (FileFormatException e)
1187 // TODO revise error handling, distinguish between
1188 // URL not found and response not valid
1193 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1194 MessageManager.formatMessage("label.couldnt_locate",
1197 MessageManager.getString("label.url_not_found"),
1198 JvOptionPane.WARNING_MESSAGE);
1203 if (viewport != null)
1205 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1210 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1216 * Opens the CutAndPaste window for the user to paste an alignment in to
1219 * - if not null, the pasted alignment is added to the current
1220 * alignment; if null, to a new alignment window
1223 public void inputTextboxMenuItem_actionPerformed(
1224 AlignmentViewPanel viewPanel)
1226 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1227 cap.setForInput(viewPanel);
1228 Desktop.addInternalFrame(cap,
1229 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1239 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1240 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1242 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1243 screen.height + "");
1244 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1245 getWidth(), getHeight()));
1247 if (jconsole != null)
1249 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1250 jconsole.stopConsole();
1254 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1257 if (dialogExecutor != null)
1259 dialogExecutor.shutdownNow();
1261 closeAll_actionPerformed(null);
1263 if (groovyConsole != null)
1265 // suppress a possible repeat prompt to save script
1266 groovyConsole.setDirty(false);
1267 groovyConsole.exit();
1272 private void storeLastKnownDimensions(String string, Rectangle jc)
1274 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1275 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1276 + " height:" + jc.height);
1278 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1279 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1280 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1281 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1291 public void aboutMenuItem_actionPerformed(ActionEvent e)
1293 // StringBuffer message = getAboutMessage(false);
1294 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1296 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1297 new Thread(new Runnable()
1302 new SplashScreen(true);
1307 public StringBuffer getAboutMessage(boolean shortv)
1309 StringBuffer message = new StringBuffer();
1310 message.append("<html>");
1313 message.append("<h1><strong>Version: "
1314 + jalview.bin.Cache.getProperty("VERSION")
1315 + "</strong></h1>");
1316 message.append("<strong>Built: <em>"
1317 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1318 + "</em> from " + jalview.bin.Cache.getBuildDetailsForSplash()
1325 message.append("<strong>Version "
1326 + jalview.bin.Cache.getProperty("VERSION")
1327 + "; last updated: "
1328 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1331 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1332 .equals("Checking"))
1334 // JBP removed this message for 2.11: May be reinstated in future version
1335 // message.append("<br>...Checking latest version...</br>");
1337 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1338 .equals(jalview.bin.Cache.getProperty("VERSION")))
1340 boolean red = false;
1341 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1342 .indexOf("automated build") == -1)
1345 // Displayed when code version and jnlp version do not match and code
1346 // version is not a development build
1347 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1350 message.append("<br>!! Version "
1351 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1353 + " is available for download from "
1354 + jalview.bin.Cache.getDefault("www.jalview.org",
1355 "http://www.jalview.org")
1359 message.append("</div>");
1362 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1364 "The Jalview Authors (See AUTHORS file for current list)")
1365 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1366 + "<br><br>For help, see the FAQ at <a href=\"http://www.jalview.org/faq\">www.jalview.org/faq</a> and/or join the jalview-discuss@jalview.org mailing list"
1367 + "<br><br>If you use Jalview, please cite:"
1368 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1369 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1370 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1382 public void documentationMenuItem_actionPerformed(ActionEvent e)
1386 Help.showHelpWindow();
1387 } catch (Exception ex)
1393 public void closeAll_actionPerformed(ActionEvent e)
1395 // TODO show a progress bar while closing?
1396 JInternalFrame[] frames = desktop.getAllFrames();
1397 for (int i = 0; i < frames.length; i++)
1401 frames[i].setClosed(true);
1402 } catch (java.beans.PropertyVetoException ex)
1406 Jalview.setCurrentAlignFrame(null);
1407 System.out.println("ALL CLOSED");
1410 * reset state of singleton objects as appropriate (clear down session state
1411 * when all windows are closed)
1413 StructureSelectionManager ssm = StructureSelectionManager
1414 .getStructureSelectionManager(this);
1422 public void raiseRelated_actionPerformed(ActionEvent e)
1424 reorderAssociatedWindows(false, false);
1428 public void minimizeAssociated_actionPerformed(ActionEvent e)
1430 reorderAssociatedWindows(true, false);
1433 void closeAssociatedWindows()
1435 reorderAssociatedWindows(false, true);
1441 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1445 protected void garbageCollect_actionPerformed(ActionEvent e)
1447 // We simply collect the garbage
1448 jalview.bin.Cache.log.debug("Collecting garbage...");
1450 jalview.bin.Cache.log.debug("Finished garbage collection.");
1457 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1461 protected void showMemusage_actionPerformed(ActionEvent e)
1463 desktop.showMemoryUsage(showMemusage.isSelected());
1470 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1474 protected void showConsole_actionPerformed(ActionEvent e)
1476 showConsole(showConsole.isSelected());
1479 Console jconsole = null;
1482 * control whether the java console is visible or not
1486 void showConsole(boolean selected)
1488 showConsole.setSelected(selected);
1489 // TODO: decide if we should update properties file
1490 Cache.setProperty("SHOW_JAVA_CONSOLE",
1491 Boolean.valueOf(selected).toString());
1492 jconsole.setVisible(selected);
1495 void reorderAssociatedWindows(boolean minimize, boolean close)
1497 JInternalFrame[] frames = desktop.getAllFrames();
1498 if (frames == null || frames.length < 1)
1503 AlignViewportI source = null;
1504 AlignViewportI target = null;
1505 if (frames[0] instanceof AlignFrame)
1507 source = ((AlignFrame) frames[0]).getCurrentView();
1509 else if (frames[0] instanceof TreePanel)
1511 source = ((TreePanel) frames[0]).getViewPort();
1513 else if (frames[0] instanceof PCAPanel)
1515 source = ((PCAPanel) frames[0]).av;
1517 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1519 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1524 for (int i = 0; i < frames.length; i++)
1527 if (frames[i] == null)
1531 if (frames[i] instanceof AlignFrame)
1533 target = ((AlignFrame) frames[i]).getCurrentView();
1535 else if (frames[i] instanceof TreePanel)
1537 target = ((TreePanel) frames[i]).getViewPort();
1539 else if (frames[i] instanceof PCAPanel)
1541 target = ((PCAPanel) frames[i]).av;
1543 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1545 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1548 if (source == target)
1554 frames[i].setClosed(true);
1558 frames[i].setIcon(minimize);
1561 frames[i].toFront();
1565 } catch (java.beans.PropertyVetoException ex)
1580 protected void preferences_actionPerformed(ActionEvent e)
1586 * Shows a file chooser dialog and writes out the current session as a Jalview
1590 public void saveState_actionPerformed()
1592 saveState_actionPerformed(false);
1595 public void saveState_actionPerformed(boolean saveAs)
1597 java.io.File projectFile = getProjectFile();
1598 // autoSave indicates we already have a file and don't need to ask
1599 boolean autoSave = projectFile != null && !saveAs
1600 && BackupFiles.getEnabled();
1602 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1603 // saveAs="+saveAs+", Backups
1604 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1606 boolean approveSave = false;
1609 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1612 chooser.setFileView(new JalviewFileView());
1613 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1615 int value = chooser.showSaveDialog(this);
1617 if (value == JalviewFileChooser.APPROVE_OPTION)
1619 projectFile = chooser.getSelectedFile();
1620 setProjectFile(projectFile);
1625 if (approveSave || autoSave)
1627 final Desktop me = this;
1628 final java.io.File chosenFile = projectFile;
1629 new Thread(new Runnable()
1634 // TODO: refactor to Jalview desktop session controller action.
1635 setProgressBar(MessageManager.formatMessage(
1636 "label.saving_jalview_project", new Object[]
1637 { chosenFile.getName() }), chosenFile.hashCode());
1638 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1639 chosenFile.getParent());
1640 // TODO catch and handle errors for savestate
1641 // TODO prevent user from messing with the Desktop whilst we're saving
1644 BackupFiles backupfiles = new BackupFiles(chosenFile);
1646 new Jalview2XML().saveState(backupfiles.getTempFile());
1648 backupfiles.setWriteSuccess(true);
1649 backupfiles.rollBackupsAndRenameTempFile();
1650 } catch (OutOfMemoryError oom)
1652 new OOMWarning("Whilst saving current state to "
1653 + chosenFile.getName(), oom);
1654 } catch (Exception ex)
1656 Cache.log.error("Problems whilst trying to save to "
1657 + chosenFile.getName(), ex);
1658 JvOptionPane.showMessageDialog(me,
1659 MessageManager.formatMessage(
1660 "label.error_whilst_saving_current_state_to",
1662 { chosenFile.getName() }),
1663 MessageManager.getString("label.couldnt_save_project"),
1664 JvOptionPane.WARNING_MESSAGE);
1666 setProgressBar(null, chosenFile.hashCode());
1673 public void saveAsState_actionPerformed(ActionEvent e)
1675 saveState_actionPerformed(true);
1678 private void setProjectFile(File choice)
1680 this.projectFile = choice;
1683 public File getProjectFile()
1685 return this.projectFile;
1689 * Shows a file chooser dialog and tries to read in the selected file as a
1693 public void loadState_actionPerformed()
1695 final String[] suffix = new String[] { "jvp", "jar" };
1696 final String[] desc = new String[] { "Jalview Project",
1697 "Jalview Project (old)" };
1698 JalviewFileChooser chooser = new JalviewFileChooser(
1699 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1700 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1702 chooser.setFileView(new JalviewFileView());
1703 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1705 int value = chooser.showOpenDialog(this);
1707 if (value == JalviewFileChooser.APPROVE_OPTION)
1709 final File selectedFile = chooser.getSelectedFile();
1710 setProjectFile(selectedFile);
1711 final String choice = selectedFile.getAbsolutePath();
1712 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1713 new Thread(new Runnable()
1718 setProgressBar(MessageManager.formatMessage(
1719 "label.loading_jalview_project", new Object[]
1720 { choice }), choice.hashCode());
1723 new Jalview2XML().loadJalviewAlign(choice);
1724 } catch (OutOfMemoryError oom)
1726 new OOMWarning("Whilst loading project from " + choice, oom);
1727 } catch (Exception ex)
1730 "Problems whilst loading project from " + choice, ex);
1731 JvOptionPane.showMessageDialog(Desktop.desktop,
1732 MessageManager.formatMessage(
1733 "label.error_whilst_loading_project_from",
1736 MessageManager.getString("label.couldnt_load_project"),
1737 JvOptionPane.WARNING_MESSAGE);
1739 setProgressBar(null, choice.hashCode());
1746 public void inputSequence_actionPerformed(ActionEvent e)
1748 new SequenceFetcher(this);
1751 JPanel progressPanel;
1753 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1755 public void startLoading(final String fileName)
1757 if (fileLoadingCount == 0)
1759 fileLoadingPanels.add(addProgressPanel(MessageManager
1760 .formatMessage("label.loading_file", new Object[]
1766 private JPanel addProgressPanel(String string)
1768 if (progressPanel == null)
1770 progressPanel = new JPanel(new GridLayout(1, 1));
1771 totalProgressCount = 0;
1772 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1774 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1775 JProgressBar progressBar = new JProgressBar();
1776 progressBar.setIndeterminate(true);
1778 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1780 thisprogress.add(progressBar, BorderLayout.CENTER);
1781 progressPanel.add(thisprogress);
1782 ((GridLayout) progressPanel.getLayout()).setRows(
1783 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1784 ++totalProgressCount;
1785 instance.validate();
1786 return thisprogress;
1789 int totalProgressCount = 0;
1791 private void removeProgressPanel(JPanel progbar)
1793 if (progressPanel != null)
1795 synchronized (progressPanel)
1797 progressPanel.remove(progbar);
1798 GridLayout gl = (GridLayout) progressPanel.getLayout();
1799 gl.setRows(gl.getRows() - 1);
1800 if (--totalProgressCount < 1)
1802 this.getContentPane().remove(progressPanel);
1803 progressPanel = null;
1810 public void stopLoading()
1813 if (fileLoadingCount < 1)
1815 while (fileLoadingPanels.size() > 0)
1817 removeProgressPanel(fileLoadingPanels.remove(0));
1819 fileLoadingPanels.clear();
1820 fileLoadingCount = 0;
1825 public static int getViewCount(String alignmentId)
1827 AlignmentViewport[] aps = getViewports(alignmentId);
1828 return (aps == null) ? 0 : aps.length;
1833 * @param alignmentId
1834 * - if null, all sets are returned
1835 * @return all AlignmentPanels concerning the alignmentId sequence set
1837 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1839 if (Desktop.desktop == null)
1841 // no frames created and in headless mode
1842 // TODO: verify that frames are recoverable when in headless mode
1845 List<AlignmentPanel> aps = new ArrayList<>();
1846 AlignFrame[] frames = getAlignFrames();
1851 for (AlignFrame af : frames)
1853 for (AlignmentPanel ap : af.alignPanels)
1855 if (alignmentId == null
1856 || alignmentId.equals(ap.av.getSequenceSetId()))
1862 if (aps.size() == 0)
1866 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1871 * get all the viewports on an alignment.
1873 * @param sequenceSetId
1874 * unique alignment id (may be null - all viewports returned in that
1876 * @return all viewports on the alignment bound to sequenceSetId
1878 public static AlignmentViewport[] getViewports(String sequenceSetId)
1880 List<AlignmentViewport> viewp = new ArrayList<>();
1881 if (desktop != null)
1883 AlignFrame[] frames = Desktop.getAlignFrames();
1885 for (AlignFrame afr : frames)
1887 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1888 .equals(sequenceSetId))
1890 if (afr.alignPanels != null)
1892 for (AlignmentPanel ap : afr.alignPanels)
1894 if (sequenceSetId == null
1895 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1903 viewp.add(afr.getViewport());
1907 if (viewp.size() > 0)
1909 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1916 * Explode the views in the given frame into separate AlignFrame
1920 public static void explodeViews(AlignFrame af)
1922 int size = af.alignPanels.size();
1928 for (int i = 0; i < size; i++)
1930 AlignmentPanel ap = af.alignPanels.get(i);
1931 AlignFrame newaf = new AlignFrame(ap);
1934 * Restore the view's last exploded frame geometry if known. Multiple
1935 * views from one exploded frame share and restore the same (frame)
1936 * position and size.
1938 Rectangle geometry = ap.av.getExplodedGeometry();
1939 if (geometry != null)
1941 newaf.setBounds(geometry);
1944 ap.av.setGatherViewsHere(false);
1946 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1947 AlignFrame.DEFAULT_HEIGHT);
1950 af.alignPanels.clear();
1951 af.closeMenuItem_actionPerformed(true);
1956 * Gather expanded views (separate AlignFrame's) with the same sequence set
1957 * identifier back in to this frame as additional views, and close the
1958 * expanded views. Note the expanded frames may themselves have multiple
1959 * views. We take the lot.
1963 public void gatherViews(AlignFrame source)
1965 source.viewport.setGatherViewsHere(true);
1966 source.viewport.setExplodedGeometry(source.getBounds());
1967 JInternalFrame[] frames = desktop.getAllFrames();
1968 String viewId = source.viewport.getSequenceSetId();
1970 for (int t = 0; t < frames.length; t++)
1972 if (frames[t] instanceof AlignFrame && frames[t] != source)
1974 AlignFrame af = (AlignFrame) frames[t];
1975 boolean gatherThis = false;
1976 for (int a = 0; a < af.alignPanels.size(); a++)
1978 AlignmentPanel ap = af.alignPanels.get(a);
1979 if (viewId.equals(ap.av.getSequenceSetId()))
1982 ap.av.setGatherViewsHere(false);
1983 ap.av.setExplodedGeometry(af.getBounds());
1984 source.addAlignmentPanel(ap, false);
1990 af.alignPanels.clear();
1991 af.closeMenuItem_actionPerformed(true);
1998 public JInternalFrame[] getAllFrames()
2000 return desktop.getAllFrames();
2004 * Checks the given url to see if it gives a response indicating that the user
2005 * should be informed of a new questionnaire.
2009 public void checkForQuestionnaire(String url)
2011 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2012 // javax.swing.SwingUtilities.invokeLater(jvq);
2013 new Thread(jvq).start();
2016 public void checkURLLinks()
2018 // Thread off the URL link checker
2019 addDialogThread(new Runnable()
2024 if (Cache.getDefault("CHECKURLLINKS", true))
2026 // check what the actual links are - if it's just the default don't
2027 // bother with the warning
2028 List<String> links = Preferences.sequenceUrlLinks
2031 // only need to check links if there is one with a
2032 // SEQUENCE_ID which is not the default EMBL_EBI link
2033 ListIterator<String> li = links.listIterator();
2034 boolean check = false;
2035 List<JLabel> urls = new ArrayList<>();
2036 while (li.hasNext())
2038 String link = li.next();
2039 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2040 && !UrlConstants.isDefaultString(link))
2043 int barPos = link.indexOf("|");
2044 String urlMsg = barPos == -1 ? link
2045 : link.substring(0, barPos) + ": "
2046 + link.substring(barPos + 1);
2047 urls.add(new JLabel(urlMsg));
2055 // ask user to check in case URL links use old style tokens
2056 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2057 JPanel msgPanel = new JPanel();
2058 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2059 msgPanel.add(Box.createVerticalGlue());
2060 JLabel msg = new JLabel(MessageManager
2061 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2062 JLabel msg2 = new JLabel(MessageManager
2063 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2065 for (JLabel url : urls)
2071 final JCheckBox jcb = new JCheckBox(
2072 MessageManager.getString("label.do_not_display_again"));
2073 jcb.addActionListener(new ActionListener()
2076 public void actionPerformed(ActionEvent e)
2078 // update Cache settings for "don't show this again"
2079 boolean showWarningAgain = !jcb.isSelected();
2080 Cache.setProperty("CHECKURLLINKS",
2081 Boolean.valueOf(showWarningAgain).toString());
2086 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2088 .getString("label.SEQUENCE_ID_no_longer_used"),
2089 JvOptionPane.WARNING_MESSAGE);
2096 * Proxy class for JDesktopPane which optionally displays the current memory
2097 * usage and highlights the desktop area with a red bar if free memory runs
2102 public class MyDesktopPane extends JDesktopPane implements Runnable
2105 private static final float ONE_MB = 1048576f;
2107 boolean showMemoryUsage = false;
2111 java.text.NumberFormat df;
2113 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2116 public MyDesktopPane(boolean showMemoryUsage)
2118 showMemoryUsage(showMemoryUsage);
2121 public void showMemoryUsage(boolean showMemory)
2123 this.showMemoryUsage = showMemory;
2126 Thread worker = new Thread(this);
2132 public boolean isShowMemoryUsage()
2134 return showMemoryUsage;
2140 df = java.text.NumberFormat.getNumberInstance();
2141 df.setMaximumFractionDigits(2);
2142 runtime = Runtime.getRuntime();
2144 while (showMemoryUsage)
2148 maxMemory = runtime.maxMemory() / ONE_MB;
2149 allocatedMemory = runtime.totalMemory() / ONE_MB;
2150 freeMemory = runtime.freeMemory() / ONE_MB;
2151 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2153 percentUsage = (totalFreeMemory / maxMemory) * 100;
2155 // if (percentUsage < 20)
2157 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2159 // instance.set.setBorder(border1);
2162 // sleep after showing usage
2164 } catch (Exception ex)
2166 ex.printStackTrace();
2172 public void paintComponent(Graphics g)
2174 if (showMemoryUsage && g != null && df != null)
2176 if (percentUsage < 20)
2178 g.setColor(Color.red);
2180 FontMetrics fm = g.getFontMetrics();
2183 g.drawString(MessageManager.formatMessage("label.memory_stats",
2185 { df.format(totalFreeMemory), df.format(maxMemory),
2186 df.format(percentUsage) }),
2187 10, getHeight() - fm.getHeight());
2194 * Accessor method to quickly get all the AlignmentFrames loaded.
2196 * @return an array of AlignFrame, or null if none found
2198 public static AlignFrame[] getAlignFrames()
2200 if (Jalview.isHeadlessMode())
2202 // Desktop.desktop is null in headless mode
2203 return new AlignFrame[] { Jalview.currentAlignFrame };
2206 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2212 List<AlignFrame> avp = new ArrayList<>();
2214 for (int i = frames.length - 1; i > -1; i--)
2216 if (frames[i] instanceof AlignFrame)
2218 avp.add((AlignFrame) frames[i]);
2220 else if (frames[i] instanceof SplitFrame)
2223 * Also check for a split frame containing an AlignFrame
2225 GSplitFrame sf = (GSplitFrame) frames[i];
2226 if (sf.getTopFrame() instanceof AlignFrame)
2228 avp.add((AlignFrame) sf.getTopFrame());
2230 if (sf.getBottomFrame() instanceof AlignFrame)
2232 avp.add((AlignFrame) sf.getBottomFrame());
2236 if (avp.size() == 0)
2240 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2245 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2249 public GStructureViewer[] getJmols()
2251 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2257 List<GStructureViewer> avp = new ArrayList<>();
2259 for (int i = frames.length - 1; i > -1; i--)
2261 if (frames[i] instanceof AppJmol)
2263 GStructureViewer af = (GStructureViewer) frames[i];
2267 if (avp.size() == 0)
2271 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2276 * Add Groovy Support to Jalview
2279 public void groovyShell_actionPerformed()
2283 openGroovyConsole();
2284 } catch (Exception ex)
2286 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2287 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2289 MessageManager.getString("label.couldnt_create_groovy_shell"),
2290 MessageManager.getString("label.groovy_support_failed"),
2291 JvOptionPane.ERROR_MESSAGE);
2296 * Open the Groovy console
2298 void openGroovyConsole()
2300 if (groovyConsole == null)
2302 groovyConsole = new groovy.ui.Console();
2303 groovyConsole.setVariable("Jalview", this);
2304 groovyConsole.run();
2307 * We allow only one console at a time, so that AlignFrame menu option
2308 * 'Calculate | Run Groovy script' is unambiguous.
2309 * Disable 'Groovy Console', and enable 'Run script', when the console is
2310 * opened, and the reverse when it is closed
2312 Window window = (Window) groovyConsole.getFrame();
2313 window.addWindowListener(new WindowAdapter()
2316 public void windowClosed(WindowEvent e)
2319 * rebind CMD-Q from Groovy Console to Jalview Quit
2322 enableExecuteGroovy(false);
2328 * show Groovy console window (after close and reopen)
2330 ((Window) groovyConsole.getFrame()).setVisible(true);
2333 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2334 * and disable opening a second console
2336 enableExecuteGroovy(true);
2340 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2341 * binding when opened
2343 protected void addQuitHandler()
2345 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2346 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2347 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2349 getRootPane().getActionMap().put("Quit", new AbstractAction()
2352 public void actionPerformed(ActionEvent e)
2360 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2363 * true if Groovy console is open
2365 public void enableExecuteGroovy(boolean enabled)
2368 * disable opening a second Groovy console
2369 * (or re-enable when the console is closed)
2371 groovyShell.setEnabled(!enabled);
2373 AlignFrame[] alignFrames = getAlignFrames();
2374 if (alignFrames != null)
2376 for (AlignFrame af : alignFrames)
2378 af.setGroovyEnabled(enabled);
2384 * Progress bars managed by the IProgressIndicator method.
2386 private Hashtable<Long, JPanel> progressBars;
2388 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2393 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2396 public void setProgressBar(String message, long id)
2398 if (progressBars == null)
2400 progressBars = new Hashtable<>();
2401 progressBarHandlers = new Hashtable<>();
2404 if (progressBars.get(Long.valueOf(id)) != null)
2406 JPanel panel = progressBars.remove(Long.valueOf(id));
2407 if (progressBarHandlers.contains(Long.valueOf(id)))
2409 progressBarHandlers.remove(Long.valueOf(id));
2411 removeProgressPanel(panel);
2415 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2422 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2423 * jalview.gui.IProgressIndicatorHandler)
2426 public void registerHandler(final long id,
2427 final IProgressIndicatorHandler handler)
2429 if (progressBarHandlers == null
2430 || !progressBars.containsKey(Long.valueOf(id)))
2432 throw new Error(MessageManager.getString(
2433 "error.call_setprogressbar_before_registering_handler"));
2435 progressBarHandlers.put(Long.valueOf(id), handler);
2436 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2437 if (handler.canCancel())
2439 JButton cancel = new JButton(
2440 MessageManager.getString("action.cancel"));
2441 final IProgressIndicator us = this;
2442 cancel.addActionListener(new ActionListener()
2446 public void actionPerformed(ActionEvent e)
2448 handler.cancelActivity(id);
2449 us.setProgressBar(MessageManager
2450 .formatMessage("label.cancelled_params", new Object[]
2451 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2455 progressPanel.add(cancel, BorderLayout.EAST);
2461 * @return true if any progress bars are still active
2464 public boolean operationInProgress()
2466 if (progressBars != null && progressBars.size() > 0)
2474 * This will return the first AlignFrame holding the given viewport instance.
2475 * It will break if there are more than one AlignFrames viewing a particular
2479 * @return alignFrame for viewport
2481 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2483 if (desktop != null)
2485 AlignmentPanel[] aps = getAlignmentPanels(
2486 viewport.getSequenceSetId());
2487 for (int panel = 0; aps != null && panel < aps.length; panel++)
2489 if (aps[panel] != null && aps[panel].av == viewport)
2491 return aps[panel].alignFrame;
2498 public VamsasApplication getVamsasApplication()
2500 // TODO: JAL-3311 remove remaining code from Jalview relating to VAMSAS
2506 * flag set if jalview GUI is being operated programmatically
2508 private boolean inBatchMode = false;
2511 * check if jalview GUI is being operated programmatically
2513 * @return inBatchMode
2515 public boolean isInBatchMode()
2521 * set flag if jalview GUI is being operated programmatically
2523 * @param inBatchMode
2525 public void setInBatchMode(boolean inBatchMode)
2527 this.inBatchMode = inBatchMode;
2530 public void startServiceDiscovery()
2532 startServiceDiscovery(false);
2535 public void startServiceDiscovery(boolean blocking)
2537 boolean alive = true;
2538 Thread t0 = null, t1 = null, t2 = null, t3 = null;
2539 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2542 // todo: changesupport handlers need to be transferred
2543 if (discoverer == null)
2545 discoverer = new jalview.ws.jws1.Discoverer();
2546 // register PCS handler for desktop.
2547 discoverer.addPropertyChangeListener(changeSupport);
2549 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2550 // until we phase out completely
2551 (t0 = new Thread(discoverer)).start();
2554 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2556 t2 = startServiceDiscovery(
2557 jalview.ws.jws2.Jws2Discoverer.getDiscoverer(), false);
2559 if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
2561 // start slivka discovery
2562 t3 = startServiceDiscovery(
2563 jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance(), false);
2572 } catch (Exception e)
2575 // FIXME: Condition should check the discoverer's isRunning rather than
2577 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2578 || (t3 != null && t3.isAlive()) || (t0 != null && t0.isAlive());
2583 public Thread startServiceDiscovery(WSDiscovererI discoverer,
2586 Thread thread = discoverer.startDiscoverer(changeSupport);
2592 } catch (InterruptedException e)
2594 e.printStackTrace();
2601 * called to check if the service discovery process completed successfully.
2605 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2607 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2609 final WSDiscovererI discoverer = jalview.ws.jws2.Jws2Discoverer
2611 final String ermsg = discoverer.getErrorMessages();
2614 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2616 if (serviceChangedDialog == null)
2618 // only run if we aren't already displaying one of these.
2619 addDialogThread(serviceChangedDialog = new Runnable()
2626 * JalviewDialog jd =new JalviewDialog() {
2628 * @Override protected void cancelPressed() { // TODO
2629 * Auto-generated method stub
2631 * }@Override protected void okPressed() { // TODO
2632 * Auto-generated method stub
2634 * }@Override protected void raiseClosed() { // TODO
2635 * Auto-generated method stub
2637 * } }; jd.initDialogFrame(new
2638 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2639 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2640 * + " or mis-configured HTTP proxy settings.<br/>" +
2641 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2643 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2644 * ), true, true, "Web Service Configuration Problem", 450,
2647 * jd.waitForInput();
2649 JvOptionPane.showConfirmDialog(Desktop.desktop,
2650 new JLabel("<html><table width=\"450\"><tr><td>"
2651 + ermsg + "</td></tr></table>"
2652 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
2653 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
2654 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
2655 + " Tools->Preferences dialog box to change them.</p></html>"),
2656 "Web Service Configuration Problem",
2657 JvOptionPane.DEFAULT_OPTION,
2658 JvOptionPane.ERROR_MESSAGE);
2659 serviceChangedDialog = null;
2668 "Errors reported by JABA discovery service. Check web services preferences.\n"
2675 private Runnable serviceChangedDialog = null;
2678 * start a thread to open a URL in the configured browser. Pops up a warning
2679 * dialog to the user if there is an exception when calling out to the browser
2684 public static void showUrl(final String url)
2686 showUrl(url, Desktop.instance);
2690 * Like showUrl but allows progress handler to be specified
2694 * (null) or object implementing IProgressIndicator
2696 public static void showUrl(final String url,
2697 final IProgressIndicator progress)
2699 new Thread(new Runnable()
2706 if (progress != null)
2708 progress.setProgressBar(MessageManager
2709 .formatMessage("status.opening_params", new Object[]
2710 { url }), this.hashCode());
2712 jalview.util.BrowserLauncher.openURL(url);
2713 } catch (Exception ex)
2715 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2717 .getString("label.web_browser_not_found_unix"),
2718 MessageManager.getString("label.web_browser_not_found"),
2719 JvOptionPane.WARNING_MESSAGE);
2721 ex.printStackTrace();
2723 if (progress != null)
2725 progress.setProgressBar(null, this.hashCode());
2731 public static WsParamSetManager wsparamManager = null;
2733 public static ParamManager getUserParameterStore()
2735 if (wsparamManager == null)
2737 wsparamManager = new WsParamSetManager();
2739 return wsparamManager;
2743 * static hyperlink handler proxy method for use by Jalview's internal windows
2747 public static void hyperlinkUpdate(HyperlinkEvent e)
2749 if (e.getEventType() == EventType.ACTIVATED)
2754 url = e.getURL().toString();
2755 Desktop.showUrl(url);
2756 } catch (Exception x)
2760 if (Cache.log != null)
2762 Cache.log.error("Couldn't handle string " + url + " as a URL.");
2767 "Couldn't handle string " + url + " as a URL.");
2770 // ignore any exceptions due to dud links.
2777 * single thread that handles display of dialogs to user.
2779 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
2782 * flag indicating if dialogExecutor should try to acquire a permit
2784 private volatile boolean dialogPause = true;
2789 private java.util.concurrent.Semaphore block = new Semaphore(0);
2791 private static groovy.ui.Console groovyConsole;
2794 * add another dialog thread to the queue
2798 public void addDialogThread(final Runnable prompter)
2800 dialogExecutor.submit(new Runnable()
2810 } catch (InterruptedException x)
2815 if (instance == null)
2821 SwingUtilities.invokeAndWait(prompter);
2822 } catch (Exception q)
2824 Cache.log.warn("Unexpected Exception in dialog thread.", q);
2830 public void startDialogQueue()
2832 // set the flag so we don't pause waiting for another permit and semaphore
2833 // the current task to begin
2834 dialogPause = false;
2839 protected void snapShotWindow_actionPerformed(ActionEvent e)
2843 ImageMaker im = new jalview.util.ImageMaker(
2844 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
2845 getHeight(), of = new File("Jalview_snapshot"
2846 + System.currentTimeMillis() + ".eps"),
2847 "View of desktop", null, 0, false);
2850 paintAll(im.getGraphics());
2852 } catch (Exception q)
2854 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
2858 Cache.log.info("Successfully written snapshot to file "
2859 + of.getAbsolutePath());
2863 * Explode the views in the given SplitFrame into separate SplitFrame windows.
2864 * This respects (remembers) any previous 'exploded geometry' i.e. the size
2865 * and location last time the view was expanded (if any). However it does not
2866 * remember the split pane divider location - this is set to match the
2867 * 'exploding' frame.
2871 public void explodeViews(SplitFrame sf)
2873 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
2874 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
2875 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
2877 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
2879 int viewCount = topPanels.size();
2886 * Processing in reverse order works, forwards order leaves the first panels
2887 * not visible. I don't know why!
2889 for (int i = viewCount - 1; i >= 0; i--)
2892 * Make new top and bottom frames. These take over the respective
2893 * AlignmentPanel objects, including their AlignmentViewports, so the
2894 * cdna/protein relationships between the viewports is carried over to the
2897 * explodedGeometry holds the (x, y) position of the previously exploded
2898 * SplitFrame, and the (width, height) of the AlignFrame component
2900 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
2901 AlignFrame newTopFrame = new AlignFrame(topPanel);
2902 newTopFrame.setSize(oldTopFrame.getSize());
2903 newTopFrame.setVisible(true);
2904 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
2905 .getExplodedGeometry();
2906 if (geometry != null)
2908 newTopFrame.setSize(geometry.getSize());
2911 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
2912 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
2913 newBottomFrame.setSize(oldBottomFrame.getSize());
2914 newBottomFrame.setVisible(true);
2915 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
2916 .getExplodedGeometry();
2917 if (geometry != null)
2919 newBottomFrame.setSize(geometry.getSize());
2922 topPanel.av.setGatherViewsHere(false);
2923 bottomPanel.av.setGatherViewsHere(false);
2924 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
2926 if (geometry != null)
2928 splitFrame.setLocation(geometry.getLocation());
2930 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
2934 * Clear references to the panels (now relocated in the new SplitFrames)
2935 * before closing the old SplitFrame.
2938 bottomPanels.clear();
2943 * Gather expanded split frames, sharing the same pairs of sequence set ids,
2944 * back into the given SplitFrame as additional views. Note that the gathered
2945 * frames may themselves have multiple views.
2949 public void gatherViews(GSplitFrame source)
2952 * special handling of explodedGeometry for a view within a SplitFrame: - it
2953 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
2954 * height) of the AlignFrame component
2956 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
2957 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
2958 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
2959 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
2960 myBottomFrame.viewport
2961 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
2962 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
2963 myTopFrame.viewport.setGatherViewsHere(true);
2964 myBottomFrame.viewport.setGatherViewsHere(true);
2965 String topViewId = myTopFrame.viewport.getSequenceSetId();
2966 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
2968 JInternalFrame[] frames = desktop.getAllFrames();
2969 for (JInternalFrame frame : frames)
2971 if (frame instanceof SplitFrame && frame != source)
2973 SplitFrame sf = (SplitFrame) frame;
2974 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
2975 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
2976 boolean gatherThis = false;
2977 for (int a = 0; a < topFrame.alignPanels.size(); a++)
2979 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
2980 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
2981 if (topViewId.equals(topPanel.av.getSequenceSetId())
2982 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
2985 topPanel.av.setGatherViewsHere(false);
2986 bottomPanel.av.setGatherViewsHere(false);
2987 topPanel.av.setExplodedGeometry(
2988 new Rectangle(sf.getLocation(), topFrame.getSize()));
2989 bottomPanel.av.setExplodedGeometry(
2990 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
2991 myTopFrame.addAlignmentPanel(topPanel, false);
2992 myBottomFrame.addAlignmentPanel(bottomPanel, false);
2998 topFrame.getAlignPanels().clear();
2999 bottomFrame.getAlignPanels().clear();
3006 * The dust settles...give focus to the tab we did this from.
3008 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3011 public static groovy.ui.Console getGroovyConsole()
3013 return groovyConsole;
3017 * handles the payload of a drag and drop event.
3019 * TODO refactor to desktop utilities class
3022 * - Data source strings extracted from the drop event
3024 * - protocol for each data source extracted from the drop event
3028 * - the payload from the drop event
3031 public static void transferFromDropTarget(List<String> files,
3032 List<DataSourceType> protocols, DropTargetDropEvent evt,
3033 Transferable t) throws Exception
3036 DataFlavor uriListFlavor = new DataFlavor(
3037 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3040 urlFlavour = new DataFlavor(
3041 "application/x-java-url; class=java.net.URL");
3042 } catch (ClassNotFoundException cfe)
3044 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3047 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3052 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3053 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3054 // means url may be null.
3057 protocols.add(DataSourceType.URL);
3058 files.add(url.toString());
3059 Cache.log.debug("Drop handled as URL dataflavor "
3060 + files.get(files.size() - 1));
3065 if (Platform.isAMac())
3068 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3072 } catch (Throwable ex)
3074 Cache.log.debug("URL drop handler failed.", ex);
3077 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3079 // Works on Windows and MacOSX
3080 Cache.log.debug("Drop handled as javaFileListFlavor");
3081 for (Object file : (List) t
3082 .getTransferData(DataFlavor.javaFileListFlavor))
3084 files.add(((File) file).toString());
3085 protocols.add(DataSourceType.FILE);
3090 // Unix like behaviour
3091 boolean added = false;
3093 if (t.isDataFlavorSupported(uriListFlavor))
3095 Cache.log.debug("Drop handled as uriListFlavor");
3096 // This is used by Unix drag system
3097 data = (String) t.getTransferData(uriListFlavor);
3101 // fallback to text: workaround - on OSX where there's a JVM bug
3102 Cache.log.debug("standard URIListFlavor failed. Trying text");
3103 // try text fallback
3104 DataFlavor textDf = new DataFlavor(
3105 "text/plain;class=java.lang.String");
3106 if (t.isDataFlavorSupported(textDf))
3108 data = (String) t.getTransferData(textDf);
3111 Cache.log.debug("Plain text drop content returned "
3112 + (data == null ? "Null - failed" : data));
3117 while (protocols.size() < files.size())
3119 Cache.log.debug("Adding missing FILE protocol for "
3120 + files.get(protocols.size()));
3121 protocols.add(DataSourceType.FILE);
3123 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3124 data, "\r\n"); st.hasMoreTokens();)
3127 String s = st.nextToken();
3128 if (s.startsWith("#"))
3130 // the line is a comment (as per the RFC 2483)
3133 java.net.URI uri = new java.net.URI(s);
3134 if (uri.getScheme().toLowerCase().startsWith("http"))
3136 protocols.add(DataSourceType.URL);
3137 files.add(uri.toString());
3141 // otherwise preserve old behaviour: catch all for file objects
3142 java.io.File file = new java.io.File(uri);
3143 protocols.add(DataSourceType.FILE);
3144 files.add(file.toString());
3149 if (Cache.log.isDebugEnabled())
3151 if (data == null || !added)
3154 if (t.getTransferDataFlavors() != null
3155 && t.getTransferDataFlavors().length > 0)
3158 "Couldn't resolve drop data. Here are the supported flavors:");
3159 for (DataFlavor fl : t.getTransferDataFlavors())
3162 "Supported transfer dataflavor: " + fl.toString());
3163 Object df = t.getTransferData(fl);
3166 Cache.log.debug("Retrieves: " + df);
3170 Cache.log.debug("Retrieved nothing");
3176 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3182 if (Platform.isWindows())
3185 Cache.log.debug("Scanning dropped content for Windows Link Files");
3187 // resolve any .lnk files in the file drop
3188 for (int f = 0; f < files.size(); f++)
3190 String source = files.get(f).toLowerCase();
3191 if (protocols.get(f).equals(DataSourceType.FILE)
3192 && (source.endsWith(".lnk") || source.endsWith(".url")
3193 || source.endsWith(".site")))
3197 File lf = new File(files.get(f));
3198 // process link file to get a URL
3199 Cache.log.debug("Found potential link file: " + lf);
3200 WindowsShortcut wscfile = new WindowsShortcut(lf);
3201 String fullname = wscfile.getRealFilename();
3202 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3203 files.set(f, fullname);
3204 Cache.log.debug("Parsed real filename " + fullname
3205 + " to extract protocol: " + protocols.get(f));
3206 } catch (Exception ex)
3209 "Couldn't parse " + files.get(f) + " as a link file.",
3218 * Sets the Preferences property for experimental features to True or False
3219 * depending on the state of the controlling menu item
3222 protected void showExperimental_actionPerformed(boolean selected)
3224 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3228 * Answers a (possibly empty) list of any structure viewer frames (currently
3229 * for either Jmol or Chimera) which are currently open. This may optionally
3230 * be restricted to viewers of a specified class, or viewers linked to a
3231 * specified alignment panel.
3234 * if not null, only return viewers linked to this panel
3235 * @param structureViewerClass
3236 * if not null, only return viewers of this class
3239 public List<StructureViewerBase> getStructureViewers(
3240 AlignmentPanel apanel,
3241 Class<? extends StructureViewerBase> structureViewerClass)
3243 List<StructureViewerBase> result = new ArrayList<>();
3244 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3246 for (JInternalFrame frame : frames)
3248 if (frame instanceof StructureViewerBase)
3250 if (structureViewerClass == null
3251 || structureViewerClass.isInstance(frame))
3254 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3256 result.add((StructureViewerBase) frame);