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 if (Cache.getProperty("NOIDENTIFIERSSERVICE") == null)
563 {// Thread off the identifiers fetcher
564 new Thread(new Runnable()
569 Cache.log.debug("Downloading data from identifiers.org");
572 UrlDownloadClient.download(IdOrgSettings.getUrl(),
573 IdOrgSettings.getDownloadLocation());
574 } catch (IOException e)
576 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 https://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("https://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 "https://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=\"https://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 AlignmentViewport source = null, target = null;
1504 if (frames[0] instanceof AlignFrame)
1506 source = ((AlignFrame) frames[0]).getCurrentView();
1508 else if (frames[0] instanceof TreePanel)
1510 source = ((TreePanel) frames[0]).getViewPort();
1512 else if (frames[0] instanceof PCAPanel)
1514 source = ((PCAPanel) frames[0]).av;
1516 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1518 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1523 for (int i = 0; i < frames.length; i++)
1526 if (frames[i] == null)
1530 if (frames[i] instanceof AlignFrame)
1532 target = ((AlignFrame) frames[i]).getCurrentView();
1534 else if (frames[i] instanceof TreePanel)
1536 target = ((TreePanel) frames[i]).getViewPort();
1538 else if (frames[i] instanceof PCAPanel)
1540 target = ((PCAPanel) frames[i]).av;
1542 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1544 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1547 if (source == target)
1553 frames[i].setClosed(true);
1557 frames[i].setIcon(minimize);
1560 frames[i].toFront();
1564 } catch (java.beans.PropertyVetoException ex)
1579 protected void preferences_actionPerformed(ActionEvent e)
1585 * Shows a file chooser dialog and writes out the current session as a Jalview
1589 public void saveState_actionPerformed()
1591 saveState_actionPerformed(false);
1594 public void saveState_actionPerformed(boolean saveAs)
1596 java.io.File projectFile = getProjectFile();
1597 // autoSave indicates we already have a file and don't need to ask
1598 boolean autoSave = projectFile != null && !saveAs
1599 && BackupFiles.getEnabled();
1601 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1602 // saveAs="+saveAs+", Backups
1603 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1605 boolean approveSave = false;
1608 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1611 chooser.setFileView(new JalviewFileView());
1612 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1614 int value = chooser.showSaveDialog(this);
1616 if (value == JalviewFileChooser.APPROVE_OPTION)
1618 projectFile = chooser.getSelectedFile();
1619 setProjectFile(projectFile);
1624 if (approveSave || autoSave)
1626 final Desktop me = this;
1627 final java.io.File chosenFile = projectFile;
1628 new Thread(new Runnable()
1633 // TODO: refactor to Jalview desktop session controller action.
1634 setProgressBar(MessageManager.formatMessage(
1635 "label.saving_jalview_project", new Object[]
1636 { chosenFile.getName() }), chosenFile.hashCode());
1637 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1638 chosenFile.getParent());
1639 // TODO catch and handle errors for savestate
1640 // TODO prevent user from messing with the Desktop whilst we're saving
1643 BackupFiles backupfiles = new BackupFiles(chosenFile);
1645 new Jalview2XML().saveState(backupfiles.getTempFile());
1647 backupfiles.setWriteSuccess(true);
1648 backupfiles.rollBackupsAndRenameTempFile();
1649 } catch (OutOfMemoryError oom)
1651 new OOMWarning("Whilst saving current state to "
1652 + chosenFile.getName(), oom);
1653 } catch (Exception ex)
1655 Cache.log.error("Problems whilst trying to save to "
1656 + chosenFile.getName(), ex);
1657 JvOptionPane.showMessageDialog(me,
1658 MessageManager.formatMessage(
1659 "label.error_whilst_saving_current_state_to",
1661 { chosenFile.getName() }),
1662 MessageManager.getString("label.couldnt_save_project"),
1663 JvOptionPane.WARNING_MESSAGE);
1665 setProgressBar(null, chosenFile.hashCode());
1672 public void saveAsState_actionPerformed(ActionEvent e)
1674 saveState_actionPerformed(true);
1677 private void setProjectFile(File choice)
1679 this.projectFile = choice;
1682 public File getProjectFile()
1684 return this.projectFile;
1688 * Shows a file chooser dialog and tries to read in the selected file as a
1692 public void loadState_actionPerformed()
1694 final String[] suffix = new String[] { "jvp", "jar" };
1695 final String[] desc = new String[] { "Jalview Project",
1696 "Jalview Project (old)" };
1697 JalviewFileChooser chooser = new JalviewFileChooser(
1698 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1699 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1701 chooser.setFileView(new JalviewFileView());
1702 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1704 int value = chooser.showOpenDialog(this);
1706 if (value == JalviewFileChooser.APPROVE_OPTION)
1708 final File selectedFile = chooser.getSelectedFile();
1709 setProjectFile(selectedFile);
1710 final String choice = selectedFile.getAbsolutePath();
1711 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1712 new Thread(new Runnable()
1717 setProgressBar(MessageManager.formatMessage(
1718 "label.loading_jalview_project", new Object[]
1719 { choice }), choice.hashCode());
1722 new Jalview2XML().loadJalviewAlign(choice);
1723 } catch (OutOfMemoryError oom)
1725 new OOMWarning("Whilst loading project from " + choice, oom);
1726 } catch (Exception ex)
1729 "Problems whilst loading project from " + choice, ex);
1730 JvOptionPane.showMessageDialog(Desktop.desktop,
1731 MessageManager.formatMessage(
1732 "label.error_whilst_loading_project_from",
1735 MessageManager.getString("label.couldnt_load_project"),
1736 JvOptionPane.WARNING_MESSAGE);
1738 setProgressBar(null, choice.hashCode());
1745 public void inputSequence_actionPerformed(ActionEvent e)
1747 new SequenceFetcher(this);
1750 JPanel progressPanel;
1752 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1754 public void startLoading(final String fileName)
1756 if (fileLoadingCount == 0)
1758 fileLoadingPanels.add(addProgressPanel(MessageManager
1759 .formatMessage("label.loading_file", new Object[]
1765 private JPanel addProgressPanel(String string)
1767 if (progressPanel == null)
1769 progressPanel = new JPanel(new GridLayout(1, 1));
1770 totalProgressCount = 0;
1771 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1773 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1774 JProgressBar progressBar = new JProgressBar();
1775 progressBar.setIndeterminate(true);
1777 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1779 thisprogress.add(progressBar, BorderLayout.CENTER);
1780 progressPanel.add(thisprogress);
1781 ((GridLayout) progressPanel.getLayout()).setRows(
1782 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1783 ++totalProgressCount;
1784 instance.validate();
1785 return thisprogress;
1788 int totalProgressCount = 0;
1790 private void removeProgressPanel(JPanel progbar)
1792 if (progressPanel != null)
1794 synchronized (progressPanel)
1796 progressPanel.remove(progbar);
1797 GridLayout gl = (GridLayout) progressPanel.getLayout();
1798 gl.setRows(gl.getRows() - 1);
1799 if (--totalProgressCount < 1)
1801 this.getContentPane().remove(progressPanel);
1802 progressPanel = null;
1809 public void stopLoading()
1812 if (fileLoadingCount < 1)
1814 while (fileLoadingPanels.size() > 0)
1816 removeProgressPanel(fileLoadingPanels.remove(0));
1818 fileLoadingPanels.clear();
1819 fileLoadingCount = 0;
1824 public static int getViewCount(String alignmentId)
1826 AlignmentViewport[] aps = getViewports(alignmentId);
1827 return (aps == null) ? 0 : aps.length;
1832 * @param alignmentId
1833 * - if null, all sets are returned
1834 * @return all AlignmentPanels concerning the alignmentId sequence set
1836 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1838 if (Desktop.desktop == null)
1840 // no frames created and in headless mode
1841 // TODO: verify that frames are recoverable when in headless mode
1844 List<AlignmentPanel> aps = new ArrayList<>();
1845 AlignFrame[] frames = getAlignFrames();
1850 for (AlignFrame af : frames)
1852 for (AlignmentPanel ap : af.alignPanels)
1854 if (alignmentId == null
1855 || alignmentId.equals(ap.av.getSequenceSetId()))
1861 if (aps.size() == 0)
1865 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1870 * get all the viewports on an alignment.
1872 * @param sequenceSetId
1873 * unique alignment id (may be null - all viewports returned in that
1875 * @return all viewports on the alignment bound to sequenceSetId
1877 public static AlignmentViewport[] getViewports(String sequenceSetId)
1879 List<AlignmentViewport> viewp = new ArrayList<>();
1880 if (desktop != null)
1882 AlignFrame[] frames = Desktop.getAlignFrames();
1884 for (AlignFrame afr : frames)
1886 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1887 .equals(sequenceSetId))
1889 if (afr.alignPanels != null)
1891 for (AlignmentPanel ap : afr.alignPanels)
1893 if (sequenceSetId == null
1894 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1902 viewp.add(afr.getViewport());
1906 if (viewp.size() > 0)
1908 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1915 * Explode the views in the given frame into separate AlignFrame
1919 public static void explodeViews(AlignFrame af)
1921 int size = af.alignPanels.size();
1927 // FIXME: ideally should use UI interface API
1928 FeatureSettings viewFeatureSettings = (af.featureSettings != null
1929 && af.featureSettings.isOpen())
1930 ? af.featureSettings
1932 Rectangle fsBounds = af.getFeatureSettingsGeometry();
1933 for (int i = 0; i < size; i++)
1935 AlignmentPanel ap = af.alignPanels.get(i);
1937 AlignFrame newaf = new AlignFrame(ap);
1939 // transfer reference for existing feature settings to new alignFrame
1940 if (ap == af.alignPanel)
1942 if (viewFeatureSettings != null && viewFeatureSettings.fr.ap == ap)
1944 newaf.featureSettings = viewFeatureSettings;
1946 newaf.setFeatureSettingsGeometry(fsBounds);
1950 * Restore the view's last exploded frame geometry if known. Multiple
1951 * views from one exploded frame share and restore the same (frame)
1952 * position and size.
1954 Rectangle geometry = ap.av.getExplodedGeometry();
1955 if (geometry != null)
1957 newaf.setBounds(geometry);
1960 ap.av.setGatherViewsHere(false);
1962 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1963 AlignFrame.DEFAULT_HEIGHT);
1964 // and materialise a new feature settings dialog instance for the new alignframe
1965 // (closes the old as if 'OK' was pressed)
1966 if (ap == af.alignPanel && newaf.featureSettings != null
1967 && newaf.featureSettings.isOpen()
1968 && af.alignPanel.getAlignViewport().isShowSequenceFeatures())
1970 newaf.showFeatureSettingsUI();
1974 af.featureSettings = null;
1975 af.alignPanels.clear();
1976 af.closeMenuItem_actionPerformed(true);
1981 * Gather expanded views (separate AlignFrame's) with the same sequence set
1982 * identifier back in to this frame as additional views, and close the
1983 * expanded views. Note the expanded frames may themselves have multiple
1984 * views. We take the lot.
1988 public void gatherViews(AlignFrame source)
1990 source.viewport.setGatherViewsHere(true);
1991 source.viewport.setExplodedGeometry(source.getBounds());
1992 JInternalFrame[] frames = desktop.getAllFrames();
1993 String viewId = source.viewport.getSequenceSetId();
1994 for (int t = 0; t < frames.length; t++)
1996 if (frames[t] instanceof AlignFrame && frames[t] != source)
1998 AlignFrame af = (AlignFrame) frames[t];
1999 boolean gatherThis = false;
2000 for (int a = 0; a < af.alignPanels.size(); a++)
2002 AlignmentPanel ap = af.alignPanels.get(a);
2003 if (viewId.equals(ap.av.getSequenceSetId()))
2006 ap.av.setGatherViewsHere(false);
2007 ap.av.setExplodedGeometry(af.getBounds());
2008 source.addAlignmentPanel(ap, false);
2014 if (af.featureSettings != null && af.featureSettings.isOpen())
2016 if (source.featureSettings == null)
2018 // preserve the feature settings geometry for this frame
2019 source.featureSettings = af.featureSettings;
2020 source.setFeatureSettingsGeometry(
2021 af.getFeatureSettingsGeometry());
2025 // close it and forget
2026 af.featureSettings.close();
2029 af.alignPanels.clear();
2030 af.closeMenuItem_actionPerformed(true);
2034 // refresh the feature setting UI for the source frame if it exists
2035 if (source.featureSettings != null
2036 && source.featureSettings.isOpen())
2038 source.showFeatureSettingsUI();
2043 public JInternalFrame[] getAllFrames()
2045 return desktop.getAllFrames();
2049 * Checks the given url to see if it gives a response indicating that the user
2050 * should be informed of a new questionnaire.
2054 public void checkForQuestionnaire(String url)
2056 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2057 // javax.swing.SwingUtilities.invokeLater(jvq);
2058 new Thread(jvq).start();
2061 public void checkURLLinks()
2063 // Thread off the URL link checker
2064 addDialogThread(new Runnable()
2069 if (Cache.getDefault("CHECKURLLINKS", true))
2071 // check what the actual links are - if it's just the default don't
2072 // bother with the warning
2073 List<String> links = Preferences.sequenceUrlLinks
2076 // only need to check links if there is one with a
2077 // SEQUENCE_ID which is not the default EMBL_EBI link
2078 ListIterator<String> li = links.listIterator();
2079 boolean check = false;
2080 List<JLabel> urls = new ArrayList<>();
2081 while (li.hasNext())
2083 String link = li.next();
2084 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2085 && !UrlConstants.isDefaultString(link))
2088 int barPos = link.indexOf("|");
2089 String urlMsg = barPos == -1 ? link
2090 : link.substring(0, barPos) + ": "
2091 + link.substring(barPos + 1);
2092 urls.add(new JLabel(urlMsg));
2100 // ask user to check in case URL links use old style tokens
2101 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2102 JPanel msgPanel = new JPanel();
2103 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2104 msgPanel.add(Box.createVerticalGlue());
2105 JLabel msg = new JLabel(MessageManager
2106 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2107 JLabel msg2 = new JLabel(MessageManager
2108 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2110 for (JLabel url : urls)
2116 final JCheckBox jcb = new JCheckBox(
2117 MessageManager.getString("label.do_not_display_again"));
2118 jcb.addActionListener(new ActionListener()
2121 public void actionPerformed(ActionEvent e)
2123 // update Cache settings for "don't show this again"
2124 boolean showWarningAgain = !jcb.isSelected();
2125 Cache.setProperty("CHECKURLLINKS",
2126 Boolean.valueOf(showWarningAgain).toString());
2131 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2133 .getString("label.SEQUENCE_ID_no_longer_used"),
2134 JvOptionPane.WARNING_MESSAGE);
2141 * Proxy class for JDesktopPane which optionally displays the current memory
2142 * usage and highlights the desktop area with a red bar if free memory runs
2147 public class MyDesktopPane extends JDesktopPane implements Runnable
2150 private static final float ONE_MB = 1048576f;
2152 boolean showMemoryUsage = false;
2156 java.text.NumberFormat df;
2158 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2161 public MyDesktopPane(boolean showMemoryUsage)
2163 showMemoryUsage(showMemoryUsage);
2166 public void showMemoryUsage(boolean showMemory)
2168 this.showMemoryUsage = showMemory;
2171 Thread worker = new Thread(this);
2177 public boolean isShowMemoryUsage()
2179 return showMemoryUsage;
2185 df = java.text.NumberFormat.getNumberInstance();
2186 df.setMaximumFractionDigits(2);
2187 runtime = Runtime.getRuntime();
2189 while (showMemoryUsage)
2193 maxMemory = runtime.maxMemory() / ONE_MB;
2194 allocatedMemory = runtime.totalMemory() / ONE_MB;
2195 freeMemory = runtime.freeMemory() / ONE_MB;
2196 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2198 percentUsage = (totalFreeMemory / maxMemory) * 100;
2200 // if (percentUsage < 20)
2202 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2204 // instance.set.setBorder(border1);
2207 // sleep after showing usage
2209 } catch (Exception ex)
2211 ex.printStackTrace();
2217 public void paintComponent(Graphics g)
2219 if (showMemoryUsage && g != null && df != null)
2221 if (percentUsage < 20)
2223 g.setColor(Color.red);
2225 FontMetrics fm = g.getFontMetrics();
2228 g.drawString(MessageManager.formatMessage("label.memory_stats",
2230 { df.format(totalFreeMemory), df.format(maxMemory),
2231 df.format(percentUsage) }),
2232 10, getHeight() - fm.getHeight());
2239 * Accessor method to quickly get all the AlignmentFrames loaded.
2241 * @return an array of AlignFrame, or null if none found
2243 public static AlignFrame[] getAlignFrames()
2245 if (Jalview.isHeadlessMode())
2247 // Desktop.desktop is null in headless mode
2248 return new AlignFrame[] { Jalview.currentAlignFrame };
2251 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2257 List<AlignFrame> avp = new ArrayList<>();
2259 for (int i = frames.length - 1; i > -1; i--)
2261 if (frames[i] instanceof AlignFrame)
2263 avp.add((AlignFrame) frames[i]);
2265 else if (frames[i] instanceof SplitFrame)
2268 * Also check for a split frame containing an AlignFrame
2270 GSplitFrame sf = (GSplitFrame) frames[i];
2271 if (sf.getTopFrame() instanceof AlignFrame)
2273 avp.add((AlignFrame) sf.getTopFrame());
2275 if (sf.getBottomFrame() instanceof AlignFrame)
2277 avp.add((AlignFrame) sf.getBottomFrame());
2281 if (avp.size() == 0)
2285 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2290 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2294 public GStructureViewer[] getJmols()
2296 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2302 List<GStructureViewer> avp = new ArrayList<>();
2304 for (int i = frames.length - 1; i > -1; i--)
2306 if (frames[i] instanceof AppJmol)
2308 GStructureViewer af = (GStructureViewer) frames[i];
2312 if (avp.size() == 0)
2316 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2321 * Add Groovy Support to Jalview
2324 public void groovyShell_actionPerformed()
2328 openGroovyConsole();
2329 } catch (Exception ex)
2331 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2332 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2334 MessageManager.getString("label.couldnt_create_groovy_shell"),
2335 MessageManager.getString("label.groovy_support_failed"),
2336 JvOptionPane.ERROR_MESSAGE);
2341 * Open the Groovy console
2343 void openGroovyConsole()
2345 if (groovyConsole == null)
2347 groovyConsole = new groovy.ui.Console();
2348 groovyConsole.setVariable("Jalview", this);
2349 groovyConsole.run();
2352 * We allow only one console at a time, so that AlignFrame menu option
2353 * 'Calculate | Run Groovy script' is unambiguous.
2354 * Disable 'Groovy Console', and enable 'Run script', when the console is
2355 * opened, and the reverse when it is closed
2357 Window window = (Window) groovyConsole.getFrame();
2358 window.addWindowListener(new WindowAdapter()
2361 public void windowClosed(WindowEvent e)
2364 * rebind CMD-Q from Groovy Console to Jalview Quit
2367 enableExecuteGroovy(false);
2373 * show Groovy console window (after close and reopen)
2375 ((Window) groovyConsole.getFrame()).setVisible(true);
2378 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2379 * and disable opening a second console
2381 enableExecuteGroovy(true);
2385 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2386 * binding when opened
2388 protected void addQuitHandler()
2390 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2391 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2392 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2394 getRootPane().getActionMap().put("Quit", new AbstractAction()
2397 public void actionPerformed(ActionEvent e)
2405 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2408 * true if Groovy console is open
2410 public void enableExecuteGroovy(boolean enabled)
2413 * disable opening a second Groovy console
2414 * (or re-enable when the console is closed)
2416 groovyShell.setEnabled(!enabled);
2418 AlignFrame[] alignFrames = getAlignFrames();
2419 if (alignFrames != null)
2421 for (AlignFrame af : alignFrames)
2423 af.setGroovyEnabled(enabled);
2429 * Progress bars managed by the IProgressIndicator method.
2431 private Hashtable<Long, JPanel> progressBars;
2433 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2438 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2441 public void setProgressBar(String message, long id)
2443 if (progressBars == null)
2445 progressBars = new Hashtable<>();
2446 progressBarHandlers = new Hashtable<>();
2449 if (progressBars.get(Long.valueOf(id)) != null)
2451 JPanel panel = progressBars.remove(Long.valueOf(id));
2452 if (progressBarHandlers.contains(Long.valueOf(id)))
2454 progressBarHandlers.remove(Long.valueOf(id));
2456 removeProgressPanel(panel);
2460 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2467 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2468 * jalview.gui.IProgressIndicatorHandler)
2471 public void registerHandler(final long id,
2472 final IProgressIndicatorHandler handler)
2474 if (progressBarHandlers == null
2475 || !progressBars.containsKey(Long.valueOf(id)))
2477 throw new Error(MessageManager.getString(
2478 "error.call_setprogressbar_before_registering_handler"));
2480 progressBarHandlers.put(Long.valueOf(id), handler);
2481 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2482 if (handler.canCancel())
2484 JButton cancel = new JButton(
2485 MessageManager.getString("action.cancel"));
2486 final IProgressIndicator us = this;
2487 cancel.addActionListener(new ActionListener()
2491 public void actionPerformed(ActionEvent e)
2493 handler.cancelActivity(id);
2494 us.setProgressBar(MessageManager
2495 .formatMessage("label.cancelled_params", new Object[]
2496 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2500 progressPanel.add(cancel, BorderLayout.EAST);
2506 * @return true if any progress bars are still active
2509 public boolean operationInProgress()
2511 if (progressBars != null && progressBars.size() > 0)
2519 * This will return the first AlignFrame holding the given viewport instance.
2520 * It will break if there are more than one AlignFrames viewing a particular
2524 * @return alignFrame for viewport
2526 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2528 if (desktop != null)
2530 AlignmentPanel[] aps = getAlignmentPanels(
2531 viewport.getSequenceSetId());
2532 for (int panel = 0; aps != null && panel < aps.length; panel++)
2534 if (aps[panel] != null && aps[panel].av == viewport)
2536 return aps[panel].alignFrame;
2543 public VamsasApplication getVamsasApplication()
2545 // TODO: JAL-3311 remove remaining code from Jalview relating to VAMSAS
2551 * flag set if jalview GUI is being operated programmatically
2553 private boolean inBatchMode = false;
2556 * check if jalview GUI is being operated programmatically
2558 * @return inBatchMode
2560 public boolean isInBatchMode()
2566 * set flag if jalview GUI is being operated programmatically
2568 * @param inBatchMode
2570 public void setInBatchMode(boolean inBatchMode)
2572 this.inBatchMode = inBatchMode;
2576 * start service discovery and wait till it is done
2578 public void startServiceDiscovery()
2580 startServiceDiscovery(false);
2584 * start service discovery threads - blocking or non-blocking
2588 public void startServiceDiscovery(boolean blocking)
2590 startServiceDiscovery(blocking,false);
2594 * start service discovery threads
2597 * - false means call returns immediately
2598 * @param ignore_SHOW_JWS2_SERVICES_preference
2599 * - when true JABA services are discovered regardless of user's JWS2
2600 * discovery preference setting
2602 public void startServiceDiscovery(boolean blocking,
2603 boolean ignore_SHOW_JWS2_SERVICES_preference)
2605 boolean alive = true;
2606 Thread t0 = null, t1 = null, t2 = null;
2607 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2610 // todo: changesupport handlers need to be transferred
2611 if (discoverer == null)
2613 discoverer = new jalview.ws.jws1.Discoverer();
2614 // register PCS handler for desktop.
2615 discoverer.addPropertyChangeListener(changeSupport);
2617 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2618 // until we phase out completely
2619 (t0 = new Thread(discoverer)).start();
2622 if (ignore_SHOW_JWS2_SERVICES_preference
2623 || Cache.getDefault("SHOW_JWS2_SERVICES", true))
2625 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2626 .startDiscoverer(changeSupport);
2630 // TODO: do rest service discovery
2639 } catch (Exception e)
2642 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2643 || (t3 != null && t3.isAlive())
2644 || (t0 != null && t0.isAlive());
2650 * called to check if the service discovery process completed successfully.
2654 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2656 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2658 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2659 .getErrorMessages();
2662 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2664 if (serviceChangedDialog == null)
2666 // only run if we aren't already displaying one of these.
2667 addDialogThread(serviceChangedDialog = new Runnable()
2674 * JalviewDialog jd =new JalviewDialog() {
2676 * @Override protected void cancelPressed() { // TODO
2677 * Auto-generated method stub
2679 * }@Override protected void okPressed() { // TODO
2680 * Auto-generated method stub
2682 * }@Override protected void raiseClosed() { // TODO
2683 * Auto-generated method stub
2685 * } }; jd.initDialogFrame(new
2686 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2687 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2688 * + " or mis-configured HTTP proxy settings.<br/>" +
2689 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2691 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2692 * ), true, true, "Web Service Configuration Problem", 450,
2695 * jd.waitForInput();
2697 JvOptionPane.showConfirmDialog(Desktop.desktop,
2698 new JLabel("<html><table width=\"450\"><tr><td>"
2699 + ermsg + "</td></tr></table>"
2700 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
2701 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
2702 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
2703 + " Tools->Preferences dialog box to change them.</p></html>"),
2704 "Web Service Configuration Problem",
2705 JvOptionPane.DEFAULT_OPTION,
2706 JvOptionPane.ERROR_MESSAGE);
2707 serviceChangedDialog = null;
2716 "Errors reported by JABA discovery service. Check web services preferences.\n"
2723 private Runnable serviceChangedDialog = null;
2726 * start a thread to open a URL in the configured browser. Pops up a warning
2727 * dialog to the user if there is an exception when calling out to the browser
2732 public static void showUrl(final String url)
2734 showUrl(url, Desktop.instance);
2738 * Like showUrl but allows progress handler to be specified
2742 * (null) or object implementing IProgressIndicator
2744 public static void showUrl(final String url,
2745 final IProgressIndicator progress)
2747 new Thread(new Runnable()
2754 if (progress != null)
2756 progress.setProgressBar(MessageManager
2757 .formatMessage("status.opening_params", new Object[]
2758 { url }), this.hashCode());
2760 jalview.util.BrowserLauncher.openURL(url);
2761 } catch (Exception ex)
2763 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2765 .getString("label.web_browser_not_found_unix"),
2766 MessageManager.getString("label.web_browser_not_found"),
2767 JvOptionPane.WARNING_MESSAGE);
2769 ex.printStackTrace();
2771 if (progress != null)
2773 progress.setProgressBar(null, this.hashCode());
2779 public static WsParamSetManager wsparamManager = null;
2781 public static ParamManager getUserParameterStore()
2783 if (wsparamManager == null)
2785 wsparamManager = new WsParamSetManager();
2787 return wsparamManager;
2791 * static hyperlink handler proxy method for use by Jalview's internal windows
2795 public static void hyperlinkUpdate(HyperlinkEvent e)
2797 if (e.getEventType() == EventType.ACTIVATED)
2802 url = e.getURL().toString();
2803 Desktop.showUrl(url);
2804 } catch (Exception x)
2808 if (Cache.log != null)
2810 Cache.log.error("Couldn't handle string " + url + " as a URL.");
2815 "Couldn't handle string " + url + " as a URL.");
2818 // ignore any exceptions due to dud links.
2825 * single thread that handles display of dialogs to user.
2827 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
2830 * flag indicating if dialogExecutor should try to acquire a permit
2832 private volatile boolean dialogPause = true;
2837 private java.util.concurrent.Semaphore block = new Semaphore(0);
2839 private static groovy.ui.Console groovyConsole;
2842 * add another dialog thread to the queue
2846 public void addDialogThread(final Runnable prompter)
2848 dialogExecutor.submit(new Runnable()
2858 } catch (InterruptedException x)
2863 if (instance == null)
2869 SwingUtilities.invokeAndWait(prompter);
2870 } catch (Exception q)
2872 Cache.log.warn("Unexpected Exception in dialog thread.", q);
2878 public void startDialogQueue()
2880 // set the flag so we don't pause waiting for another permit and semaphore
2881 // the current task to begin
2882 dialogPause = false;
2887 protected void snapShotWindow_actionPerformed(ActionEvent e)
2891 ImageMaker im = new jalview.util.ImageMaker(
2892 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
2893 getHeight(), of = new File("Jalview_snapshot"
2894 + System.currentTimeMillis() + ".eps"),
2895 "View of desktop", null, 0, false);
2898 paintAll(im.getGraphics());
2900 } catch (Exception q)
2902 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
2906 Cache.log.info("Successfully written snapshot to file "
2907 + of.getAbsolutePath());
2911 * Explode the views in the given SplitFrame into separate SplitFrame windows.
2912 * This respects (remembers) any previous 'exploded geometry' i.e. the size
2913 * and location last time the view was expanded (if any). However it does not
2914 * remember the split pane divider location - this is set to match the
2915 * 'exploding' frame.
2919 public void explodeViews(SplitFrame sf)
2921 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
2922 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
2923 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
2925 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
2927 int viewCount = topPanels.size();
2934 * Processing in reverse order works, forwards order leaves the first panels
2935 * not visible. I don't know why!
2937 for (int i = viewCount - 1; i >= 0; i--)
2940 * Make new top and bottom frames. These take over the respective
2941 * AlignmentPanel objects, including their AlignmentViewports, so the
2942 * cdna/protein relationships between the viewports is carried over to the
2945 * explodedGeometry holds the (x, y) position of the previously exploded
2946 * SplitFrame, and the (width, height) of the AlignFrame component
2948 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
2949 AlignFrame newTopFrame = new AlignFrame(topPanel);
2950 newTopFrame.setSize(oldTopFrame.getSize());
2951 newTopFrame.setVisible(true);
2952 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
2953 .getExplodedGeometry();
2954 if (geometry != null)
2956 newTopFrame.setSize(geometry.getSize());
2959 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
2960 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
2961 newBottomFrame.setSize(oldBottomFrame.getSize());
2962 newBottomFrame.setVisible(true);
2963 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
2964 .getExplodedGeometry();
2965 if (geometry != null)
2967 newBottomFrame.setSize(geometry.getSize());
2970 topPanel.av.setGatherViewsHere(false);
2971 bottomPanel.av.setGatherViewsHere(false);
2972 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
2974 if (geometry != null)
2976 splitFrame.setLocation(geometry.getLocation());
2978 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
2982 * Clear references to the panels (now relocated in the new SplitFrames)
2983 * before closing the old SplitFrame.
2986 bottomPanels.clear();
2991 * Gather expanded split frames, sharing the same pairs of sequence set ids,
2992 * back into the given SplitFrame as additional views. Note that the gathered
2993 * frames may themselves have multiple views.
2997 public void gatherViews(GSplitFrame source)
3000 * special handling of explodedGeometry for a view within a SplitFrame: - it
3001 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3002 * height) of the AlignFrame component
3004 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3005 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3006 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3007 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3008 myBottomFrame.viewport
3009 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3010 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3011 myTopFrame.viewport.setGatherViewsHere(true);
3012 myBottomFrame.viewport.setGatherViewsHere(true);
3013 String topViewId = myTopFrame.viewport.getSequenceSetId();
3014 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3016 JInternalFrame[] frames = desktop.getAllFrames();
3017 for (JInternalFrame frame : frames)
3019 if (frame instanceof SplitFrame && frame != source)
3021 SplitFrame sf = (SplitFrame) frame;
3022 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3023 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3024 boolean gatherThis = false;
3025 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3027 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3028 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3029 if (topViewId.equals(topPanel.av.getSequenceSetId())
3030 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3033 topPanel.av.setGatherViewsHere(false);
3034 bottomPanel.av.setGatherViewsHere(false);
3035 topPanel.av.setExplodedGeometry(
3036 new Rectangle(sf.getLocation(), topFrame.getSize()));
3037 bottomPanel.av.setExplodedGeometry(
3038 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3039 myTopFrame.addAlignmentPanel(topPanel, false);
3040 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3046 topFrame.getAlignPanels().clear();
3047 bottomFrame.getAlignPanels().clear();
3054 * The dust settles...give focus to the tab we did this from.
3056 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3059 public static groovy.ui.Console getGroovyConsole()
3061 return groovyConsole;
3065 * handles the payload of a drag and drop event.
3067 * TODO refactor to desktop utilities class
3070 * - Data source strings extracted from the drop event
3072 * - protocol for each data source extracted from the drop event
3076 * - the payload from the drop event
3079 public static void transferFromDropTarget(List<String> files,
3080 List<DataSourceType> protocols, DropTargetDropEvent evt,
3081 Transferable t) throws Exception
3084 DataFlavor uriListFlavor = new DataFlavor(
3085 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3088 urlFlavour = new DataFlavor(
3089 "application/x-java-url; class=java.net.URL");
3090 } catch (ClassNotFoundException cfe)
3092 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3095 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3100 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3101 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3102 // means url may be null.
3105 protocols.add(DataSourceType.URL);
3106 files.add(url.toString());
3107 Cache.log.debug("Drop handled as URL dataflavor "
3108 + files.get(files.size() - 1));
3113 if (Platform.isAMac())
3116 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3120 } catch (Throwable ex)
3122 Cache.log.debug("URL drop handler failed.", ex);
3125 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3127 // Works on Windows and MacOSX
3128 Cache.log.debug("Drop handled as javaFileListFlavor");
3129 for (Object file : (List) t
3130 .getTransferData(DataFlavor.javaFileListFlavor))
3132 files.add(((File) file).toString());
3133 protocols.add(DataSourceType.FILE);
3138 // Unix like behaviour
3139 boolean added = false;
3141 if (t.isDataFlavorSupported(uriListFlavor))
3143 Cache.log.debug("Drop handled as uriListFlavor");
3144 // This is used by Unix drag system
3145 data = (String) t.getTransferData(uriListFlavor);
3149 // fallback to text: workaround - on OSX where there's a JVM bug
3150 Cache.log.debug("standard URIListFlavor failed. Trying text");
3151 // try text fallback
3152 DataFlavor textDf = new DataFlavor(
3153 "text/plain;class=java.lang.String");
3154 if (t.isDataFlavorSupported(textDf))
3156 data = (String) t.getTransferData(textDf);
3159 Cache.log.debug("Plain text drop content returned "
3160 + (data == null ? "Null - failed" : data));
3165 while (protocols.size() < files.size())
3167 Cache.log.debug("Adding missing FILE protocol for "
3168 + files.get(protocols.size()));
3169 protocols.add(DataSourceType.FILE);
3171 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3172 data, "\r\n"); st.hasMoreTokens();)
3175 String s = st.nextToken();
3176 if (s.startsWith("#"))
3178 // the line is a comment (as per the RFC 2483)
3181 java.net.URI uri = new java.net.URI(s);
3182 if (uri.getScheme().toLowerCase().startsWith("http"))
3184 protocols.add(DataSourceType.URL);
3185 files.add(uri.toString());
3189 // otherwise preserve old behaviour: catch all for file objects
3190 java.io.File file = new java.io.File(uri);
3191 protocols.add(DataSourceType.FILE);
3192 files.add(file.toString());
3197 if (Cache.log.isDebugEnabled())
3199 if (data == null || !added)
3202 if (t.getTransferDataFlavors() != null
3203 && t.getTransferDataFlavors().length > 0)
3206 "Couldn't resolve drop data. Here are the supported flavors:");
3207 for (DataFlavor fl : t.getTransferDataFlavors())
3210 "Supported transfer dataflavor: " + fl.toString());
3211 Object df = t.getTransferData(fl);
3214 Cache.log.debug("Retrieves: " + df);
3218 Cache.log.debug("Retrieved nothing");
3224 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3230 if (Platform.isWindows())
3233 Cache.log.debug("Scanning dropped content for Windows Link Files");
3235 // resolve any .lnk files in the file drop
3236 for (int f = 0; f < files.size(); f++)
3238 String source = files.get(f).toLowerCase();
3239 if (protocols.get(f).equals(DataSourceType.FILE)
3240 && (source.endsWith(".lnk") || source.endsWith(".url")
3241 || source.endsWith(".site")))
3245 File lf = new File(files.get(f));
3246 // process link file to get a URL
3247 Cache.log.debug("Found potential link file: " + lf);
3248 WindowsShortcut wscfile = new WindowsShortcut(lf);
3249 String fullname = wscfile.getRealFilename();
3250 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3251 files.set(f, fullname);
3252 Cache.log.debug("Parsed real filename " + fullname
3253 + " to extract protocol: " + protocols.get(f));
3254 } catch (Exception ex)
3257 "Couldn't parse " + files.get(f) + " as a link file.",
3266 * Sets the Preferences property for experimental features to True or False
3267 * depending on the state of the controlling menu item
3270 protected void showExperimental_actionPerformed(boolean selected)
3272 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3276 * Answers a (possibly empty) list of any structure viewer frames (currently
3277 * for either Jmol or Chimera) which are currently open. This may optionally
3278 * be restricted to viewers of a specified class, or viewers linked to a
3279 * specified alignment panel.
3282 * if not null, only return viewers linked to this panel
3283 * @param structureViewerClass
3284 * if not null, only return viewers of this class
3287 public List<StructureViewerBase> getStructureViewers(
3288 AlignmentPanel apanel,
3289 Class<? extends StructureViewerBase> structureViewerClass)
3291 List<StructureViewerBase> result = new ArrayList<>();
3292 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3294 for (JInternalFrame frame : frames)
3296 if (frame instanceof StructureViewerBase)
3298 if (structureViewerClass == null
3299 || structureViewerClass.isInstance(frame))
3302 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3304 result.add((StructureViewerBase) frame);