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 java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.FontMetrics;
27 import java.awt.Graphics;
28 import java.awt.GridLayout;
29 import java.awt.Point;
30 import java.awt.Rectangle;
31 import java.awt.Toolkit;
32 import java.awt.Window;
33 import java.awt.datatransfer.Clipboard;
34 import java.awt.datatransfer.ClipboardOwner;
35 import java.awt.datatransfer.DataFlavor;
36 import java.awt.datatransfer.Transferable;
37 import java.awt.dnd.DnDConstants;
38 import java.awt.dnd.DropTargetDragEvent;
39 import java.awt.dnd.DropTargetDropEvent;
40 import java.awt.dnd.DropTargetEvent;
41 import java.awt.dnd.DropTargetListener;
42 import java.awt.event.ActionEvent;
43 import java.awt.event.ActionListener;
44 import java.awt.event.InputEvent;
45 import java.awt.event.KeyEvent;
46 import java.awt.event.MouseAdapter;
47 import java.awt.event.MouseEvent;
48 import java.awt.event.WindowAdapter;
49 import java.awt.event.WindowEvent;
50 import java.beans.PropertyChangeEvent;
51 import java.beans.PropertyChangeListener;
53 import java.io.FileWriter;
54 import java.io.IOException;
56 import java.util.ArrayList;
57 import java.util.HashMap;
58 import java.util.Hashtable;
59 import java.util.List;
60 import java.util.ListIterator;
61 import java.util.StringTokenizer;
62 import java.util.Vector;
63 import java.util.concurrent.ExecutorService;
64 import java.util.concurrent.Executors;
65 import java.util.concurrent.Semaphore;
67 import javax.swing.AbstractAction;
68 import javax.swing.Action;
69 import javax.swing.ActionMap;
70 import javax.swing.Box;
71 import javax.swing.BoxLayout;
72 import javax.swing.DefaultDesktopManager;
73 import javax.swing.DesktopManager;
74 import javax.swing.InputMap;
75 import javax.swing.JButton;
76 import javax.swing.JCheckBox;
77 import javax.swing.JComboBox;
78 import javax.swing.JComponent;
79 import javax.swing.JDesktopPane;
80 import javax.swing.JInternalFrame;
81 import javax.swing.JLabel;
82 import javax.swing.JMenuItem;
83 import javax.swing.JPanel;
84 import javax.swing.JPopupMenu;
85 import javax.swing.JProgressBar;
86 import javax.swing.KeyStroke;
87 import javax.swing.SwingUtilities;
88 import javax.swing.event.HyperlinkEvent;
89 import javax.swing.event.HyperlinkEvent.EventType;
90 import javax.swing.event.InternalFrameAdapter;
91 import javax.swing.event.InternalFrameEvent;
93 import org.stackoverflowusers.file.WindowsShortcut;
95 import jalview.api.AlignViewportI;
96 import jalview.api.AlignmentViewPanel;
97 import jalview.bin.Cache;
98 import jalview.bin.Jalview;
99 import jalview.io.BackupFiles;
100 import jalview.io.DataSourceType;
101 import jalview.io.FileFormat;
102 import jalview.io.FileFormatException;
103 import jalview.io.FileFormatI;
104 import jalview.io.FileFormats;
105 import jalview.io.FileLoader;
106 import jalview.io.FormatAdapter;
107 import jalview.io.IdentifyFile;
108 import jalview.io.JalviewFileChooser;
109 import jalview.io.JalviewFileView;
110 import jalview.jbgui.GSplitFrame;
111 import jalview.jbgui.GStructureViewer;
112 import jalview.project.Jalview2XML;
113 import jalview.structure.StructureSelectionManager;
114 import jalview.urls.IdOrgSettings;
115 import jalview.util.ImageMaker;
116 import jalview.util.MessageManager;
117 import jalview.util.Platform;
118 import jalview.util.UrlConstants;
119 import jalview.viewmodel.AlignmentViewport;
120 import jalview.ws.params.ParamManager;
121 import jalview.ws.utils.UrlDownloadClient;
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();
372 addWindowListener(new WindowAdapter()
376 public void windowClosing(WindowEvent ev)
382 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
385 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
387 desktop = new MyDesktopPane(selmemusage);
388 showMemusage.setSelected(selmemusage);
389 desktop.setBackground(Color.white);
391 getContentPane().setLayout(new BorderLayout());
392 // alternate config - have scrollbars - see notes in JAL-153
393 // JScrollPane sp = new JScrollPane();
394 // sp.getViewport().setView(desktop);
395 // getContentPane().add(sp, BorderLayout.CENTER);
396 getContentPane().add(desktop, BorderLayout.CENTER);
397 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
399 // This line prevents Windows Look&Feel resizing all new windows to maximum
400 // if previous window was maximised
401 desktop.setDesktopManager(new MyDesktopManager(
402 (Platform.isWindows() ? new DefaultDesktopManager()
404 ? new AquaInternalFrameManager(
405 desktop.getDesktopManager())
406 : desktop.getDesktopManager())));
408 Rectangle dims = getLastKnownDimensions("");
415 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
416 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
419 jconsole = new Console(this, showjconsole);
420 // add essential build information
421 jconsole.setHeader(jalview.bin.Cache.getVersionDetailsForConsole());
423 showConsole(showjconsole);
425 showNews.setVisible(false);
427 experimentalFeatures.setSelected(showExperimental());
429 getIdentifiersOrgData();
433 this.addWindowListener(new WindowAdapter()
436 public void windowClosing(WindowEvent evt)
443 this.addMouseListener(ma = new MouseAdapter()
446 public void mousePressed(MouseEvent evt)
448 if (evt.isPopupTrigger()) // Mac
450 showPasteMenu(evt.getX(), evt.getY());
455 public void mouseReleased(MouseEvent evt)
457 if (evt.isPopupTrigger()) // Windows
459 showPasteMenu(evt.getX(), evt.getY());
463 desktop.addMouseListener(ma);
465 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
466 // Spawn a thread that shows the splashscreen
467 SwingUtilities.invokeLater(new Runnable()
476 // Thread off a new instance of the file chooser - this reduces the time it
477 // takes to open it later on.
478 new Thread(new Runnable()
483 Cache.log.debug("Filechooser init thread started.");
484 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
485 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
487 Cache.log.debug("Filechooser init thread finished.");
490 // Add the service change listener
491 changeSupport.addJalviewPropertyChangeListener("services",
492 new PropertyChangeListener()
496 public void propertyChange(PropertyChangeEvent evt)
498 Cache.log.debug("Firing service changed event for "
499 + evt.getNewValue());
500 JalviewServicesChanged(evt);
507 * Answers true if user preferences to enable experimental features is True
512 public boolean showExperimental()
514 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
515 Boolean.FALSE.toString());
516 return Boolean.valueOf(experimental).booleanValue();
519 public void doConfigureStructurePrefs()
521 // configure services
522 StructureSelectionManager ssm = StructureSelectionManager
523 .getStructureSelectionManager(this);
524 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
526 ssm.setAddTempFacAnnot(jalview.bin.Cache
527 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
528 ssm.setProcessSecondaryStructure(jalview.bin.Cache
529 .getDefault(Preferences.STRUCT_FROM_PDB, true));
530 ssm.setSecStructServices(
531 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
535 ssm.setAddTempFacAnnot(false);
536 ssm.setProcessSecondaryStructure(false);
537 ssm.setSecStructServices(false);
541 public void checkForNews()
543 final Desktop me = this;
544 // Thread off the news reader, in case there are connection problems.
545 new Thread(new Runnable()
550 Cache.log.debug("Starting news thread.");
552 jvnews = new BlogReader(me);
553 showNews.setVisible(true);
554 Cache.log.debug("Completed news thread.");
559 public void getIdentifiersOrgData()
561 // Thread off the identifiers fetcher
562 new Thread(new Runnable()
567 Cache.log.debug("Downloading data from identifiers.org");
568 UrlDownloadClient client = new UrlDownloadClient();
571 client.download(IdOrgSettings.getUrl(),
572 IdOrgSettings.getDownloadLocation());
573 } catch (IOException e)
575 Cache.log.debug("Exception downloading identifiers.org data"
584 protected void showNews_actionPerformed(ActionEvent e)
586 showNews(showNews.isSelected());
589 void showNews(boolean visible)
592 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
593 showNews.setSelected(visible);
594 if (visible && !jvnews.isVisible())
596 new Thread(new Runnable()
601 long now = System.currentTimeMillis();
602 Desktop.instance.setProgressBar(
603 MessageManager.getString("status.refreshing_news"),
605 jvnews.refreshNews();
606 Desktop.instance.setProgressBar(null, now);
615 * recover the last known dimensions for a jalview window
618 * - empty string is desktop, all other windows have unique prefix
619 * @return null or last known dimensions scaled to current geometry (if last
620 * window geom was known)
622 Rectangle getLastKnownDimensions(String windowName)
624 // TODO: lock aspect ratio for scaling desktop Bug #0058199
625 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
626 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
627 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
628 String width = jalview.bin.Cache
629 .getProperty(windowName + "SCREEN_WIDTH");
630 String height = jalview.bin.Cache
631 .getProperty(windowName + "SCREEN_HEIGHT");
632 if ((x != null) && (y != null) && (width != null) && (height != null))
634 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
635 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
636 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
638 // attempt #1 - try to cope with change in screen geometry - this
639 // version doesn't preserve original jv aspect ratio.
640 // take ratio of current screen size vs original screen size.
641 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
642 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
643 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
644 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
645 // rescale the bounds depending upon the current screen geometry.
646 ix = (int) (ix * sw);
647 iw = (int) (iw * sw);
648 iy = (int) (iy * sh);
649 ih = (int) (ih * sh);
650 while (ix >= screenSize.width)
652 jalview.bin.Cache.log.debug(
653 "Window geometry location recall error: shifting horizontal to within screenbounds.");
654 ix -= screenSize.width;
656 while (iy >= screenSize.height)
658 jalview.bin.Cache.log.debug(
659 "Window geometry location recall error: shifting vertical to within screenbounds.");
660 iy -= screenSize.height;
662 jalview.bin.Cache.log.debug(
663 "Got last known dimensions for " + windowName + ": x:" + ix
664 + " y:" + iy + " width:" + iw + " height:" + ih);
666 // return dimensions for new instance
667 return new Rectangle(ix, iy, iw, ih);
672 void showPasteMenu(int x, int y)
674 JPopupMenu popup = new JPopupMenu();
675 JMenuItem item = new JMenuItem(
676 MessageManager.getString("label.paste_new_window"));
677 item.addActionListener(new ActionListener()
680 public void actionPerformed(ActionEvent evt)
687 popup.show(this, x, y);
694 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
695 Transferable contents = c.getContents(this);
697 if (contents != null)
699 String file = (String) contents
700 .getTransferData(DataFlavor.stringFlavor);
702 FileFormatI format = new IdentifyFile().identify(file,
703 DataSourceType.PASTE);
705 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
708 } catch (Exception ex)
711 "Unable to paste alignment from system clipboard:\n" + ex);
716 * Adds and opens the given frame to the desktop
727 public static synchronized void addInternalFrame(
728 final JInternalFrame frame, String title, int w, int h)
730 addInternalFrame(frame, title, true, w, h, true, false);
734 * Add an internal frame to the Jalview desktop
741 * When true, display frame immediately, otherwise, caller must call
742 * setVisible themselves.
748 public static synchronized void addInternalFrame(
749 final JInternalFrame frame, String title, boolean makeVisible,
752 addInternalFrame(frame, title, makeVisible, w, h, true, false);
756 * Add an internal frame to the Jalview desktop and make it visible
769 public static synchronized void addInternalFrame(
770 final JInternalFrame frame, String title, int w, int h,
773 addInternalFrame(frame, title, true, w, h, resizable, false);
777 * Add an internal frame to the Jalview desktop
784 * When true, display frame immediately, otherwise, caller must call
785 * setVisible themselves.
792 * @param ignoreMinSize
793 * Do not set the default minimum size for frame
795 public static synchronized void addInternalFrame(
796 final JInternalFrame frame, String title, boolean makeVisible,
797 int w, int h, boolean resizable, boolean ignoreMinSize)
800 // TODO: allow callers to determine X and Y position of frame (eg. via
802 // TODO: consider fixing method to update entries in the window submenu with
803 // the current window title
805 frame.setTitle(title);
806 if (frame.getWidth() < 1 || frame.getHeight() < 1)
810 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
811 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
812 // IF JALVIEW IS RUNNING HEADLESS
813 // ///////////////////////////////////////////////
814 if (instance == null || (System.getProperty("java.awt.headless") != null
815 && System.getProperty("java.awt.headless").equals("true")))
824 frame.setMinimumSize(
825 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
827 // Set default dimension for Alignment Frame window.
828 // The Alignment Frame window could be added from a number of places,
830 // I did this here in order not to miss out on any Alignment frame.
831 if (frame instanceof AlignFrame)
833 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
834 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
838 frame.setVisible(makeVisible);
839 frame.setClosable(true);
840 frame.setResizable(resizable);
841 frame.setMaximizable(resizable);
842 frame.setIconifiable(resizable);
843 frame.setOpaque(false);
845 if (frame.getX() < 1 && frame.getY() < 1)
847 frame.setLocation(xOffset * openFrameCount,
848 yOffset * ((openFrameCount - 1) % 10) + yOffset);
852 * add an entry for the new frame in the Window menu
853 * (and remove it when the frame is closed)
855 final JMenuItem menuItem = new JMenuItem(title);
856 frame.addInternalFrameListener(new InternalFrameAdapter()
859 public void internalFrameActivated(InternalFrameEvent evt)
861 JInternalFrame itf = desktop.getSelectedFrame();
864 if (itf instanceof AlignFrame)
866 Jalview.setCurrentAlignFrame((AlignFrame) itf);
873 public void internalFrameClosed(InternalFrameEvent evt)
875 PaintRefresher.RemoveComponent(frame);
878 * defensive check to prevent frames being
879 * added half off the window
881 if (openFrameCount > 0)
887 * ensure no reference to alignFrame retained by menu item listener
889 if (menuItem.getActionListeners().length > 0)
891 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
893 windowMenu.remove(menuItem);
897 menuItem.addActionListener(new ActionListener()
900 public void actionPerformed(ActionEvent e)
904 frame.setSelected(true);
905 frame.setIcon(false);
906 } catch (java.beans.PropertyVetoException ex)
913 setKeyBindings(frame);
917 windowMenu.add(menuItem);
922 frame.setSelected(true);
923 frame.requestFocus();
924 } catch (java.beans.PropertyVetoException ve)
926 } catch (java.lang.ClassCastException cex)
929 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
935 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
940 private static void setKeyBindings(JInternalFrame frame)
942 @SuppressWarnings("serial")
943 final Action closeAction = new AbstractAction()
946 public void actionPerformed(ActionEvent e)
953 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
955 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
956 InputEvent.CTRL_DOWN_MASK);
957 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
958 jalview.util.ShortcutKeyMaskExWrapper
959 .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.forRead(
1073 Cache.getProperty("LAST_DIRECTORY"), fileFormat,
1074 BackupFiles.getEnabled());
1076 chooser.setFileView(new JalviewFileView());
1077 chooser.setDialogTitle(
1078 MessageManager.getString("label.open_local_file"));
1079 chooser.setToolTipText(MessageManager.getString("action.open"));
1081 int value = chooser.showOpenDialog(this);
1083 if (value == JalviewFileChooser.APPROVE_OPTION)
1085 String choice = chooser.getSelectedFile().getPath();
1086 Cache.setProperty("LAST_DIRECTORY",
1087 chooser.getSelectedFile().getParent());
1089 FileFormatI format = chooser.getSelectedFormat();
1092 * Call IdentifyFile to verify the file contains what its extension implies.
1093 * Skip this step for dynamically added file formats, because
1094 * IdentifyFile does not know how to recognise them.
1096 if (FileFormats.getInstance().isIdentifiable(format))
1100 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1101 } catch (FileFormatException e)
1103 // format = null; //??
1107 if (viewport != null)
1109 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1114 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1126 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1128 // This construct allows us to have a wider textfield
1130 JLabel label = new JLabel(
1131 MessageManager.getString("label.input_file_url"));
1132 final JComboBox history = new JComboBox();
1134 JPanel panel = new JPanel(new GridLayout(2, 1));
1137 history.setPreferredSize(new Dimension(400, 20));
1138 history.setEditable(true);
1139 history.addItem("http://www.");
1141 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1145 if (historyItems != null)
1147 st = new StringTokenizer(historyItems, "\t");
1149 while (st.hasMoreTokens())
1151 history.addItem(st.nextElement());
1155 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1156 MessageManager.getString("label.input_alignment_from_url"),
1157 JvOptionPane.OK_CANCEL_OPTION);
1159 if (reply != JvOptionPane.OK_OPTION)
1164 String url = history.getSelectedItem().toString();
1166 if (url.toLowerCase().endsWith(".jar"))
1168 if (viewport != null)
1170 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1171 FileFormat.Jalview);
1175 new FileLoader().LoadFile(url, DataSourceType.URL,
1176 FileFormat.Jalview);
1181 FileFormatI format = null;
1184 format = new IdentifyFile().identify(url, DataSourceType.URL);
1185 } catch (FileFormatException e)
1187 // TODO revise error handling, distinguish between
1188 // URL not found and response not valid
1193 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1194 MessageManager.formatMessage("label.couldnt_locate",
1197 MessageManager.getString("label.url_not_found"),
1198 JvOptionPane.WARNING_MESSAGE);
1203 if (viewport != null)
1205 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1210 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1216 * Opens the CutAndPaste window for the user to paste an alignment in to
1219 * - if not null, the pasted alignment is added to the current
1220 * alignment; if null, to a new alignment window
1223 public void inputTextboxMenuItem_actionPerformed(
1224 AlignmentViewPanel viewPanel)
1226 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1227 cap.setForInput(viewPanel);
1228 Desktop.addInternalFrame(cap,
1229 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1239 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1240 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1242 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1243 screen.height + "");
1244 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1245 getWidth(), getHeight()));
1247 if (jconsole != null)
1249 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1250 jconsole.stopConsole();
1254 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1257 if (dialogExecutor != null)
1259 dialogExecutor.shutdownNow();
1261 closeAll_actionPerformed(null);
1263 if (groovyConsole != null)
1265 // suppress a possible repeat prompt to save script
1266 groovyConsole.setDirty(false);
1267 groovyConsole.exit();
1272 private void storeLastKnownDimensions(String string, Rectangle jc)
1274 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1275 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1276 + " height:" + jc.height);
1278 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1279 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1280 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1281 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1291 public void aboutMenuItem_actionPerformed(ActionEvent e)
1293 // StringBuffer message = getAboutMessage(false);
1294 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1296 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1297 new Thread(new Runnable()
1302 new SplashScreen(true);
1307 public StringBuffer getAboutMessage(boolean shortv)
1309 StringBuffer message = new StringBuffer();
1310 message.append("<html>");
1313 message.append("<h1><strong>Version: "
1314 + jalview.bin.Cache.getProperty("VERSION")
1315 + "</strong></h1>");
1316 message.append("<strong>Built: <em>"
1317 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1318 + "</em> from " + jalview.bin.Cache.getBuildDetailsForSplash()
1325 message.append("<strong>Version "
1326 + jalview.bin.Cache.getProperty("VERSION")
1327 + "; last updated: "
1328 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1331 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1332 .equals("Checking"))
1334 // JBP removed this message for 2.11: May be reinstated in future version
1335 // message.append("<br>...Checking latest version...</br>");
1337 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1338 .equals(jalview.bin.Cache.getProperty("VERSION")))
1340 boolean red = false;
1341 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1342 .indexOf("automated build") == -1)
1345 // Displayed when code version and jnlp version do not match and code
1346 // version is not a development build
1347 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1350 message.append("<br>!! Version "
1351 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1353 + " is available for download from "
1354 + jalview.bin.Cache.getDefault("www.jalview.org",
1355 "http://www.jalview.org")
1359 message.append("</div>");
1362 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1364 "The Jalview Authors (See AUTHORS file for current list)")
1365 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1366 + "<br><br>For help, see the FAQ at <a href=\"http://www.jalview.org/faq\">www.jalview.org/faq</a> and/or join the jalview-discuss@jalview.org mailing list"
1367 + "<br><br>If you use Jalview, please cite:"
1368 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1369 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1370 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1382 public void documentationMenuItem_actionPerformed(ActionEvent e)
1386 Help.showHelpWindow();
1387 } catch (Exception ex)
1393 public void closeAll_actionPerformed(ActionEvent e)
1395 // TODO show a progress bar while closing?
1396 JInternalFrame[] frames = desktop.getAllFrames();
1397 for (int i = 0; i < frames.length; i++)
1401 frames[i].setClosed(true);
1402 } catch (java.beans.PropertyVetoException ex)
1406 Jalview.setCurrentAlignFrame(null);
1407 System.out.println("ALL CLOSED");
1410 * reset state of singleton objects as appropriate (clear down session state
1411 * when all windows are closed)
1413 StructureSelectionManager ssm = StructureSelectionManager
1414 .getStructureSelectionManager(this);
1422 public void raiseRelated_actionPerformed(ActionEvent e)
1424 reorderAssociatedWindows(false, false);
1428 public void minimizeAssociated_actionPerformed(ActionEvent e)
1430 reorderAssociatedWindows(true, false);
1433 void closeAssociatedWindows()
1435 reorderAssociatedWindows(false, true);
1441 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1445 protected void garbageCollect_actionPerformed(ActionEvent e)
1447 // We simply collect the garbage
1448 jalview.bin.Cache.log.debug("Collecting garbage...");
1450 jalview.bin.Cache.log.debug("Finished garbage collection.");
1457 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1461 protected void showMemusage_actionPerformed(ActionEvent e)
1463 desktop.showMemoryUsage(showMemusage.isSelected());
1470 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1474 protected void showConsole_actionPerformed(ActionEvent e)
1476 showConsole(showConsole.isSelected());
1479 Console jconsole = null;
1482 * control whether the java console is visible or not
1486 void showConsole(boolean selected)
1488 showConsole.setSelected(selected);
1489 // TODO: decide if we should update properties file
1490 Cache.setProperty("SHOW_JAVA_CONSOLE",
1491 Boolean.valueOf(selected).toString());
1492 jconsole.setVisible(selected);
1495 void reorderAssociatedWindows(boolean minimize, boolean close)
1497 JInternalFrame[] frames = desktop.getAllFrames();
1498 if (frames == null || frames.length < 1)
1503 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)
1581 Preferences.openPreferences();
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
1703 chooser.setFileView(new JalviewFileView());
1704 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1706 int value = chooser.showOpenDialog(this);
1708 if (value == JalviewFileChooser.APPROVE_OPTION)
1710 final File selectedFile = chooser.getSelectedFile();
1711 setProjectFile(selectedFile);
1712 final String choice = selectedFile.getAbsolutePath();
1713 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1714 new Thread(new Runnable()
1719 setProgressBar(MessageManager.formatMessage(
1720 "label.loading_jalview_project", new Object[]
1721 { choice }), choice.hashCode());
1724 new Jalview2XML().loadJalviewAlign(choice);
1725 } catch (OutOfMemoryError oom)
1727 new OOMWarning("Whilst loading project from " + choice, oom);
1728 } catch (Exception ex)
1731 "Problems whilst loading project from " + choice, ex);
1732 JvOptionPane.showMessageDialog(Desktop.desktop,
1733 MessageManager.formatMessage(
1734 "label.error_whilst_loading_project_from",
1737 MessageManager.getString("label.couldnt_load_project"),
1738 JvOptionPane.WARNING_MESSAGE);
1740 setProgressBar(null, choice.hashCode());
1747 public void inputSequence_actionPerformed(ActionEvent e)
1749 new SequenceFetcher(this);
1752 JPanel progressPanel;
1754 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1756 public void startLoading(final String fileName)
1758 if (fileLoadingCount == 0)
1760 fileLoadingPanels.add(addProgressPanel(MessageManager
1761 .formatMessage("label.loading_file", new Object[]
1767 private JPanel addProgressPanel(String string)
1769 if (progressPanel == null)
1771 progressPanel = new JPanel(new GridLayout(1, 1));
1772 totalProgressCount = 0;
1773 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1775 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1776 JProgressBar progressBar = new JProgressBar();
1777 progressBar.setIndeterminate(true);
1779 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1781 thisprogress.add(progressBar, BorderLayout.CENTER);
1782 progressPanel.add(thisprogress);
1783 ((GridLayout) progressPanel.getLayout()).setRows(
1784 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1785 ++totalProgressCount;
1786 instance.validate();
1787 return thisprogress;
1790 int totalProgressCount = 0;
1792 private void removeProgressPanel(JPanel progbar)
1794 if (progressPanel != null)
1796 synchronized (progressPanel)
1798 progressPanel.remove(progbar);
1799 GridLayout gl = (GridLayout) progressPanel.getLayout();
1800 gl.setRows(gl.getRows() - 1);
1801 if (--totalProgressCount < 1)
1803 this.getContentPane().remove(progressPanel);
1804 progressPanel = null;
1811 public void stopLoading()
1814 if (fileLoadingCount < 1)
1816 while (fileLoadingPanels.size() > 0)
1818 removeProgressPanel(fileLoadingPanels.remove(0));
1820 fileLoadingPanels.clear();
1821 fileLoadingCount = 0;
1826 public static int getViewCount(String alignmentId)
1828 AlignmentViewport[] aps = getViewports(alignmentId);
1829 return (aps == null) ? 0 : aps.length;
1834 * @param alignmentId
1835 * - if null, all sets are returned
1836 * @return all AlignmentPanels concerning the alignmentId sequence set
1838 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1840 if (Desktop.desktop == null)
1842 // no frames created and in headless mode
1843 // TODO: verify that frames are recoverable when in headless mode
1846 List<AlignmentPanel> aps = new ArrayList<>();
1847 AlignFrame[] frames = getAlignFrames();
1852 for (AlignFrame af : frames)
1854 for (AlignmentPanel ap : af.alignPanels)
1856 if (alignmentId == null
1857 || alignmentId.equals(ap.av.getSequenceSetId()))
1863 if (aps.size() == 0)
1867 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1872 * get all the viewports on an alignment.
1874 * @param sequenceSetId
1875 * unique alignment id (may be null - all viewports returned in that
1877 * @return all viewports on the alignment bound to sequenceSetId
1879 public static AlignmentViewport[] getViewports(String sequenceSetId)
1881 List<AlignmentViewport> viewp = new ArrayList<>();
1882 if (desktop != null)
1884 AlignFrame[] frames = Desktop.getAlignFrames();
1886 for (AlignFrame afr : frames)
1888 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1889 .equals(sequenceSetId))
1891 if (afr.alignPanels != null)
1893 for (AlignmentPanel ap : afr.alignPanels)
1895 if (sequenceSetId == null
1896 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1904 viewp.add(afr.getViewport());
1908 if (viewp.size() > 0)
1910 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1917 * Explode the views in the given frame into separate AlignFrame
1921 public static void explodeViews(AlignFrame af)
1923 int size = af.alignPanels.size();
1929 // FIXME: ideally should use UI interface API
1930 FeatureSettings viewFeatureSettings = (af.featureSettings != null
1931 && af.featureSettings.isOpen()) ? af.featureSettings : null;
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
1966 // (closes the old as if 'OK' was pressed)
1967 if (ap == af.alignPanel && newaf.featureSettings != null
1968 && newaf.featureSettings.isOpen()
1969 && af.alignPanel.getAlignViewport().isShowSequenceFeatures())
1971 newaf.showFeatureSettingsUI();
1975 af.featureSettings = null;
1976 af.alignPanels.clear();
1977 af.closeMenuItem_actionPerformed(true);
1982 * Gather expanded views (separate AlignFrame's) with the same sequence set
1983 * identifier back in to this frame as additional views, and close the
1984 * expanded views. Note the expanded frames may themselves have multiple
1985 * views. We take the lot.
1989 public void gatherViews(AlignFrame source)
1991 source.viewport.setGatherViewsHere(true);
1992 source.viewport.setExplodedGeometry(source.getBounds());
1993 JInternalFrame[] frames = desktop.getAllFrames();
1994 String viewId = source.viewport.getSequenceSetId();
1995 for (int t = 0; t < frames.length; t++)
1997 if (frames[t] instanceof AlignFrame && frames[t] != source)
1999 AlignFrame af = (AlignFrame) frames[t];
2000 boolean gatherThis = false;
2001 for (int a = 0; a < af.alignPanels.size(); a++)
2003 AlignmentPanel ap = af.alignPanels.get(a);
2004 if (viewId.equals(ap.av.getSequenceSetId()))
2007 ap.av.setGatherViewsHere(false);
2008 ap.av.setExplodedGeometry(af.getBounds());
2009 source.addAlignmentPanel(ap, false);
2015 if (af.featureSettings != null && af.featureSettings.isOpen())
2017 if (source.featureSettings == null)
2019 // preserve the feature settings geometry for this frame
2020 source.featureSettings = af.featureSettings;
2021 source.setFeatureSettingsGeometry(
2022 af.getFeatureSettingsGeometry());
2026 // close it and forget
2027 af.featureSettings.close();
2030 af.alignPanels.clear();
2031 af.closeMenuItem_actionPerformed(true);
2035 // refresh the feature setting UI for the source frame if it exists
2036 if (source.featureSettings != null && 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()
2391 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
2393 .getKeyStroke(KeyEvent.VK_Q,
2394 jalview.util.ShortcutKeyMaskExWrapper
2395 .getMenuShortcutKeyMaskEx()),
2397 getRootPane().getActionMap().put("Quit", new AbstractAction()
2400 public void actionPerformed(ActionEvent e)
2408 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2411 * true if Groovy console is open
2413 public void enableExecuteGroovy(boolean enabled)
2416 * disable opening a second Groovy console
2417 * (or re-enable when the console is closed)
2419 groovyShell.setEnabled(!enabled);
2421 AlignFrame[] alignFrames = getAlignFrames();
2422 if (alignFrames != null)
2424 for (AlignFrame af : alignFrames)
2426 af.setGroovyEnabled(enabled);
2432 * Progress bars managed by the IProgressIndicator method.
2434 private Hashtable<Long, JPanel> progressBars;
2436 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2441 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2444 public void setProgressBar(String message, long id)
2446 if (progressBars == null)
2448 progressBars = new Hashtable<>();
2449 progressBarHandlers = new Hashtable<>();
2452 if (progressBars.get(Long.valueOf(id)) != null)
2454 JPanel panel = progressBars.remove(Long.valueOf(id));
2455 if (progressBarHandlers.contains(Long.valueOf(id)))
2457 progressBarHandlers.remove(Long.valueOf(id));
2459 removeProgressPanel(panel);
2463 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2470 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2471 * jalview.gui.IProgressIndicatorHandler)
2474 public void registerHandler(final long id,
2475 final IProgressIndicatorHandler handler)
2477 if (progressBarHandlers == null
2478 || !progressBars.containsKey(Long.valueOf(id)))
2480 throw new Error(MessageManager.getString(
2481 "error.call_setprogressbar_before_registering_handler"));
2483 progressBarHandlers.put(Long.valueOf(id), handler);
2484 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2485 if (handler.canCancel())
2487 JButton cancel = new JButton(
2488 MessageManager.getString("action.cancel"));
2489 final IProgressIndicator us = this;
2490 cancel.addActionListener(new ActionListener()
2494 public void actionPerformed(ActionEvent e)
2496 handler.cancelActivity(id);
2497 us.setProgressBar(MessageManager
2498 .formatMessage("label.cancelled_params", new Object[]
2499 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2503 progressPanel.add(cancel, BorderLayout.EAST);
2509 * @return true if any progress bars are still active
2512 public boolean operationInProgress()
2514 if (progressBars != null && progressBars.size() > 0)
2522 * This will return the first AlignFrame holding the given viewport instance.
2523 * It will break if there are more than one AlignFrames viewing a particular
2527 * @return alignFrame for viewport
2529 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2531 if (desktop != null)
2533 AlignmentPanel[] aps = getAlignmentPanels(
2534 viewport.getSequenceSetId());
2535 for (int panel = 0; aps != null && panel < aps.length; panel++)
2537 if (aps[panel] != null && aps[panel].av == viewport)
2539 return aps[panel].alignFrame;
2546 public VamsasApplication getVamsasApplication()
2548 // TODO: JAL-3311 remove remaining code from Jalview relating to VAMSAS
2554 * flag set if jalview GUI is being operated programmatically
2556 private boolean inBatchMode = false;
2559 * check if jalview GUI is being operated programmatically
2561 * @return inBatchMode
2563 public boolean isInBatchMode()
2569 * set flag if jalview GUI is being operated programmatically
2571 * @param inBatchMode
2573 public void setInBatchMode(boolean inBatchMode)
2575 this.inBatchMode = inBatchMode;
2578 public void startServiceDiscovery()
2580 startServiceDiscovery(false);
2583 public void startServiceDiscovery(boolean blocking)
2585 boolean alive = true;
2586 Thread t0 = null, t1 = null, t2 = null;
2587 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2590 // todo: changesupport handlers need to be transferred
2591 if (discoverer == null)
2593 discoverer = new jalview.ws.jws1.Discoverer();
2594 // register PCS handler for desktop.
2595 discoverer.addPropertyChangeListener(changeSupport);
2597 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2598 // until we phase out completely
2599 (t0 = new Thread(discoverer)).start();
2602 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2604 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2605 .startDiscoverer(changeSupport);
2609 // TODO: do rest service discovery
2618 } catch (Exception e)
2621 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2622 || (t3 != null && t3.isAlive())
2623 || (t0 != null && t0.isAlive());
2629 * called to check if the service discovery process completed successfully.
2633 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2635 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2637 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2638 .getErrorMessages();
2641 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2643 if (serviceChangedDialog == null)
2645 // only run if we aren't already displaying one of these.
2646 addDialogThread(serviceChangedDialog = new Runnable()
2653 * JalviewDialog jd =new JalviewDialog() {
2655 * @Override protected void cancelPressed() { // TODO
2656 * Auto-generated method stub
2658 * }@Override protected void okPressed() { // TODO
2659 * Auto-generated method stub
2661 * }@Override protected void raiseClosed() { // TODO
2662 * Auto-generated method stub
2664 * } }; jd.initDialogFrame(new
2665 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2666 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2667 * + " or mis-configured HTTP proxy settings.<br/>" +
2668 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2670 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2671 * ), true, true, "Web Service Configuration Problem", 450,
2674 * jd.waitForInput();
2676 JvOptionPane.showConfirmDialog(Desktop.desktop,
2677 new JLabel("<html><table width=\"450\"><tr><td>"
2678 + ermsg + "</td></tr></table>"
2679 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
2680 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
2681 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
2682 + " Tools->Preferences dialog box to change them.</p></html>"),
2683 "Web Service Configuration Problem",
2684 JvOptionPane.DEFAULT_OPTION,
2685 JvOptionPane.ERROR_MESSAGE);
2686 serviceChangedDialog = null;
2695 "Errors reported by JABA discovery service. Check web services preferences.\n"
2702 private Runnable serviceChangedDialog = null;
2705 * start a thread to open a URL in the configured browser. Pops up a warning
2706 * dialog to the user if there is an exception when calling out to the browser
2711 public static void showUrl(final String url)
2713 showUrl(url, Desktop.instance);
2717 * Like showUrl but allows progress handler to be specified
2721 * (null) or object implementing IProgressIndicator
2723 public static void showUrl(final String url,
2724 final IProgressIndicator progress)
2726 new Thread(new Runnable()
2733 if (progress != null)
2735 progress.setProgressBar(MessageManager
2736 .formatMessage("status.opening_params", new Object[]
2737 { url }), this.hashCode());
2739 jalview.util.BrowserLauncher.openURL(url);
2740 } catch (Exception ex)
2742 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2744 .getString("label.web_browser_not_found_unix"),
2745 MessageManager.getString("label.web_browser_not_found"),
2746 JvOptionPane.WARNING_MESSAGE);
2748 ex.printStackTrace();
2750 if (progress != null)
2752 progress.setProgressBar(null, this.hashCode());
2758 public static WsParamSetManager wsparamManager = null;
2760 public static ParamManager getUserParameterStore()
2762 if (wsparamManager == null)
2764 wsparamManager = new WsParamSetManager();
2766 return wsparamManager;
2770 * static hyperlink handler proxy method for use by Jalview's internal windows
2774 public static void hyperlinkUpdate(HyperlinkEvent e)
2776 if (e.getEventType() == EventType.ACTIVATED)
2781 url = e.getURL().toString();
2782 Desktop.showUrl(url);
2783 } catch (Exception x)
2787 if (Cache.log != null)
2789 Cache.log.error("Couldn't handle string " + url + " as a URL.");
2794 "Couldn't handle string " + url + " as a URL.");
2797 // ignore any exceptions due to dud links.
2804 * single thread that handles display of dialogs to user.
2806 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
2809 * flag indicating if dialogExecutor should try to acquire a permit
2811 private volatile boolean dialogPause = true;
2816 private java.util.concurrent.Semaphore block = new Semaphore(0);
2818 private static groovy.ui.Console groovyConsole;
2821 * add another dialog thread to the queue
2825 public void addDialogThread(final Runnable prompter)
2827 dialogExecutor.submit(new Runnable()
2837 } catch (InterruptedException x)
2842 if (instance == null)
2848 SwingUtilities.invokeAndWait(prompter);
2849 } catch (Exception q)
2851 Cache.log.warn("Unexpected Exception in dialog thread.", q);
2857 public void startDialogQueue()
2859 // set the flag so we don't pause waiting for another permit and semaphore
2860 // the current task to begin
2861 dialogPause = false;
2866 protected void snapShotWindow_actionPerformed(ActionEvent e)
2870 ImageMaker im = new jalview.util.ImageMaker(
2871 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
2872 getHeight(), of = new File("Jalview_snapshot"
2873 + System.currentTimeMillis() + ".eps"),
2874 "View of desktop", null, 0, false);
2877 paintAll(im.getGraphics());
2879 } catch (Exception q)
2881 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
2885 Cache.log.info("Successfully written snapshot to file "
2886 + of.getAbsolutePath());
2890 * Explode the views in the given SplitFrame into separate SplitFrame windows.
2891 * This respects (remembers) any previous 'exploded geometry' i.e. the size
2892 * and location last time the view was expanded (if any). However it does not
2893 * remember the split pane divider location - this is set to match the
2894 * 'exploding' frame.
2898 public void explodeViews(SplitFrame sf)
2900 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
2901 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
2902 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
2904 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
2906 int viewCount = topPanels.size();
2913 * Processing in reverse order works, forwards order leaves the first panels
2914 * not visible. I don't know why!
2916 for (int i = viewCount - 1; i >= 0; i--)
2919 * Make new top and bottom frames. These take over the respective
2920 * AlignmentPanel objects, including their AlignmentViewports, so the
2921 * cdna/protein relationships between the viewports is carried over to the
2924 * explodedGeometry holds the (x, y) position of the previously exploded
2925 * SplitFrame, and the (width, height) of the AlignFrame component
2927 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
2928 AlignFrame newTopFrame = new AlignFrame(topPanel);
2929 newTopFrame.setSize(oldTopFrame.getSize());
2930 newTopFrame.setVisible(true);
2931 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
2932 .getExplodedGeometry();
2933 if (geometry != null)
2935 newTopFrame.setSize(geometry.getSize());
2938 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
2939 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
2940 newBottomFrame.setSize(oldBottomFrame.getSize());
2941 newBottomFrame.setVisible(true);
2942 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
2943 .getExplodedGeometry();
2944 if (geometry != null)
2946 newBottomFrame.setSize(geometry.getSize());
2949 topPanel.av.setGatherViewsHere(false);
2950 bottomPanel.av.setGatherViewsHere(false);
2951 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
2953 if (geometry != null)
2955 splitFrame.setLocation(geometry.getLocation());
2957 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
2961 * Clear references to the panels (now relocated in the new SplitFrames)
2962 * before closing the old SplitFrame.
2965 bottomPanels.clear();
2970 * Gather expanded split frames, sharing the same pairs of sequence set ids,
2971 * back into the given SplitFrame as additional views. Note that the gathered
2972 * frames may themselves have multiple views.
2976 public void gatherViews(GSplitFrame source)
2979 * special handling of explodedGeometry for a view within a SplitFrame: - it
2980 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
2981 * height) of the AlignFrame component
2983 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
2984 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
2985 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
2986 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
2987 myBottomFrame.viewport
2988 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
2989 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
2990 myTopFrame.viewport.setGatherViewsHere(true);
2991 myBottomFrame.viewport.setGatherViewsHere(true);
2992 String topViewId = myTopFrame.viewport.getSequenceSetId();
2993 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
2995 JInternalFrame[] frames = desktop.getAllFrames();
2996 for (JInternalFrame frame : frames)
2998 if (frame instanceof SplitFrame && frame != source)
3000 SplitFrame sf = (SplitFrame) frame;
3001 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3002 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3003 boolean gatherThis = false;
3004 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3006 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3007 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3008 if (topViewId.equals(topPanel.av.getSequenceSetId())
3009 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3012 topPanel.av.setGatherViewsHere(false);
3013 bottomPanel.av.setGatherViewsHere(false);
3014 topPanel.av.setExplodedGeometry(
3015 new Rectangle(sf.getLocation(), topFrame.getSize()));
3016 bottomPanel.av.setExplodedGeometry(
3017 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3018 myTopFrame.addAlignmentPanel(topPanel, false);
3019 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3025 topFrame.getAlignPanels().clear();
3026 bottomFrame.getAlignPanels().clear();
3033 * The dust settles...give focus to the tab we did this from.
3035 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3038 public static groovy.ui.Console getGroovyConsole()
3040 return groovyConsole;
3044 * handles the payload of a drag and drop event.
3046 * TODO refactor to desktop utilities class
3049 * - Data source strings extracted from the drop event
3051 * - protocol for each data source extracted from the drop event
3055 * - the payload from the drop event
3058 public static void transferFromDropTarget(List<String> files,
3059 List<DataSourceType> protocols, DropTargetDropEvent evt,
3060 Transferable t) throws Exception
3063 DataFlavor uriListFlavor = new DataFlavor(
3064 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3067 urlFlavour = new DataFlavor(
3068 "application/x-java-url; class=java.net.URL");
3069 } catch (ClassNotFoundException cfe)
3071 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3074 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3079 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3080 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3081 // means url may be null.
3084 protocols.add(DataSourceType.URL);
3085 files.add(url.toString());
3086 Cache.log.debug("Drop handled as URL dataflavor "
3087 + files.get(files.size() - 1));
3092 if (Platform.isAMac())
3095 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3099 } catch (Throwable ex)
3101 Cache.log.debug("URL drop handler failed.", ex);
3104 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3106 // Works on Windows and MacOSX
3107 Cache.log.debug("Drop handled as javaFileListFlavor");
3108 for (Object file : (List) t
3109 .getTransferData(DataFlavor.javaFileListFlavor))
3111 files.add(((File) file).toString());
3112 protocols.add(DataSourceType.FILE);
3117 // Unix like behaviour
3118 boolean added = false;
3120 if (t.isDataFlavorSupported(uriListFlavor))
3122 Cache.log.debug("Drop handled as uriListFlavor");
3123 // This is used by Unix drag system
3124 data = (String) t.getTransferData(uriListFlavor);
3128 // fallback to text: workaround - on OSX where there's a JVM bug
3129 Cache.log.debug("standard URIListFlavor failed. Trying text");
3130 // try text fallback
3131 DataFlavor textDf = new DataFlavor(
3132 "text/plain;class=java.lang.String");
3133 if (t.isDataFlavorSupported(textDf))
3135 data = (String) t.getTransferData(textDf);
3138 Cache.log.debug("Plain text drop content returned "
3139 + (data == null ? "Null - failed" : data));
3144 while (protocols.size() < files.size())
3146 Cache.log.debug("Adding missing FILE protocol for "
3147 + files.get(protocols.size()));
3148 protocols.add(DataSourceType.FILE);
3150 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3151 data, "\r\n"); st.hasMoreTokens();)
3154 String s = st.nextToken();
3155 if (s.startsWith("#"))
3157 // the line is a comment (as per the RFC 2483)
3160 java.net.URI uri = new java.net.URI(s);
3161 if (uri.getScheme().toLowerCase().startsWith("http"))
3163 protocols.add(DataSourceType.URL);
3164 files.add(uri.toString());
3168 // otherwise preserve old behaviour: catch all for file objects
3169 java.io.File file = new java.io.File(uri);
3170 protocols.add(DataSourceType.FILE);
3171 files.add(file.toString());
3176 if (Cache.log.isDebugEnabled())
3178 if (data == null || !added)
3181 if (t.getTransferDataFlavors() != null
3182 && t.getTransferDataFlavors().length > 0)
3185 "Couldn't resolve drop data. Here are the supported flavors:");
3186 for (DataFlavor fl : t.getTransferDataFlavors())
3189 "Supported transfer dataflavor: " + fl.toString());
3190 Object df = t.getTransferData(fl);
3193 Cache.log.debug("Retrieves: " + df);
3197 Cache.log.debug("Retrieved nothing");
3203 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3209 if (Platform.isWindows())
3212 Cache.log.debug("Scanning dropped content for Windows Link Files");
3214 // resolve any .lnk files in the file drop
3215 for (int f = 0; f < files.size(); f++)
3217 String source = files.get(f).toLowerCase();
3218 if (protocols.get(f).equals(DataSourceType.FILE)
3219 && (source.endsWith(".lnk") || source.endsWith(".url")
3220 || source.endsWith(".site")))
3224 File lf = new File(files.get(f));
3225 // process link file to get a URL
3226 Cache.log.debug("Found potential link file: " + lf);
3227 WindowsShortcut wscfile = new WindowsShortcut(lf);
3228 String fullname = wscfile.getRealFilename();
3229 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3230 files.set(f, fullname);
3231 Cache.log.debug("Parsed real filename " + fullname
3232 + " to extract protocol: " + protocols.get(f));
3233 } catch (Exception ex)
3236 "Couldn't parse " + files.get(f) + " as a link file.",
3245 * Sets the Preferences property for experimental features to True or False
3246 * depending on the state of the controlling menu item
3249 protected void showExperimental_actionPerformed(boolean selected)
3251 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3255 * Answers a (possibly empty) list of any structure viewer frames (currently
3256 * for either Jmol or Chimera) which are currently open. This may optionally
3257 * be restricted to viewers of a specified class, or viewers linked to a
3258 * specified alignment panel.
3261 * if not null, only return viewers linked to this panel
3262 * @param structureViewerClass
3263 * if not null, only return viewers of this class
3266 public List<StructureViewerBase> getStructureViewers(
3267 AlignmentPanel apanel,
3268 Class<? extends StructureViewerBase> structureViewerClass)
3270 List<StructureViewerBase> result = new ArrayList<>();
3271 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3273 for (JInternalFrame frame : frames)
3275 if (frame instanceof StructureViewerBase)
3277 if (structureViewerClass == null
3278 || structureViewerClass.isInstance(frame))
3281 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3283 result.add((StructureViewerBase) frame);