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.params.ParamManager;
49 import jalview.ws.utils.UrlDownloadClient;
51 import java.awt.BorderLayout;
52 import java.awt.Color;
53 import java.awt.Dimension;
54 import java.awt.FontMetrics;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.Toolkit;
60 import java.awt.Window;
61 import java.awt.datatransfer.Clipboard;
62 import java.awt.datatransfer.ClipboardOwner;
63 import java.awt.datatransfer.DataFlavor;
64 import java.awt.datatransfer.Transferable;
65 import java.awt.dnd.DnDConstants;
66 import java.awt.dnd.DropTargetDragEvent;
67 import java.awt.dnd.DropTargetDropEvent;
68 import java.awt.dnd.DropTargetEvent;
69 import java.awt.dnd.DropTargetListener;
70 import java.awt.event.ActionEvent;
71 import java.awt.event.ActionListener;
72 import java.awt.event.InputEvent;
73 import java.awt.event.KeyEvent;
74 import java.awt.event.MouseAdapter;
75 import java.awt.event.MouseEvent;
76 import java.awt.event.WindowAdapter;
77 import java.awt.event.WindowEvent;
78 import java.beans.PropertyChangeEvent;
79 import java.beans.PropertyChangeListener;
81 import java.io.FileWriter;
82 import java.io.IOException;
84 import java.util.ArrayList;
85 import java.util.HashMap;
86 import java.util.Hashtable;
87 import java.util.List;
88 import java.util.ListIterator;
89 import java.util.StringTokenizer;
90 import java.util.Vector;
91 import java.util.concurrent.ExecutorService;
92 import java.util.concurrent.Executors;
93 import java.util.concurrent.Semaphore;
95 import javax.swing.AbstractAction;
96 import javax.swing.Action;
97 import javax.swing.ActionMap;
98 import javax.swing.Box;
99 import javax.swing.BoxLayout;
100 import javax.swing.DefaultDesktopManager;
101 import javax.swing.DesktopManager;
102 import javax.swing.InputMap;
103 import javax.swing.JButton;
104 import javax.swing.JCheckBox;
105 import javax.swing.JComboBox;
106 import javax.swing.JComponent;
107 import javax.swing.JDesktopPane;
108 import javax.swing.JInternalFrame;
109 import javax.swing.JLabel;
110 import javax.swing.JMenuItem;
111 import javax.swing.JPanel;
112 import javax.swing.JPopupMenu;
113 import javax.swing.JProgressBar;
114 import javax.swing.KeyStroke;
115 import javax.swing.SwingUtilities;
116 import javax.swing.event.HyperlinkEvent;
117 import javax.swing.event.HyperlinkEvent.EventType;
118 import javax.swing.event.InternalFrameAdapter;
119 import javax.swing.event.InternalFrameEvent;
121 import org.stackoverflowusers.file.WindowsShortcut;
128 * @version $Revision: 1.155 $
130 public class Desktop extends jalview.jbgui.GDesktop
131 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
132 jalview.api.StructureSelectionManagerProvider
134 private static int DEFAULT_MIN_WIDTH = 300;
136 private static int DEFAULT_MIN_HEIGHT = 250;
138 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
140 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
142 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
144 protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
146 public static HashMap<String, FileWriter> savingFiles = new HashMap<String, FileWriter>();
148 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
151 * news reader - null if it was never started.
153 private BlogReader jvnews = null;
155 private File projectFile;
159 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
161 public void addJalviewPropertyChangeListener(
162 PropertyChangeListener listener)
164 changeSupport.addJalviewPropertyChangeListener(listener);
168 * @param propertyName
170 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
171 * java.beans.PropertyChangeListener)
173 public void addJalviewPropertyChangeListener(String propertyName,
174 PropertyChangeListener listener)
176 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
180 * @param propertyName
182 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
183 * java.beans.PropertyChangeListener)
185 public void removeJalviewPropertyChangeListener(String propertyName,
186 PropertyChangeListener listener)
188 changeSupport.removeJalviewPropertyChangeListener(propertyName,
192 /** Singleton Desktop instance */
193 public static Desktop instance;
195 public static MyDesktopPane desktop;
197 static int openFrameCount = 0;
199 static final int xOffset = 30;
201 static final int yOffset = 30;
203 public static jalview.ws.jws1.Discoverer discoverer;
205 public static Object[] jalviewClipboard;
207 public static boolean internalCopy = false;
209 static int fileLoadingCount = 0;
211 class MyDesktopManager implements DesktopManager
214 private DesktopManager delegate;
216 public MyDesktopManager(DesktopManager delegate)
218 this.delegate = delegate;
222 public void activateFrame(JInternalFrame f)
226 delegate.activateFrame(f);
227 } catch (NullPointerException npe)
229 Point p = getMousePosition();
230 instance.showPasteMenu(p.x, p.y);
235 public void beginDraggingFrame(JComponent f)
237 delegate.beginDraggingFrame(f);
241 public void beginResizingFrame(JComponent f, int direction)
243 delegate.beginResizingFrame(f, direction);
247 public void closeFrame(JInternalFrame f)
249 delegate.closeFrame(f);
253 public void deactivateFrame(JInternalFrame f)
255 delegate.deactivateFrame(f);
259 public void deiconifyFrame(JInternalFrame f)
261 delegate.deiconifyFrame(f);
265 public void dragFrame(JComponent f, int newX, int newY)
271 delegate.dragFrame(f, newX, newY);
275 public void endDraggingFrame(JComponent f)
277 delegate.endDraggingFrame(f);
282 public void endResizingFrame(JComponent f)
284 delegate.endResizingFrame(f);
289 public void iconifyFrame(JInternalFrame f)
291 delegate.iconifyFrame(f);
295 public void maximizeFrame(JInternalFrame f)
297 delegate.maximizeFrame(f);
301 public void minimizeFrame(JInternalFrame f)
303 delegate.minimizeFrame(f);
307 public void openFrame(JInternalFrame f)
309 delegate.openFrame(f);
313 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
320 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
324 public void setBoundsForFrame(JComponent f, int newX, int newY,
325 int newWidth, int newHeight)
327 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
330 // All other methods, simply delegate
335 * Creates a new Desktop object.
340 * A note to implementors. It is ESSENTIAL that any activities that might
341 * block are spawned off as threads rather than waited for during this
346 doConfigureStructurePrefs();
347 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
349 if (!Platform.isAMac())
351 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
355 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
361 APQHandlers.setAPQHandlers(this);
362 } catch (Exception e)
364 System.out.println("Cannot set APQHandlers");
365 // e.printStackTrace();
366 } catch (Throwable t)
368 System.out.println("Cannot set APQHandlers");
369 // t.printStackTrace();
373 addWindowListener(new WindowAdapter()
377 public void windowClosing(WindowEvent ev)
383 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
386 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
388 desktop = new MyDesktopPane(selmemusage);
389 showMemusage.setSelected(selmemusage);
390 desktop.setBackground(Color.white);
392 getContentPane().setLayout(new BorderLayout());
393 // alternate config - have scrollbars - see notes in JAL-153
394 // JScrollPane sp = new JScrollPane();
395 // sp.getViewport().setView(desktop);
396 // getContentPane().add(sp, BorderLayout.CENTER);
397 getContentPane().add(desktop, BorderLayout.CENTER);
398 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
400 // This line prevents Windows Look&Feel resizing all new windows to maximum
401 // if previous window was maximised
402 desktop.setDesktopManager(new MyDesktopManager(
403 (Platform.isWindows() ? new DefaultDesktopManager()
405 ? new AquaInternalFrameManager(
406 desktop.getDesktopManager())
407 : desktop.getDesktopManager())));
409 Rectangle dims = getLastKnownDimensions("");
416 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
417 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
420 jconsole = new Console(this, showjconsole);
421 // add essential build information
422 jconsole.setHeader(jalview.bin.Cache.getVersionDetailsForConsole());
424 showConsole(showjconsole);
426 showNews.setVisible(false);
428 experimentalFeatures.setSelected(showExperimental());
430 getIdentifiersOrgData();
434 this.addWindowListener(new WindowAdapter()
437 public void windowClosing(WindowEvent evt)
444 this.addMouseListener(ma = new MouseAdapter()
447 public void mousePressed(MouseEvent evt)
449 if (evt.isPopupTrigger()) // Mac
451 showPasteMenu(evt.getX(), evt.getY());
456 public void mouseReleased(MouseEvent evt)
458 if (evt.isPopupTrigger()) // Windows
460 showPasteMenu(evt.getX(), evt.getY());
464 desktop.addMouseListener(ma);
466 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
467 // Spawn a thread that shows the splashscreen
468 SwingUtilities.invokeLater(new Runnable()
477 // Thread off a new instance of the file chooser - this reduces the time it
478 // takes to open it later on.
479 new Thread(new Runnable()
484 Cache.log.debug("Filechooser init thread started.");
485 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
486 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
488 Cache.log.debug("Filechooser init thread finished.");
491 // Add the service change listener
492 changeSupport.addJalviewPropertyChangeListener("services",
493 new PropertyChangeListener()
497 public void propertyChange(PropertyChangeEvent evt)
499 Cache.log.debug("Firing service changed event for "
500 + evt.getNewValue());
501 JalviewServicesChanged(evt);
508 * Answers true if user preferences to enable experimental features is True
513 public boolean showExperimental()
515 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
516 Boolean.FALSE.toString());
517 return Boolean.valueOf(experimental).booleanValue();
520 public void doConfigureStructurePrefs()
522 // configure services
523 StructureSelectionManager ssm = StructureSelectionManager
524 .getStructureSelectionManager(this);
525 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
527 ssm.setAddTempFacAnnot(jalview.bin.Cache
528 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
529 ssm.setProcessSecondaryStructure(jalview.bin.Cache
530 .getDefault(Preferences.STRUCT_FROM_PDB, true));
531 ssm.setSecStructServices(
532 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
536 ssm.setAddTempFacAnnot(false);
537 ssm.setProcessSecondaryStructure(false);
538 ssm.setSecStructServices(false);
542 public void checkForNews()
544 final Desktop me = this;
545 // Thread off the news reader, in case there are connection problems.
546 new Thread(new Runnable()
551 Cache.log.debug("Starting news thread.");
553 jvnews = new BlogReader(me);
554 showNews.setVisible(true);
555 Cache.log.debug("Completed news thread.");
560 public void getIdentifiersOrgData()
562 // Thread off the identifiers fetcher
563 new Thread(new Runnable()
568 Cache.log.debug("Downloading data from identifiers.org");
569 UrlDownloadClient client = new UrlDownloadClient();
572 client.download(IdOrgSettings.getUrl(),
573 IdOrgSettings.getDownloadLocation());
574 } catch (IOException e)
576 Cache.log.debug("Exception downloading identifiers.org data"
585 protected void showNews_actionPerformed(ActionEvent e)
587 showNews(showNews.isSelected());
590 void showNews(boolean visible)
593 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
594 showNews.setSelected(visible);
595 if (visible && !jvnews.isVisible())
597 new Thread(new Runnable()
602 long now = System.currentTimeMillis();
603 Desktop.instance.setProgressBar(
604 MessageManager.getString("status.refreshing_news"),
606 jvnews.refreshNews();
607 Desktop.instance.setProgressBar(null, now);
616 * recover the last known dimensions for a jalview window
619 * - empty string is desktop, all other windows have unique prefix
620 * @return null or last known dimensions scaled to current geometry (if last
621 * window geom was known)
623 Rectangle getLastKnownDimensions(String windowName)
625 // TODO: lock aspect ratio for scaling desktop Bug #0058199
626 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
627 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
628 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
629 String width = jalview.bin.Cache
630 .getProperty(windowName + "SCREEN_WIDTH");
631 String height = jalview.bin.Cache
632 .getProperty(windowName + "SCREEN_HEIGHT");
633 if ((x != null) && (y != null) && (width != null) && (height != null))
635 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
636 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
637 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
639 // attempt #1 - try to cope with change in screen geometry - this
640 // version doesn't preserve original jv aspect ratio.
641 // take ratio of current screen size vs original screen size.
642 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
643 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
644 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
645 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
646 // rescale the bounds depending upon the current screen geometry.
647 ix = (int) (ix * sw);
648 iw = (int) (iw * sw);
649 iy = (int) (iy * sh);
650 ih = (int) (ih * sh);
651 while (ix >= screenSize.width)
653 jalview.bin.Cache.log.debug(
654 "Window geometry location recall error: shifting horizontal to within screenbounds.");
655 ix -= screenSize.width;
657 while (iy >= screenSize.height)
659 jalview.bin.Cache.log.debug(
660 "Window geometry location recall error: shifting vertical to within screenbounds.");
661 iy -= screenSize.height;
663 jalview.bin.Cache.log.debug(
664 "Got last known dimensions for " + windowName + ": x:" + ix
665 + " y:" + iy + " width:" + iw + " height:" + ih);
667 // return dimensions for new instance
668 return new Rectangle(ix, iy, iw, ih);
673 void showPasteMenu(int x, int y)
675 JPopupMenu popup = new JPopupMenu();
676 JMenuItem item = new JMenuItem(
677 MessageManager.getString("label.paste_new_window"));
678 item.addActionListener(new ActionListener()
681 public void actionPerformed(ActionEvent evt)
688 popup.show(this, x, y);
695 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
696 Transferable contents = c.getContents(this);
698 if (contents != null)
700 String file = (String) contents
701 .getTransferData(DataFlavor.stringFlavor);
703 FileFormatI format = new IdentifyFile().identify(file,
704 DataSourceType.PASTE);
706 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
709 } catch (Exception ex)
712 "Unable to paste alignment from system clipboard:\n" + ex);
717 * Adds and opens the given frame to the desktop
728 public static synchronized void addInternalFrame(
729 final JInternalFrame frame, String title, int w, int h)
731 addInternalFrame(frame, title, true, w, h, true, false);
735 * Add an internal frame to the Jalview desktop
742 * When true, display frame immediately, otherwise, caller must call
743 * setVisible themselves.
749 public static synchronized void addInternalFrame(
750 final JInternalFrame frame, String title, boolean makeVisible,
753 addInternalFrame(frame, title, makeVisible, w, h, true, false);
757 * Add an internal frame to the Jalview desktop and make it visible
770 public static synchronized void addInternalFrame(
771 final JInternalFrame frame, String title, int w, int h,
774 addInternalFrame(frame, title, true, w, h, resizable, false);
778 * Add an internal frame to the Jalview desktop
785 * When true, display frame immediately, otherwise, caller must call
786 * setVisible themselves.
793 * @param ignoreMinSize
794 * Do not set the default minimum size for frame
796 public static synchronized void addInternalFrame(
797 final JInternalFrame frame, String title, boolean makeVisible,
798 int w, int h, boolean resizable, boolean ignoreMinSize)
801 // TODO: allow callers to determine X and Y position of frame (eg. via
803 // TODO: consider fixing method to update entries in the window submenu with
804 // the current window title
806 frame.setTitle(title);
807 if (frame.getWidth() < 1 || frame.getHeight() < 1)
811 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
812 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
813 // IF JALVIEW IS RUNNING HEADLESS
814 // ///////////////////////////////////////////////
815 if (instance == null || (System.getProperty("java.awt.headless") != null
816 && System.getProperty("java.awt.headless").equals("true")))
825 frame.setMinimumSize(
826 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
828 // Set default dimension for Alignment Frame window.
829 // The Alignment Frame window could be added from a number of places,
831 // I did this here in order not to miss out on any Alignment frame.
832 if (frame instanceof AlignFrame)
834 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
835 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
839 frame.setVisible(makeVisible);
840 frame.setClosable(true);
841 frame.setResizable(resizable);
842 frame.setMaximizable(resizable);
843 frame.setIconifiable(resizable);
844 frame.setOpaque(false);
846 if (frame.getX() < 1 && frame.getY() < 1)
848 frame.setLocation(xOffset * openFrameCount,
849 yOffset * ((openFrameCount - 1) % 10) + yOffset);
853 * add an entry for the new frame in the Window menu
854 * (and remove it when the frame is closed)
856 final JMenuItem menuItem = new JMenuItem(title);
857 frame.addInternalFrameListener(new InternalFrameAdapter()
860 public void internalFrameActivated(InternalFrameEvent evt)
862 JInternalFrame itf = desktop.getSelectedFrame();
865 if (itf instanceof AlignFrame)
867 Jalview.setCurrentAlignFrame((AlignFrame) itf);
874 public void internalFrameClosed(InternalFrameEvent evt)
876 PaintRefresher.RemoveComponent(frame);
879 * defensive check to prevent frames being
880 * added half off the window
882 if (openFrameCount > 0)
888 * ensure no reference to alignFrame retained by menu item listener
890 if (menuItem.getActionListeners().length > 0)
892 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
894 windowMenu.remove(menuItem);
898 menuItem.addActionListener(new ActionListener()
901 public void actionPerformed(ActionEvent e)
905 frame.setSelected(true);
906 frame.setIcon(false);
907 } catch (java.beans.PropertyVetoException ex)
914 setKeyBindings(frame);
918 windowMenu.add(menuItem);
923 frame.setSelected(true);
924 frame.requestFocus();
925 } catch (java.beans.PropertyVetoException ve)
927 } catch (java.lang.ClassCastException cex)
930 "Squashed a possible GUI implementation error. If you can recreate this, please look at https://issues.jalview.org/browse/JAL-869",
936 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
941 private static void setKeyBindings(JInternalFrame frame)
943 @SuppressWarnings("serial")
944 final Action closeAction = new AbstractAction()
947 public void actionPerformed(ActionEvent e)
954 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
956 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
957 InputEvent.CTRL_DOWN_MASK);
958 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
959 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
961 InputMap inputMap = frame
962 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
963 String ctrlW = ctrlWKey.toString();
964 inputMap.put(ctrlWKey, ctrlW);
965 inputMap.put(cmdWKey, ctrlW);
967 ActionMap actionMap = frame.getActionMap();
968 actionMap.put(ctrlW, closeAction);
972 public void lostOwnership(Clipboard clipboard, Transferable contents)
976 Desktop.jalviewClipboard = null;
979 internalCopy = false;
983 public void dragEnter(DropTargetDragEvent evt)
988 public void dragExit(DropTargetEvent evt)
993 public void dragOver(DropTargetDragEvent evt)
998 public void dropActionChanged(DropTargetDragEvent evt)
1009 public void drop(DropTargetDropEvent evt)
1011 boolean success = true;
1012 // JAL-1552 - acceptDrop required before getTransferable call for
1013 // Java's Transferable for native dnd
1014 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1015 Transferable t = evt.getTransferable();
1016 List<String> files = new ArrayList<>();
1017 List<DataSourceType> protocols = new ArrayList<>();
1021 Desktop.transferFromDropTarget(files, protocols, evt, t);
1022 } catch (Exception e)
1024 e.printStackTrace();
1032 for (int i = 0; i < files.size(); i++)
1034 String file = files.get(i).toString();
1035 DataSourceType protocol = (protocols == null)
1036 ? DataSourceType.FILE
1038 FileFormatI format = null;
1040 if (file.endsWith(".jar"))
1042 format = FileFormat.Jalview;
1047 format = new IdentifyFile().identify(file, protocol);
1050 new FileLoader().LoadFile(file, protocol, format);
1053 } catch (Exception ex)
1058 evt.dropComplete(success); // need this to ensure input focus is properly
1059 // transfered to any new windows created
1069 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1071 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1072 JalviewFileChooser chooser = JalviewFileChooser
1073 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, BackupFiles.getEnabled());
1075 chooser.setFileView(new JalviewFileView());
1076 chooser.setDialogTitle(
1077 MessageManager.getString("label.open_local_file"));
1078 chooser.setToolTipText(MessageManager.getString("action.open"));
1080 int value = chooser.showOpenDialog(this);
1082 if (value == JalviewFileChooser.APPROVE_OPTION)
1084 String choice = chooser.getSelectedFile().getPath();
1085 Cache.setProperty("LAST_DIRECTORY",
1086 chooser.getSelectedFile().getParent());
1088 FileFormatI format = chooser.getSelectedFormat();
1091 * Call IdentifyFile to verify the file contains what its extension implies.
1092 * Skip this step for dynamically added file formats, because
1093 * IdentifyFile does not know how to recognise them.
1095 if (FileFormats.getInstance().isIdentifiable(format))
1099 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1100 } catch (FileFormatException e)
1102 // format = null; //??
1106 if (viewport != null)
1108 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1113 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1125 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1127 // This construct allows us to have a wider textfield
1129 JLabel label = new JLabel(
1130 MessageManager.getString("label.input_file_url"));
1131 final JComboBox history = new JComboBox();
1133 JPanel panel = new JPanel(new GridLayout(2, 1));
1136 history.setPreferredSize(new Dimension(400, 20));
1137 history.setEditable(true);
1138 history.addItem("https://www.");
1140 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1144 if (historyItems != null)
1146 st = new StringTokenizer(historyItems, "\t");
1148 while (st.hasMoreTokens())
1150 history.addItem(st.nextElement());
1154 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1155 MessageManager.getString("label.input_alignment_from_url"),
1156 JvOptionPane.OK_CANCEL_OPTION);
1158 if (reply != JvOptionPane.OK_OPTION)
1163 String url = history.getSelectedItem().toString();
1165 if (url.toLowerCase().endsWith(".jar"))
1167 if (viewport != null)
1169 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1170 FileFormat.Jalview);
1174 new FileLoader().LoadFile(url, DataSourceType.URL,
1175 FileFormat.Jalview);
1180 FileFormatI format = null;
1183 format = new IdentifyFile().identify(url, DataSourceType.URL);
1184 } catch (FileFormatException e)
1186 // TODO revise error handling, distinguish between
1187 // URL not found and response not valid
1192 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1193 MessageManager.formatMessage("label.couldnt_locate",
1196 MessageManager.getString("label.url_not_found"),
1197 JvOptionPane.WARNING_MESSAGE);
1202 if (viewport != null)
1204 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1209 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1215 * Opens the CutAndPaste window for the user to paste an alignment in to
1218 * - if not null, the pasted alignment is added to the current
1219 * alignment; if null, to a new alignment window
1222 public void inputTextboxMenuItem_actionPerformed(
1223 AlignmentViewPanel viewPanel)
1225 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1226 cap.setForInput(viewPanel);
1227 Desktop.addInternalFrame(cap,
1228 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1238 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1239 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1241 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1242 screen.height + "");
1243 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1244 getWidth(), getHeight()));
1246 if (jconsole != null)
1248 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1249 jconsole.stopConsole();
1253 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1256 if (dialogExecutor != null)
1258 dialogExecutor.shutdownNow();
1260 closeAll_actionPerformed(null);
1262 if (groovyConsole != null)
1264 // suppress a possible repeat prompt to save script
1265 groovyConsole.setDirty(false);
1266 groovyConsole.exit();
1271 private void storeLastKnownDimensions(String string, Rectangle jc)
1273 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1274 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1275 + " height:" + jc.height);
1277 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1278 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1279 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1280 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1290 public void aboutMenuItem_actionPerformed(ActionEvent e)
1292 // StringBuffer message = getAboutMessage(false);
1293 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1295 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1296 new Thread(new Runnable()
1301 new SplashScreen(true);
1306 public StringBuffer getAboutMessage(boolean shortv)
1308 StringBuffer message = new StringBuffer();
1309 message.append("<html>");
1312 message.append("<h1><strong>Version: "
1313 + jalview.bin.Cache.getProperty("VERSION")
1314 + "</strong></h1>");
1315 message.append("<strong>Built: <em>"
1316 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1317 + "</em> from " + jalview.bin.Cache.getBuildDetailsForSplash()
1324 message.append("<strong>Version "
1325 + jalview.bin.Cache.getProperty("VERSION")
1326 + "; last updated: "
1327 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1330 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1331 .equals("Checking"))
1333 // JBP removed this message for 2.11: May be reinstated in future version
1334 // message.append("<br>...Checking latest version...</br>");
1336 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1337 .equals(jalview.bin.Cache.getProperty("VERSION")))
1339 boolean red = false;
1340 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1341 .indexOf("automated build") == -1)
1344 // Displayed when code version and jnlp version do not match and code
1345 // version is not a development build
1346 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1349 message.append("<br>!! Version "
1350 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1352 + " is available for download from "
1353 + jalview.bin.Cache.getDefault("www.jalview.org",
1354 "https://www.jalview.org")
1358 message.append("</div>");
1361 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1363 "The Jalview Authors (See AUTHORS file for current list)")
1364 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1365 + "<br><br>For help, see the FAQ at <a href=\"https://www.jalview.org/faq\">www.jalview.org/faq</a> and/or join the jalview-discuss@jalview.org mailing list"
1366 + "<br><br>If you use Jalview, please cite:"
1367 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1368 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1369 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1381 public void documentationMenuItem_actionPerformed(ActionEvent e)
1385 Help.showHelpWindow();
1386 } catch (Exception ex)
1392 public void closeAll_actionPerformed(ActionEvent e)
1394 // TODO show a progress bar while closing?
1395 JInternalFrame[] frames = desktop.getAllFrames();
1396 for (int i = 0; i < frames.length; i++)
1400 frames[i].setClosed(true);
1401 } catch (java.beans.PropertyVetoException ex)
1405 Jalview.setCurrentAlignFrame(null);
1406 System.out.println("ALL CLOSED");
1409 * reset state of singleton objects as appropriate (clear down session state
1410 * when all windows are closed)
1412 StructureSelectionManager ssm = StructureSelectionManager
1413 .getStructureSelectionManager(this);
1421 public void raiseRelated_actionPerformed(ActionEvent e)
1423 reorderAssociatedWindows(false, false);
1427 public void minimizeAssociated_actionPerformed(ActionEvent e)
1429 reorderAssociatedWindows(true, false);
1432 void closeAssociatedWindows()
1434 reorderAssociatedWindows(false, true);
1440 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1444 protected void garbageCollect_actionPerformed(ActionEvent e)
1446 // We simply collect the garbage
1447 jalview.bin.Cache.log.debug("Collecting garbage...");
1449 jalview.bin.Cache.log.debug("Finished garbage collection.");
1456 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1460 protected void showMemusage_actionPerformed(ActionEvent e)
1462 desktop.showMemoryUsage(showMemusage.isSelected());
1469 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1473 protected void showConsole_actionPerformed(ActionEvent e)
1475 showConsole(showConsole.isSelected());
1478 Console jconsole = null;
1481 * control whether the java console is visible or not
1485 void showConsole(boolean selected)
1487 showConsole.setSelected(selected);
1488 // TODO: decide if we should update properties file
1489 Cache.setProperty("SHOW_JAVA_CONSOLE",
1490 Boolean.valueOf(selected).toString());
1491 jconsole.setVisible(selected);
1494 void reorderAssociatedWindows(boolean minimize, boolean close)
1496 JInternalFrame[] frames = desktop.getAllFrames();
1497 if (frames == null || frames.length < 1)
1502 AlignmentViewport source = null, target = null;
1503 if (frames[0] instanceof AlignFrame)
1505 source = ((AlignFrame) frames[0]).getCurrentView();
1507 else if (frames[0] instanceof TreePanel)
1509 source = ((TreePanel) frames[0]).getViewPort();
1511 else if (frames[0] instanceof PCAPanel)
1513 source = ((PCAPanel) frames[0]).av;
1515 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1517 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1522 for (int i = 0; i < frames.length; i++)
1525 if (frames[i] == null)
1529 if (frames[i] instanceof AlignFrame)
1531 target = ((AlignFrame) frames[i]).getCurrentView();
1533 else if (frames[i] instanceof TreePanel)
1535 target = ((TreePanel) frames[i]).getViewPort();
1537 else if (frames[i] instanceof PCAPanel)
1539 target = ((PCAPanel) frames[i]).av;
1541 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1543 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1546 if (source == target)
1552 frames[i].setClosed(true);
1556 frames[i].setIcon(minimize);
1559 frames[i].toFront();
1563 } catch (java.beans.PropertyVetoException ex)
1578 protected void preferences_actionPerformed(ActionEvent e)
1584 * Shows a file chooser dialog and writes out the current session as a Jalview
1588 public void saveState_actionPerformed()
1590 saveState_actionPerformed(false);
1593 public void saveState_actionPerformed(boolean saveAs)
1595 java.io.File projectFile = getProjectFile();
1596 // autoSave indicates we already have a file and don't need to ask
1597 boolean autoSave = projectFile != null && !saveAs
1598 && BackupFiles.getEnabled();
1600 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1601 // saveAs="+saveAs+", Backups
1602 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1604 boolean approveSave = false;
1607 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1610 chooser.setFileView(new JalviewFileView());
1611 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1613 int value = chooser.showSaveDialog(this);
1615 if (value == JalviewFileChooser.APPROVE_OPTION)
1617 projectFile = chooser.getSelectedFile();
1618 setProjectFile(projectFile);
1623 if (approveSave || autoSave)
1625 final Desktop me = this;
1626 final java.io.File chosenFile = projectFile;
1627 new Thread(new Runnable()
1632 // TODO: refactor to Jalview desktop session controller action.
1633 setProgressBar(MessageManager.formatMessage(
1634 "label.saving_jalview_project", new Object[]
1635 { chosenFile.getName() }), chosenFile.hashCode());
1636 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1637 chosenFile.getParent());
1638 // TODO catch and handle errors for savestate
1639 // TODO prevent user from messing with the Desktop whilst we're saving
1642 BackupFiles backupfiles = new BackupFiles(chosenFile);
1644 new Jalview2XML().saveState(backupfiles.getTempFile());
1646 backupfiles.setWriteSuccess(true);
1647 backupfiles.rollBackupsAndRenameTempFile();
1648 } catch (OutOfMemoryError oom)
1650 new OOMWarning("Whilst saving current state to "
1651 + chosenFile.getName(), oom);
1652 } catch (Exception ex)
1654 Cache.log.error("Problems whilst trying to save to "
1655 + chosenFile.getName(), ex);
1656 JvOptionPane.showMessageDialog(me,
1657 MessageManager.formatMessage(
1658 "label.error_whilst_saving_current_state_to",
1660 { chosenFile.getName() }),
1661 MessageManager.getString("label.couldnt_save_project"),
1662 JvOptionPane.WARNING_MESSAGE);
1664 setProgressBar(null, chosenFile.hashCode());
1671 public void saveAsState_actionPerformed(ActionEvent e)
1673 saveState_actionPerformed(true);
1676 private void setProjectFile(File choice)
1678 this.projectFile = choice;
1681 public File getProjectFile()
1683 return this.projectFile;
1687 * Shows a file chooser dialog and tries to read in the selected file as a
1691 public void loadState_actionPerformed()
1693 final String[] suffix = new String[] { "jvp", "jar" };
1694 final String[] desc = new String[] { "Jalview Project",
1695 "Jalview Project (old)" };
1696 JalviewFileChooser chooser = new JalviewFileChooser(
1697 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1698 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1700 chooser.setFileView(new JalviewFileView());
1701 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1703 int value = chooser.showOpenDialog(this);
1705 if (value == JalviewFileChooser.APPROVE_OPTION)
1707 final File selectedFile = chooser.getSelectedFile();
1708 setProjectFile(selectedFile);
1709 final String choice = selectedFile.getAbsolutePath();
1710 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1711 new Thread(new Runnable()
1716 setProgressBar(MessageManager.formatMessage(
1717 "label.loading_jalview_project", new Object[]
1718 { choice }), choice.hashCode());
1721 new Jalview2XML().loadJalviewAlign(choice);
1722 } catch (OutOfMemoryError oom)
1724 new OOMWarning("Whilst loading project from " + choice, oom);
1725 } catch (Exception ex)
1728 "Problems whilst loading project from " + choice, ex);
1729 JvOptionPane.showMessageDialog(Desktop.desktop,
1730 MessageManager.formatMessage(
1731 "label.error_whilst_loading_project_from",
1734 MessageManager.getString("label.couldnt_load_project"),
1735 JvOptionPane.WARNING_MESSAGE);
1737 setProgressBar(null, choice.hashCode());
1744 public void inputSequence_actionPerformed(ActionEvent e)
1746 new SequenceFetcher(this);
1749 JPanel progressPanel;
1751 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1753 public void startLoading(final String fileName)
1755 if (fileLoadingCount == 0)
1757 fileLoadingPanels.add(addProgressPanel(MessageManager
1758 .formatMessage("label.loading_file", new Object[]
1764 private JPanel addProgressPanel(String string)
1766 if (progressPanel == null)
1768 progressPanel = new JPanel(new GridLayout(1, 1));
1769 totalProgressCount = 0;
1770 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1772 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1773 JProgressBar progressBar = new JProgressBar();
1774 progressBar.setIndeterminate(true);
1776 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1778 thisprogress.add(progressBar, BorderLayout.CENTER);
1779 progressPanel.add(thisprogress);
1780 ((GridLayout) progressPanel.getLayout()).setRows(
1781 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1782 ++totalProgressCount;
1783 instance.validate();
1784 return thisprogress;
1787 int totalProgressCount = 0;
1789 private void removeProgressPanel(JPanel progbar)
1791 if (progressPanel != null)
1793 synchronized (progressPanel)
1795 progressPanel.remove(progbar);
1796 GridLayout gl = (GridLayout) progressPanel.getLayout();
1797 gl.setRows(gl.getRows() - 1);
1798 if (--totalProgressCount < 1)
1800 this.getContentPane().remove(progressPanel);
1801 progressPanel = null;
1808 public void stopLoading()
1811 if (fileLoadingCount < 1)
1813 while (fileLoadingPanels.size() > 0)
1815 removeProgressPanel(fileLoadingPanels.remove(0));
1817 fileLoadingPanels.clear();
1818 fileLoadingCount = 0;
1823 public static int getViewCount(String alignmentId)
1825 AlignmentViewport[] aps = getViewports(alignmentId);
1826 return (aps == null) ? 0 : aps.length;
1831 * @param alignmentId
1832 * - if null, all sets are returned
1833 * @return all AlignmentPanels concerning the alignmentId sequence set
1835 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1837 if (Desktop.desktop == null)
1839 // no frames created and in headless mode
1840 // TODO: verify that frames are recoverable when in headless mode
1843 List<AlignmentPanel> aps = new ArrayList<>();
1844 AlignFrame[] frames = getAlignFrames();
1849 for (AlignFrame af : frames)
1851 for (AlignmentPanel ap : af.alignPanels)
1853 if (alignmentId == null
1854 || alignmentId.equals(ap.av.getSequenceSetId()))
1860 if (aps.size() == 0)
1864 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1869 * get all the viewports on an alignment.
1871 * @param sequenceSetId
1872 * unique alignment id (may be null - all viewports returned in that
1874 * @return all viewports on the alignment bound to sequenceSetId
1876 public static AlignmentViewport[] getViewports(String sequenceSetId)
1878 List<AlignmentViewport> viewp = new ArrayList<>();
1879 if (desktop != null)
1881 AlignFrame[] frames = Desktop.getAlignFrames();
1883 for (AlignFrame afr : frames)
1885 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1886 .equals(sequenceSetId))
1888 if (afr.alignPanels != null)
1890 for (AlignmentPanel ap : afr.alignPanels)
1892 if (sequenceSetId == null
1893 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1901 viewp.add(afr.getViewport());
1905 if (viewp.size() > 0)
1907 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1914 * Explode the views in the given frame into separate AlignFrame
1918 public static void explodeViews(AlignFrame af)
1920 int size = af.alignPanels.size();
1926 // FIXME: ideally should use UI interface API
1927 FeatureSettings viewFeatureSettings = (af.featureSettings != null
1928 && af.featureSettings.isOpen())
1929 ? af.featureSettings
1931 Rectangle fsBounds = af.getFeatureSettingsGeometry();
1932 for (int i = 0; i < size; i++)
1934 AlignmentPanel ap = af.alignPanels.get(i);
1936 AlignFrame newaf = new AlignFrame(ap);
1938 // transfer reference for existing feature settings to new alignFrame
1939 if (ap == af.alignPanel)
1941 if (viewFeatureSettings != null && viewFeatureSettings.fr.ap == ap)
1943 newaf.featureSettings = viewFeatureSettings;
1945 newaf.setFeatureSettingsGeometry(fsBounds);
1949 * Restore the view's last exploded frame geometry if known. Multiple
1950 * views from one exploded frame share and restore the same (frame)
1951 * position and size.
1953 Rectangle geometry = ap.av.getExplodedGeometry();
1954 if (geometry != null)
1956 newaf.setBounds(geometry);
1959 ap.av.setGatherViewsHere(false);
1961 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1962 AlignFrame.DEFAULT_HEIGHT);
1963 // and materialise a new feature settings dialog instance for the new alignframe
1964 // (closes the old as if 'OK' was pressed)
1965 if (ap == af.alignPanel && newaf.featureSettings != null
1966 && newaf.featureSettings.isOpen()
1967 && af.alignPanel.getAlignViewport().isShowSequenceFeatures())
1969 newaf.showFeatureSettingsUI();
1973 af.featureSettings = null;
1974 af.alignPanels.clear();
1975 af.closeMenuItem_actionPerformed(true);
1980 * Gather expanded views (separate AlignFrame's) with the same sequence set
1981 * identifier back in to this frame as additional views, and close the
1982 * expanded views. Note the expanded frames may themselves have multiple
1983 * views. We take the lot.
1987 public void gatherViews(AlignFrame source)
1989 source.viewport.setGatherViewsHere(true);
1990 source.viewport.setExplodedGeometry(source.getBounds());
1991 JInternalFrame[] frames = desktop.getAllFrames();
1992 String viewId = source.viewport.getSequenceSetId();
1993 for (int t = 0; t < frames.length; t++)
1995 if (frames[t] instanceof AlignFrame && frames[t] != source)
1997 AlignFrame af = (AlignFrame) frames[t];
1998 boolean gatherThis = false;
1999 for (int a = 0; a < af.alignPanels.size(); a++)
2001 AlignmentPanel ap = af.alignPanels.get(a);
2002 if (viewId.equals(ap.av.getSequenceSetId()))
2005 ap.av.setGatherViewsHere(false);
2006 ap.av.setExplodedGeometry(af.getBounds());
2007 source.addAlignmentPanel(ap, false);
2013 if (af.featureSettings != null && af.featureSettings.isOpen())
2015 if (source.featureSettings == null)
2017 // preserve the feature settings geometry for this frame
2018 source.featureSettings = af.featureSettings;
2019 source.setFeatureSettingsGeometry(
2020 af.getFeatureSettingsGeometry());
2024 // close it and forget
2025 af.featureSettings.close();
2028 af.alignPanels.clear();
2029 af.closeMenuItem_actionPerformed(true);
2033 // refresh the feature setting UI for the source frame if it exists
2034 if (source.featureSettings != null
2035 && source.featureSettings.isOpen())
2037 source.showFeatureSettingsUI();
2042 public JInternalFrame[] getAllFrames()
2044 return desktop.getAllFrames();
2048 * Checks the given url to see if it gives a response indicating that the user
2049 * should be informed of a new questionnaire.
2053 public void checkForQuestionnaire(String url)
2055 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2056 // javax.swing.SwingUtilities.invokeLater(jvq);
2057 new Thread(jvq).start();
2060 public void checkURLLinks()
2062 // Thread off the URL link checker
2063 addDialogThread(new Runnable()
2068 if (Cache.getDefault("CHECKURLLINKS", true))
2070 // check what the actual links are - if it's just the default don't
2071 // bother with the warning
2072 List<String> links = Preferences.sequenceUrlLinks
2075 // only need to check links if there is one with a
2076 // SEQUENCE_ID which is not the default EMBL_EBI link
2077 ListIterator<String> li = links.listIterator();
2078 boolean check = false;
2079 List<JLabel> urls = new ArrayList<>();
2080 while (li.hasNext())
2082 String link = li.next();
2083 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2084 && !UrlConstants.isDefaultString(link))
2087 int barPos = link.indexOf("|");
2088 String urlMsg = barPos == -1 ? link
2089 : link.substring(0, barPos) + ": "
2090 + link.substring(barPos + 1);
2091 urls.add(new JLabel(urlMsg));
2099 // ask user to check in case URL links use old style tokens
2100 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2101 JPanel msgPanel = new JPanel();
2102 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2103 msgPanel.add(Box.createVerticalGlue());
2104 JLabel msg = new JLabel(MessageManager
2105 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2106 JLabel msg2 = new JLabel(MessageManager
2107 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2109 for (JLabel url : urls)
2115 final JCheckBox jcb = new JCheckBox(
2116 MessageManager.getString("label.do_not_display_again"));
2117 jcb.addActionListener(new ActionListener()
2120 public void actionPerformed(ActionEvent e)
2122 // update Cache settings for "don't show this again"
2123 boolean showWarningAgain = !jcb.isSelected();
2124 Cache.setProperty("CHECKURLLINKS",
2125 Boolean.valueOf(showWarningAgain).toString());
2130 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2132 .getString("label.SEQUENCE_ID_no_longer_used"),
2133 JvOptionPane.WARNING_MESSAGE);
2140 * Proxy class for JDesktopPane which optionally displays the current memory
2141 * usage and highlights the desktop area with a red bar if free memory runs
2146 public class MyDesktopPane extends JDesktopPane implements Runnable
2149 private static final float ONE_MB = 1048576f;
2151 boolean showMemoryUsage = false;
2155 java.text.NumberFormat df;
2157 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2160 public MyDesktopPane(boolean showMemoryUsage)
2162 showMemoryUsage(showMemoryUsage);
2165 public void showMemoryUsage(boolean showMemory)
2167 this.showMemoryUsage = showMemory;
2170 Thread worker = new Thread(this);
2176 public boolean isShowMemoryUsage()
2178 return showMemoryUsage;
2184 df = java.text.NumberFormat.getNumberInstance();
2185 df.setMaximumFractionDigits(2);
2186 runtime = Runtime.getRuntime();
2188 while (showMemoryUsage)
2192 maxMemory = runtime.maxMemory() / ONE_MB;
2193 allocatedMemory = runtime.totalMemory() / ONE_MB;
2194 freeMemory = runtime.freeMemory() / ONE_MB;
2195 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2197 percentUsage = (totalFreeMemory / maxMemory) * 100;
2199 // if (percentUsage < 20)
2201 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2203 // instance.set.setBorder(border1);
2206 // sleep after showing usage
2208 } catch (Exception ex)
2210 ex.printStackTrace();
2216 public void paintComponent(Graphics g)
2218 if (showMemoryUsage && g != null && df != null)
2220 if (percentUsage < 20)
2222 g.setColor(Color.red);
2224 FontMetrics fm = g.getFontMetrics();
2227 g.drawString(MessageManager.formatMessage("label.memory_stats",
2229 { df.format(totalFreeMemory), df.format(maxMemory),
2230 df.format(percentUsage) }),
2231 10, getHeight() - fm.getHeight());
2238 * Accessor method to quickly get all the AlignmentFrames loaded.
2240 * @return an array of AlignFrame, or null if none found
2242 public static AlignFrame[] getAlignFrames()
2244 if (Jalview.isHeadlessMode())
2246 // Desktop.desktop is null in headless mode
2247 return new AlignFrame[] { Jalview.currentAlignFrame };
2250 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2256 List<AlignFrame> avp = new ArrayList<>();
2258 for (int i = frames.length - 1; i > -1; i--)
2260 if (frames[i] instanceof AlignFrame)
2262 avp.add((AlignFrame) frames[i]);
2264 else if (frames[i] instanceof SplitFrame)
2267 * Also check for a split frame containing an AlignFrame
2269 GSplitFrame sf = (GSplitFrame) frames[i];
2270 if (sf.getTopFrame() instanceof AlignFrame)
2272 avp.add((AlignFrame) sf.getTopFrame());
2274 if (sf.getBottomFrame() instanceof AlignFrame)
2276 avp.add((AlignFrame) sf.getBottomFrame());
2280 if (avp.size() == 0)
2284 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2289 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2293 public GStructureViewer[] getJmols()
2295 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2301 List<GStructureViewer> avp = new ArrayList<>();
2303 for (int i = frames.length - 1; i > -1; i--)
2305 if (frames[i] instanceof AppJmol)
2307 GStructureViewer af = (GStructureViewer) frames[i];
2311 if (avp.size() == 0)
2315 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2320 * Add Groovy Support to Jalview
2323 public void groovyShell_actionPerformed()
2327 openGroovyConsole();
2328 } catch (Exception ex)
2330 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2331 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2333 MessageManager.getString("label.couldnt_create_groovy_shell"),
2334 MessageManager.getString("label.groovy_support_failed"),
2335 JvOptionPane.ERROR_MESSAGE);
2340 * Open the Groovy console
2342 void openGroovyConsole()
2344 if (groovyConsole == null)
2346 groovyConsole = new groovy.ui.Console();
2347 groovyConsole.setVariable("Jalview", this);
2348 groovyConsole.run();
2351 * We allow only one console at a time, so that AlignFrame menu option
2352 * 'Calculate | Run Groovy script' is unambiguous.
2353 * Disable 'Groovy Console', and enable 'Run script', when the console is
2354 * opened, and the reverse when it is closed
2356 Window window = (Window) groovyConsole.getFrame();
2357 window.addWindowListener(new WindowAdapter()
2360 public void windowClosed(WindowEvent e)
2363 * rebind CMD-Q from Groovy Console to Jalview Quit
2366 enableExecuteGroovy(false);
2372 * show Groovy console window (after close and reopen)
2374 ((Window) groovyConsole.getFrame()).setVisible(true);
2377 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2378 * and disable opening a second console
2380 enableExecuteGroovy(true);
2384 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2385 * binding when opened
2387 protected void addQuitHandler()
2389 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2390 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2391 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2393 getRootPane().getActionMap().put("Quit", new AbstractAction()
2396 public void actionPerformed(ActionEvent e)
2404 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2407 * true if Groovy console is open
2409 public void enableExecuteGroovy(boolean enabled)
2412 * disable opening a second Groovy console
2413 * (or re-enable when the console is closed)
2415 groovyShell.setEnabled(!enabled);
2417 AlignFrame[] alignFrames = getAlignFrames();
2418 if (alignFrames != null)
2420 for (AlignFrame af : alignFrames)
2422 af.setGroovyEnabled(enabled);
2428 * Progress bars managed by the IProgressIndicator method.
2430 private Hashtable<Long, JPanel> progressBars;
2432 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2437 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2440 public void setProgressBar(String message, long id)
2442 if (progressBars == null)
2444 progressBars = new Hashtable<>();
2445 progressBarHandlers = new Hashtable<>();
2448 if (progressBars.get(Long.valueOf(id)) != null)
2450 JPanel panel = progressBars.remove(Long.valueOf(id));
2451 if (progressBarHandlers.contains(Long.valueOf(id)))
2453 progressBarHandlers.remove(Long.valueOf(id));
2455 removeProgressPanel(panel);
2459 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2466 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2467 * jalview.gui.IProgressIndicatorHandler)
2470 public void registerHandler(final long id,
2471 final IProgressIndicatorHandler handler)
2473 if (progressBarHandlers == null
2474 || !progressBars.containsKey(Long.valueOf(id)))
2476 throw new Error(MessageManager.getString(
2477 "error.call_setprogressbar_before_registering_handler"));
2479 progressBarHandlers.put(Long.valueOf(id), handler);
2480 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2481 if (handler.canCancel())
2483 JButton cancel = new JButton(
2484 MessageManager.getString("action.cancel"));
2485 final IProgressIndicator us = this;
2486 cancel.addActionListener(new ActionListener()
2490 public void actionPerformed(ActionEvent e)
2492 handler.cancelActivity(id);
2493 us.setProgressBar(MessageManager
2494 .formatMessage("label.cancelled_params", new Object[]
2495 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2499 progressPanel.add(cancel, BorderLayout.EAST);
2505 * @return true if any progress bars are still active
2508 public boolean operationInProgress()
2510 if (progressBars != null && progressBars.size() > 0)
2518 * This will return the first AlignFrame holding the given viewport instance.
2519 * It will break if there are more than one AlignFrames viewing a particular
2523 * @return alignFrame for viewport
2525 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2527 if (desktop != null)
2529 AlignmentPanel[] aps = getAlignmentPanels(
2530 viewport.getSequenceSetId());
2531 for (int panel = 0; aps != null && panel < aps.length; panel++)
2533 if (aps[panel] != null && aps[panel].av == viewport)
2535 return aps[panel].alignFrame;
2542 public VamsasApplication getVamsasApplication()
2544 // TODO: JAL-3311 remove remaining code from Jalview relating to VAMSAS
2550 * flag set if jalview GUI is being operated programmatically
2552 private boolean inBatchMode = false;
2555 * check if jalview GUI is being operated programmatically
2557 * @return inBatchMode
2559 public boolean isInBatchMode()
2565 * set flag if jalview GUI is being operated programmatically
2567 * @param inBatchMode
2569 public void setInBatchMode(boolean inBatchMode)
2571 this.inBatchMode = inBatchMode;
2575 * start service discovery and wait till it is done
2577 public void startServiceDiscovery()
2579 startServiceDiscovery(false);
2583 * start service discovery threads - blocking or non-blocking
2587 public void startServiceDiscovery(boolean blocking)
2589 startServiceDiscovery(blocking,false);
2593 * start service discovery threads
2596 * - false means call returns immediately
2597 * @param ignore_SHOW_JWS2_SERVICES_preference
2598 * - when true JABA services are discovered regardless of user's JWS2
2599 * discovery preference setting
2601 public void startServiceDiscovery(boolean blocking,
2602 boolean ignore_SHOW_JWS2_SERVICES_preference)
2604 boolean alive = true;
2605 Thread t0 = null, t1 = null, t2 = null;
2606 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2609 // todo: changesupport handlers need to be transferred
2610 if (discoverer == null)
2612 discoverer = new jalview.ws.jws1.Discoverer();
2613 // register PCS handler for desktop.
2614 discoverer.addPropertyChangeListener(changeSupport);
2616 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2617 // until we phase out completely
2618 (t0 = new Thread(discoverer)).start();
2621 if (ignore_SHOW_JWS2_SERVICES_preference
2622 || Cache.getDefault("SHOW_JWS2_SERVICES", true))
2624 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2625 .startDiscoverer(changeSupport);
2629 // TODO: do rest service discovery
2638 } catch (Exception e)
2641 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2642 || (t3 != null && t3.isAlive())
2643 || (t0 != null && t0.isAlive());
2649 * called to check if the service discovery process completed successfully.
2653 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2655 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2657 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2658 .getErrorMessages();
2661 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2663 if (serviceChangedDialog == null)
2665 // only run if we aren't already displaying one of these.
2666 addDialogThread(serviceChangedDialog = new Runnable()
2673 * JalviewDialog jd =new JalviewDialog() {
2675 * @Override protected void cancelPressed() { // TODO
2676 * Auto-generated method stub
2678 * }@Override protected void okPressed() { // TODO
2679 * Auto-generated method stub
2681 * }@Override protected void raiseClosed() { // TODO
2682 * Auto-generated method stub
2684 * } }; jd.initDialogFrame(new
2685 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2686 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2687 * + " or mis-configured HTTP proxy settings.<br/>" +
2688 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2690 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2691 * ), true, true, "Web Service Configuration Problem", 450,
2694 * jd.waitForInput();
2696 JvOptionPane.showConfirmDialog(Desktop.desktop,
2697 new JLabel("<html><table width=\"450\"><tr><td>"
2698 + ermsg + "</td></tr></table>"
2699 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
2700 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
2701 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
2702 + " Tools->Preferences dialog box to change them.</p></html>"),
2703 "Web Service Configuration Problem",
2704 JvOptionPane.DEFAULT_OPTION,
2705 JvOptionPane.ERROR_MESSAGE);
2706 serviceChangedDialog = null;
2715 "Errors reported by JABA discovery service. Check web services preferences.\n"
2722 private Runnable serviceChangedDialog = null;
2725 * start a thread to open a URL in the configured browser. Pops up a warning
2726 * dialog to the user if there is an exception when calling out to the browser
2731 public static void showUrl(final String url)
2733 showUrl(url, Desktop.instance);
2737 * Like showUrl but allows progress handler to be specified
2741 * (null) or object implementing IProgressIndicator
2743 public static void showUrl(final String url,
2744 final IProgressIndicator progress)
2746 new Thread(new Runnable()
2753 if (progress != null)
2755 progress.setProgressBar(MessageManager
2756 .formatMessage("status.opening_params", new Object[]
2757 { url }), this.hashCode());
2759 jalview.util.BrowserLauncher.openURL(url);
2760 } catch (Exception ex)
2762 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2764 .getString("label.web_browser_not_found_unix"),
2765 MessageManager.getString("label.web_browser_not_found"),
2766 JvOptionPane.WARNING_MESSAGE);
2768 ex.printStackTrace();
2770 if (progress != null)
2772 progress.setProgressBar(null, this.hashCode());
2778 public static WsParamSetManager wsparamManager = null;
2780 public static ParamManager getUserParameterStore()
2782 if (wsparamManager == null)
2784 wsparamManager = new WsParamSetManager();
2786 return wsparamManager;
2790 * static hyperlink handler proxy method for use by Jalview's internal windows
2794 public static void hyperlinkUpdate(HyperlinkEvent e)
2796 if (e.getEventType() == EventType.ACTIVATED)
2801 url = e.getURL().toString();
2802 Desktop.showUrl(url);
2803 } catch (Exception x)
2807 if (Cache.log != null)
2809 Cache.log.error("Couldn't handle string " + url + " as a URL.");
2814 "Couldn't handle string " + url + " as a URL.");
2817 // ignore any exceptions due to dud links.
2824 * single thread that handles display of dialogs to user.
2826 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
2829 * flag indicating if dialogExecutor should try to acquire a permit
2831 private volatile boolean dialogPause = true;
2836 private java.util.concurrent.Semaphore block = new Semaphore(0);
2838 private static groovy.ui.Console groovyConsole;
2841 * add another dialog thread to the queue
2845 public void addDialogThread(final Runnable prompter)
2847 dialogExecutor.submit(new Runnable()
2857 } catch (InterruptedException x)
2862 if (instance == null)
2868 SwingUtilities.invokeAndWait(prompter);
2869 } catch (Exception q)
2871 Cache.log.warn("Unexpected Exception in dialog thread.", q);
2877 public void startDialogQueue()
2879 // set the flag so we don't pause waiting for another permit and semaphore
2880 // the current task to begin
2881 dialogPause = false;
2886 protected void snapShotWindow_actionPerformed(ActionEvent e)
2890 ImageMaker im = new jalview.util.ImageMaker(
2891 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
2892 getHeight(), of = new File("Jalview_snapshot"
2893 + System.currentTimeMillis() + ".eps"),
2894 "View of desktop", null, 0, false);
2897 paintAll(im.getGraphics());
2899 } catch (Exception q)
2901 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
2905 Cache.log.info("Successfully written snapshot to file "
2906 + of.getAbsolutePath());
2910 * Explode the views in the given SplitFrame into separate SplitFrame windows.
2911 * This respects (remembers) any previous 'exploded geometry' i.e. the size
2912 * and location last time the view was expanded (if any). However it does not
2913 * remember the split pane divider location - this is set to match the
2914 * 'exploding' frame.
2918 public void explodeViews(SplitFrame sf)
2920 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
2921 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
2922 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
2924 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
2926 int viewCount = topPanels.size();
2933 * Processing in reverse order works, forwards order leaves the first panels
2934 * not visible. I don't know why!
2936 for (int i = viewCount - 1; i >= 0; i--)
2939 * Make new top and bottom frames. These take over the respective
2940 * AlignmentPanel objects, including their AlignmentViewports, so the
2941 * cdna/protein relationships between the viewports is carried over to the
2944 * explodedGeometry holds the (x, y) position of the previously exploded
2945 * SplitFrame, and the (width, height) of the AlignFrame component
2947 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
2948 AlignFrame newTopFrame = new AlignFrame(topPanel);
2949 newTopFrame.setSize(oldTopFrame.getSize());
2950 newTopFrame.setVisible(true);
2951 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
2952 .getExplodedGeometry();
2953 if (geometry != null)
2955 newTopFrame.setSize(geometry.getSize());
2958 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
2959 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
2960 newBottomFrame.setSize(oldBottomFrame.getSize());
2961 newBottomFrame.setVisible(true);
2962 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
2963 .getExplodedGeometry();
2964 if (geometry != null)
2966 newBottomFrame.setSize(geometry.getSize());
2969 topPanel.av.setGatherViewsHere(false);
2970 bottomPanel.av.setGatherViewsHere(false);
2971 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
2973 if (geometry != null)
2975 splitFrame.setLocation(geometry.getLocation());
2977 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
2981 * Clear references to the panels (now relocated in the new SplitFrames)
2982 * before closing the old SplitFrame.
2985 bottomPanels.clear();
2990 * Gather expanded split frames, sharing the same pairs of sequence set ids,
2991 * back into the given SplitFrame as additional views. Note that the gathered
2992 * frames may themselves have multiple views.
2996 public void gatherViews(GSplitFrame source)
2999 * special handling of explodedGeometry for a view within a SplitFrame: - it
3000 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3001 * height) of the AlignFrame component
3003 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3004 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3005 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3006 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3007 myBottomFrame.viewport
3008 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3009 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3010 myTopFrame.viewport.setGatherViewsHere(true);
3011 myBottomFrame.viewport.setGatherViewsHere(true);
3012 String topViewId = myTopFrame.viewport.getSequenceSetId();
3013 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3015 JInternalFrame[] frames = desktop.getAllFrames();
3016 for (JInternalFrame frame : frames)
3018 if (frame instanceof SplitFrame && frame != source)
3020 SplitFrame sf = (SplitFrame) frame;
3021 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3022 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3023 boolean gatherThis = false;
3024 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3026 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3027 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3028 if (topViewId.equals(topPanel.av.getSequenceSetId())
3029 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3032 topPanel.av.setGatherViewsHere(false);
3033 bottomPanel.av.setGatherViewsHere(false);
3034 topPanel.av.setExplodedGeometry(
3035 new Rectangle(sf.getLocation(), topFrame.getSize()));
3036 bottomPanel.av.setExplodedGeometry(
3037 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3038 myTopFrame.addAlignmentPanel(topPanel, false);
3039 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3045 topFrame.getAlignPanels().clear();
3046 bottomFrame.getAlignPanels().clear();
3053 * The dust settles...give focus to the tab we did this from.
3055 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3058 public static groovy.ui.Console getGroovyConsole()
3060 return groovyConsole;
3064 * handles the payload of a drag and drop event.
3066 * TODO refactor to desktop utilities class
3069 * - Data source strings extracted from the drop event
3071 * - protocol for each data source extracted from the drop event
3075 * - the payload from the drop event
3078 public static void transferFromDropTarget(List<String> files,
3079 List<DataSourceType> protocols, DropTargetDropEvent evt,
3080 Transferable t) throws Exception
3083 DataFlavor uriListFlavor = new DataFlavor(
3084 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3087 urlFlavour = new DataFlavor(
3088 "application/x-java-url; class=java.net.URL");
3089 } catch (ClassNotFoundException cfe)
3091 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3094 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3099 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3100 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3101 // means url may be null.
3104 protocols.add(DataSourceType.URL);
3105 files.add(url.toString());
3106 Cache.log.debug("Drop handled as URL dataflavor "
3107 + files.get(files.size() - 1));
3112 if (Platform.isAMac())
3115 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3119 } catch (Throwable ex)
3121 Cache.log.debug("URL drop handler failed.", ex);
3124 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3126 // Works on Windows and MacOSX
3127 Cache.log.debug("Drop handled as javaFileListFlavor");
3128 for (Object file : (List) t
3129 .getTransferData(DataFlavor.javaFileListFlavor))
3131 files.add(((File) file).toString());
3132 protocols.add(DataSourceType.FILE);
3137 // Unix like behaviour
3138 boolean added = false;
3140 if (t.isDataFlavorSupported(uriListFlavor))
3142 Cache.log.debug("Drop handled as uriListFlavor");
3143 // This is used by Unix drag system
3144 data = (String) t.getTransferData(uriListFlavor);
3148 // fallback to text: workaround - on OSX where there's a JVM bug
3149 Cache.log.debug("standard URIListFlavor failed. Trying text");
3150 // try text fallback
3151 DataFlavor textDf = new DataFlavor(
3152 "text/plain;class=java.lang.String");
3153 if (t.isDataFlavorSupported(textDf))
3155 data = (String) t.getTransferData(textDf);
3158 Cache.log.debug("Plain text drop content returned "
3159 + (data == null ? "Null - failed" : data));
3164 while (protocols.size() < files.size())
3166 Cache.log.debug("Adding missing FILE protocol for "
3167 + files.get(protocols.size()));
3168 protocols.add(DataSourceType.FILE);
3170 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3171 data, "\r\n"); st.hasMoreTokens();)
3174 String s = st.nextToken();
3175 if (s.startsWith("#"))
3177 // the line is a comment (as per the RFC 2483)
3180 java.net.URI uri = new java.net.URI(s);
3181 if (uri.getScheme().toLowerCase().startsWith("http"))
3183 protocols.add(DataSourceType.URL);
3184 files.add(uri.toString());
3188 // otherwise preserve old behaviour: catch all for file objects
3189 java.io.File file = new java.io.File(uri);
3190 protocols.add(DataSourceType.FILE);
3191 files.add(file.toString());
3196 if (Cache.log.isDebugEnabled())
3198 if (data == null || !added)
3201 if (t.getTransferDataFlavors() != null
3202 && t.getTransferDataFlavors().length > 0)
3205 "Couldn't resolve drop data. Here are the supported flavors:");
3206 for (DataFlavor fl : t.getTransferDataFlavors())
3209 "Supported transfer dataflavor: " + fl.toString());
3210 Object df = t.getTransferData(fl);
3213 Cache.log.debug("Retrieves: " + df);
3217 Cache.log.debug("Retrieved nothing");
3223 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3229 if (Platform.isWindows())
3232 Cache.log.debug("Scanning dropped content for Windows Link Files");
3234 // resolve any .lnk files in the file drop
3235 for (int f = 0; f < files.size(); f++)
3237 String source = files.get(f).toLowerCase();
3238 if (protocols.get(f).equals(DataSourceType.FILE)
3239 && (source.endsWith(".lnk") || source.endsWith(".url")
3240 || source.endsWith(".site")))
3244 File lf = new File(files.get(f));
3245 // process link file to get a URL
3246 Cache.log.debug("Found potential link file: " + lf);
3247 WindowsShortcut wscfile = new WindowsShortcut(lf);
3248 String fullname = wscfile.getRealFilename();
3249 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3250 files.set(f, fullname);
3251 Cache.log.debug("Parsed real filename " + fullname
3252 + " to extract protocol: " + protocols.get(f));
3253 } catch (Exception ex)
3256 "Couldn't parse " + files.get(f) + " as a link file.",
3265 * Sets the Preferences property for experimental features to True or False
3266 * depending on the state of the controlling menu item
3269 protected void showExperimental_actionPerformed(boolean selected)
3271 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3275 * Answers a (possibly empty) list of any structure viewer frames (currently
3276 * for either Jmol or Chimera) which are currently open. This may optionally
3277 * be restricted to viewers of a specified class, or viewers linked to a
3278 * specified alignment panel.
3281 * if not null, only return viewers linked to this panel
3282 * @param structureViewerClass
3283 * if not null, only return viewers of this class
3286 public List<StructureViewerBase> getStructureViewers(
3287 AlignmentPanel apanel,
3288 Class<? extends StructureViewerBase> structureViewerClass)
3290 List<StructureViewerBase> result = new ArrayList<>();
3291 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3293 for (JInternalFrame frame : frames)
3295 if (frame instanceof StructureViewerBase)
3297 if (structureViewerClass == null
3298 || structureViewerClass.isInstance(frame))
3301 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3303 result.add((StructureViewerBase) frame);