label.quit_jalview = Are you sure you want to quit Jalview?
label.wait_for_save = Wait for save
label.unsaved_changes = There are unsaved changes.
+label.unsaved_alignments = There are unsaved alignments.
label.save_in_progress = Some files are still saving:
+label.confirm_quit_viewer = An external viewer is still open. Close the external window as well?
+label.confirm_quit_viewers = External viewers are still open. Close these external windows as well?
label.unknown = Unknown
label.quit_after_saving = Jalview will quit after saving.
label.all_saved = All files saved.
label.sequence_details = Sequence Details
label.viewer_help = {0} Help
label.close_viewer = Close Viewer
+label.close_viewers = Close Viewers
label.confirm_close_viewer = This will close Jalview''s connection to {0}.<br>Do you want to close the {1} window as well?
label.all = All
label.sort_by = Sort alignment by
label.quit_jalview = ¿Estás seguro de que quieres salir de Jalview?
label.wait_for_save = Esperar a guardar
label.unsaved_changes = Hay cambios sin guardar.
+label.unsaved_alignments = Hay alineamientos sin guardar.
label.save_in_progress = Algunos archivos aún se están guardando:
+label.confirm_quit_viewer = Un visualizador externo todavía está abierto. ¿Cerrar también la ventana externa?
+label.confirm_quit_viewers = Los visualizadores externos siguen abiertos. ¿Cerrar también estas ventanas externas?
label.unknown = desconocido
label.quit_after_saving = Jalview se cerrará después de guardar.
label.all_saved = Todos los archivos guardados.
label.show_all_seq_annotations=Mostrar anotaciones relacionadas con las secuencias
label.hide_all_seq_annotations=Ocultar anotaciones relacionadas con las secuencias
label.close_viewer=Cerrar Visualizador
+label.close_viewers=Cerrar Visualizadores
label.all_views=Todas las Vistas
label.search_result=Resultado de búsqueda
action.fetch_sequences=Recuperar Secuencias...
void closeViewer(boolean closeExternalViewer);
/**
+ * Check if the external viewer is still running
+ */
+ boolean stillRunning();
+
+ /**
*
* @return true if all background sequence/structure binding threads have
* completed for this viewer instance
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import com.formdev.flatlaf.FlatLightLaf;
+import com.formdev.flatlaf.themes.FlatMacLightLaf;
import com.formdev.flatlaf.util.SystemInfo;
import com.threerings.getdown.util.LaunchUtil;
startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
format);
+ // don't ask to save when quitting if only the startup file has been
+ // opened
+ Console.debug("Resetting up-to-date flag for startup file");
+ startUpAlframe.getViewport().setSavedUpToDate(true);
// extract groovy arguments before anything else.
}
Console.error("Could not set requested laf=" + laf);
}
break;
- case "quaqua":
- lafSet = setQuaquaLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
- }
- break;
- case "vaqua":
- lafSet = setVaquaLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
- }
- break;
case "mac":
lafSet = setMacLookAndFeel();
if (!lafSet)
private static boolean setFlatLookAndFeel()
{
boolean set = false;
- if (Platform.isMac()) {
+ if (SystemInfo.isMacOS)
+ {
try
{
- UIManager.setLookAndFeel("com.formdev.flatlaf.themes.FlatMacLightLaf");
+ UIManager.setLookAndFeel(
+ "com.formdev.flatlaf.themes.FlatMacLightLaf");
set = true;
+ Console.debug("Using FlatMacLightLaf");
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e)
{
- Console.debug("Exception loading FlatMacLightLaf", e);
+ Console.debug("Exception loading FlatLightLaf", e);
+ }
+ System.setProperty("apple.laf.useScreenMenuBar", "true");
+ System.setProperty("apple.awt.application.name",
+ ChannelProperties.getProperty("app_name"));
+ System.setProperty("apple.awt.application.appearance", "system");
+ if (SystemInfo.isMacFullWindowContentSupported
+ && Desktop.desktop != null)
+ {
+ Console.debug("Setting transparent title bar");
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.fullWindowContent", true);
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.transparentTitleBar", true);
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.fullscreenable", true);
}
+ SwingUtilities.invokeLater(() -> {
+ FlatMacLightLaf.setup();
+ });
+ Console.debug("Using FlatMacLightLaf");
+ set = true;
}
- if (!set) {
+ if (!set)
+ {
try
{
UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
set = true;
+ Console.debug("Using FlatLightLaf");
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e)
{
Console.debug("Exception loading FlatLightLaf", e);
}
+ // Windows specific properties here
+ SwingUtilities.invokeLater(() -> {
+ FlatLightLaf.setup();
+ });
+ Console.debug("Using FlatLightLaf");
+ set = true;
}
- if (set)
+ else if (SystemInfo.isLinux)
{
- if (Platform.isMac())
+ try
{
- System.setProperty("apple.laf.useScreenMenuBar", "true");
- System.setProperty("apple.awt.application.name",
- ChannelProperties.getProperty("app_name"));
- System.setProperty("apple.awt.application.appearance", "system");
- if (SystemInfo.isMacFullWindowContentSupported
- && Desktop.desktop != null)
- {
- Desktop.desktop.getRootPane()
- .putClientProperty("apple.awt.fullWindowContent", true);
- Desktop.desktop.getRootPane()
- .putClientProperty("apple.awt.transparentTitleBar", true);
- }
+ UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
+ set = true;
+ Console.debug("Using FlatLightLaf");
+ } catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException | UnsupportedLookAndFeelException e)
+ {
+ Console.debug("Exception loading FlatLightLaf", e);
+ }
+ // enable custom window decorations
+ JFrame.setDefaultLookAndFeelDecorated(true);
+ JDialog.setDefaultLookAndFeelDecorated(true);
+ SwingUtilities.invokeLater(() -> {
+ FlatLightLaf.setup();
+ });
+ Console.debug("Using FlatLightLaf");
+ set = true;
+ }
- SwingUtilities.invokeLater(() -> {
- FlatLightLaf.setup();
- });
+ if (!set)
+ {
+ try
+ {
+ UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
+ set = true;
+ Console.debug("Using FlatLightLaf");
+ } catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException | UnsupportedLookAndFeelException e)
+ {
+ Console.debug("Exception loading FlatLightLaf", e);
}
+ }
+ if (set)
+ {
+ UIManager.put("TabbedPane.tabType", "card");
UIManager.put("TabbedPane.showTabSeparators", true);
+ UIManager.put("TabbedPane.showContentSeparator", true);
UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
UIManager.put("TabbedPane.tabsOverlapBorder", true);
- // UIManager.put("TabbedPane.hasFullBorder", true);
+ UIManager.put("TabbedPane.hasFullBorder", true);
UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
UIManager.put("TabbedPane.smoothScrolling", true);
return set;
}
- private static boolean setQuaquaLookAndFeel()
- {
- return setSpecificLookAndFeel("quaqua",
- ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
- .getName(),
- false);
- }
-
- private static boolean setVaquaLookAndFeel()
- {
- return setSpecificLookAndFeel("vaqua",
- "org.violetlib.aqua.AquaLookAndFeel", false);
- }
-
private static boolean setMacLookAndFeel()
{
boolean set = false;
+++ /dev/null
-/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jalview.gui;
-
-import java.awt.Container;
-import java.beans.PropertyVetoException;
-import java.util.Vector;
-
-import javax.swing.DefaultDesktopManager;
-import javax.swing.DesktopManager;
-import javax.swing.JInternalFrame;
-
-/**
- * Based on AquaInternalFrameManager
- *
- * DesktopManager implementation for Aqua
- *
- * Mac is more like Windows than it's like Motif/Basic
- *
- * From WindowsDesktopManager:
- *
- * This class implements a DesktopManager which more closely follows the MDI
- * model than the DefaultDesktopManager. Unlike the DefaultDesktopManager
- * policy, MDI requires that the selected and activated child frames are the
- * same, and that that frame always be the top-most window.
- * <p>
- * The maximized state is managed by the DesktopManager with MDI, instead of
- * just being a property of the individual child frame. This means that if the
- * currently selected window is maximized and another window is selected, that
- * new window will be maximized.
- *
- * Downloaded from
- * https://raw.githubusercontent.com/frohoff/jdk8u-jdk/master/src/macosx/classes/com/apple/laf/AquaInternalFrameManager.java
- *
- * Patch from Jim Procter - when the most recently opened frame is closed,
- * correct behaviour is to go to the next most recent frame, rather than wrap
- * around to the bottom of the window stack (as the original implementation
- * does)
- *
- * see com.sun.java.swing.plaf.windows.WindowsDesktopManager
- */
-public class AquaInternalFrameManager extends DefaultDesktopManager
-{
- // Variables
-
- /* The frame which is currently selected/activated.
- * We store this value to enforce Mac's single-selection model.
- */
- JInternalFrame fCurrentFrame;
-
- JInternalFrame fInitialFrame;
-
- /* The list of frames, sorted by order of creation.
- * This list is necessary because by default the order of
- * child frames in the JDesktopPane changes during frame
- * activation (the activated frame is moved to index 0).
- * We preserve the creation order so that "next" and "previous"
- * frame actions make sense.
- */
- Vector<JInternalFrame> fChildFrames = new Vector<>(1);
-
- /**
- * keep a reference to the original LAF manager so we can iconise/de-iconise
- * correctly
- */
- private DesktopManager ourManager;
-
- public AquaInternalFrameManager(DesktopManager desktopManager)
- {
- ourManager = desktopManager;
- }
-
- @Override
- public void closeFrame(final JInternalFrame f)
- {
- if (f == fCurrentFrame)
- {
- boolean mostRecentFrame = fChildFrames
- .indexOf(f) == fChildFrames.size() - 1;
- if (!mostRecentFrame)
- {
- activateNextFrame();
- }
- else
- {
- activatePreviousFrame();
- }
- }
- fChildFrames.removeElement(f);
- super.closeFrame(f);
- }
-
- @Override
- public void deiconifyFrame(final JInternalFrame f)
- {
- JInternalFrame.JDesktopIcon desktopIcon;
-
- desktopIcon = f.getDesktopIcon();
- // If the icon moved, move the frame to that spot before expanding it
- // reshape does delta checks for us
- f.reshape(desktopIcon.getX(), desktopIcon.getY(), f.getWidth(),
- f.getHeight());
- ourManager.deiconifyFrame(f);
- }
-
- void addIcon(final Container c,
- final JInternalFrame.JDesktopIcon desktopIcon)
- {
- c.add(desktopIcon);
- }
-
- /**
- * Removes the frame from its parent and adds its desktopIcon to the parent.
- */
- @Override
- public void iconifyFrame(final JInternalFrame f)
- {
- ourManager.iconifyFrame(f);
- }
-
- // WindowsDesktopManager code
- @Override
- public void activateFrame(final JInternalFrame f)
- {
- try
- {
- if (f != null)
- {
- super.activateFrame(f);
- }
-
- // add or relocate to top of stack
- if (fChildFrames.indexOf(f) != -1)
- {
- fChildFrames.remove(f);
- }
- fChildFrames.addElement(f);
-
- if (fCurrentFrame != null && f != fCurrentFrame)
- {
- if (fCurrentFrame.isSelected())
- {
- fCurrentFrame.setSelected(false);
- }
- }
-
- if (f != null && !f.isSelected())
- {
- f.setSelected(true);
- }
-
- fCurrentFrame = f;
- } catch (final PropertyVetoException e)
- {
- }
- }
-
- private void switchFrame(final boolean next)
- {
- if (fCurrentFrame == null)
- {
- // initialize first frame we find
- if (fInitialFrame != null)
- {
- activateFrame(fInitialFrame);
- }
- return;
- }
-
- final int count = fChildFrames.size();
- if (count <= 1)
- {
- // No other child frames.
- return;
- }
-
- final int currentIndex = fChildFrames.indexOf(fCurrentFrame);
- if (currentIndex == -1)
- {
- // the "current frame" is no longer in the list
- fCurrentFrame = null;
- return;
- }
-
- int nextIndex;
- if (next)
- {
- nextIndex = currentIndex + 1;
- if (nextIndex == count)
- {
- nextIndex = 0;
- }
- }
- else
- {
- nextIndex = currentIndex - 1;
- if (nextIndex == -1)
- {
- nextIndex = count - 1;
- }
- }
- final JInternalFrame f = fChildFrames.elementAt(nextIndex);
- activateFrame(f);
- fCurrentFrame = f;
- }
-
- /**
- * Activate the next child JInternalFrame, as determined by the frames'
- * Z-order. If there is only one child frame, it remains activated. If there
- * are no child frames, nothing happens.
- */
- public void activateNextFrame()
- {
- switchFrame(true);
- }
-
- /**
- * same as above but will activate a frame if none have been selected
- */
- public void activateNextFrame(final JInternalFrame f)
- {
- fInitialFrame = f;
- switchFrame(true);
- }
-
- /**
- * Activate the previous child JInternalFrame, as determined by the frames'
- * Z-order. If there is only one child frame, it remains activated. If there
- * are no child frames, nothing happens.
- */
- public void activatePreviousFrame()
- {
- switchFrame(false);
- }
-}
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
+import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
import jalview.gui.ImageExporter.ImageWriterI;
// This line prevents Windows Look&Feel resizing all new windows to maximum
// if previous window was maximised
desktop.setDesktopManager(new MyDesktopManager(
- (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
- : Platform.isAMacAndNotJS()
- ? new AquaInternalFrameManager(
- desktop.getDesktopManager())
- : desktop.getDesktopManager())));
+ Platform.isJS() ? desktop.getDesktopManager()
+ : new DefaultDesktopManager()));
+ /*
+ (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
+ : Platform.isAMacAndNotJS()
+ ? new AquaInternalFrameManager(
+ desktop.getDesktopManager())
+ : desktop.getDesktopManager())));
+ */
Rectangle dims = getLastKnownDimensions("");
if (dims != null)
if (jvnews != null)
{
storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
+ }
+
+ // Frames should all close automatically. Keeping external
+ // viewers open should already be decided by user.
+ closeAll_actionPerformed(null);
+ // check for aborted quit
+ if (QuitHandler.quitCancelled())
+ {
+ jalview.bin.Console.debug("Desktop aborting quit");
+ return null;
}
if (dialogExecutor != null)
dialogExecutor.shutdownNow();
}
- closeAll_actionPerformed(null);
-
if (groovyConsole != null)
{
// suppress a possible repeat prompt to save script
}
}
+ public int structureViewersStillRunningCount()
+ {
+ int count = 0;
+ JInternalFrame[] frames = desktop.getAllFrames();
+ for (int i = 0; i < frames.length; i++)
+ {
+ if (frames[i] != null
+ && frames[i] instanceof JalviewStructureDisplayI)
+ {
+ if (((JalviewStructureDisplayI) frames[i]).stillRunning())
+ count++;
+ }
+ }
+ return count;
+ }
+
@Override
public void raiseRelated_actionPerformed(ActionEvent e)
{
/**
* single thread that handles display of dialogs to user.
*/
- ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
+ ExecutorService dialogExecutor = Executors.newFixedThreadPool(3);
/**
* flag indicating if dialogExecutor should try to acquire a permit
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.Icon;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
+import jalview.bin.Console;
import jalview.util.ChannelProperties;
import jalview.util.Platform;
import jalview.util.dialogrunner.DialogRunnerI;
private Component parentComponent;
+ private ExecutorService executor = Executors.newCachedThreadPool();
+
+ private JDialog dialog = null;
+
private Map<Object, Callable<Void>> callbacks = new HashMap<>();
/*
JOptionPane joptionpane = (JOptionPane) joptionpaneObject;
joptionpane.setValue(buttonAction);
if (action != null)
- Executors.newSingleThreadExecutor().submit(action);
+ getExecutor().submit(action);
joptionpane.transferFocusBackward();
joptionpane.setVisible(false);
// put focus and raise parent window if possible, unless cancel or
jb.setText((String) o);
jb.addActionListener(new ActionListener()
{
+
@Override
public void actionPerformed(ActionEvent e)
{
joptionpane.setValue(buttonAction);
if (action != null)
- Executors.newSingleThreadExecutor().submit(action);
+ getExecutor().submit(action);
// joptionpane.transferFocusBackward();
joptionpane.transferFocusBackward();
joptionpane.setVisible(false);
: ModalityType.MODELESS);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
+ setDialog(dialog);
}
}
return this;
}
+ public ExecutorService getExecutor()
+ {
+ if (executor == null)
+ executor = Executors.newSingleThreadExecutor();
+ return executor;
+ }
+
+ public void setExecutor(ExecutorService es)
+ {
+ executor = es;
+ }
+
+ public void setDialog(JDialog d)
+ {
+ dialog = d;
+ }
+
+ public JDialog getDialog()
+ {
+ return dialog;
+ }
+
/**
* showDialogOnTop will create a dialog that (attempts to) come to top of OS
* desktop windows
public static int showDialogOnTop(String label, String actionString,
int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE)
{
+ return showDialogOnTop(null, label, actionString, JOPTIONPANE_OPTION,
+ JOPTIONPANE_MESSAGETYPE);
+ }
+
+ public static int showDialogOnTop(Component dialogParentComponent,
+ String label, String actionString, int JOPTIONPANE_OPTION,
+ int JOPTIONPANE_MESSAGETYPE)
+ {
if (!isInteractiveMode())
{
return (int) getMockResponse();
// A better hack which works is to create a new JFrame parent with
// setAlwaysOnTop(true)
JFrame dialogParent = new JFrame();
- dialogParent.setIconImages(ChannelProperties.getIconList());
- dialogParent.setAlwaysOnTop(true);
+ if (dialogParentComponent == null)
+ {
+ dialogParent.setIconImages(ChannelProperties.getIconList());
+ dialogParent.setAlwaysOnTop(true);
+ }
- int answer = JOptionPane.showConfirmDialog(dialogParent, label,
- actionString, JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE);
+ int answer = JOptionPane.showConfirmDialog(
+ dialogParentComponent == null ? dialogParent
+ : dialogParentComponent,
+ label, actionString, JOPTIONPANE_OPTION,
+ JOPTIONPANE_MESSAGETYPE);
- dialogParent.setAlwaysOnTop(false);
- dialogParent.dispose();
+ if (dialogParentComponent == null)
+ {
+ dialogParent.setAlwaysOnTop(false);
+ dialogParent.dispose();
+ }
return answer;
}
{
try
{
- action.call();
+ getExecutor().submit(action).get();
+ // action.call();
} catch (Exception e)
{
e.printStackTrace();
{
joptionpane.setValue(buttonAction);
if (action != null)
- Executors.newSingleThreadExecutor().submit(action);
+ getExecutor().submit(action);
// joptionpane.transferFocusBackward();
joptionpane.transferFocusBackward();
joptionpane.setVisible(false);
dialog.setModalityType(
modal ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ setDialog(dialog);
return dialog;
}
parent.remove(f);
}
}
+
+ public static JvOptionPane frameDialog(String message, String title,
+ int messageType, String[] buttonsText, String defaultButton,
+ Callable<Void>[] handlers, boolean modal)
+ {
+ JFrame parent = new JFrame();
+ JvOptionPane jvop = JvOptionPane.newOptionDialog();
+ JButton[] buttons = new JButton[buttonsText.length];
+ for (int i = 0; i < buttonsText.length; i++)
+ {
+ buttons[i] = new JButton();
+ buttons[i].setText(buttonsText[i]);
+ Console.debug("DISABLING BUTTON " + buttons[i].getText());
+ buttons[i].setEnabled(false);
+ buttons[i].setVisible(false);
+ }
+
+ int dialogType = -1;
+ if (buttonsText.length == 1)
+ {
+ dialogType = JOptionPane.OK_OPTION;
+ }
+ else if (buttonsText.length == 2)
+ {
+ dialogType = JOptionPane.YES_NO_OPTION;
+ }
+ else
+ {
+ dialogType = JOptionPane.YES_NO_CANCEL_OPTION;
+ }
+ jvop.setResponseHandler(JOptionPane.YES_OPTION, handlers[0]);
+ if (dialogType == JOptionPane.YES_NO_OPTION
+ || dialogType == JOptionPane.YES_NO_CANCEL_OPTION)
+ {
+ jvop.setResponseHandler(JOptionPane.NO_OPTION, handlers[1]);
+ }
+ if (dialogType == JOptionPane.YES_NO_CANCEL_OPTION)
+ {
+ jvop.setResponseHandler(JOptionPane.CANCEL_OPTION, handlers[2]);
+ }
+
+ final int dt = dialogType;
+ jvop.getExecutor().execute(() -> {
+ jvop.showDialog(message, title, dt, messageType, null, buttonsText,
+ defaultButton, modal, buttons);
+ });
+
+ return jvop;
+ }
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
NULL, QUIT, CANCEL_QUIT, FORCE_QUIT
};
+ public static enum Message
+ {
+ UNSAVED_CHANGES, UNSAVED_ALIGNMENTS
+ };
+
+ protected static Message message = Message.UNSAVED_CHANGES;
+
+ public static void setMessage(Message m)
+ {
+ message = m;
+ }
+
private static ExecutorService executor = Executors.newFixedThreadPool(3);
public static QResponse setQuitHandler()
if (confirmQuit)
{
- JvOptionPane.newOptionDialog()
+ String messageString = MessageManager
+ .getString(message == Message.UNSAVED_ALIGNMENTS
+ ? "label.unsaved_alignments"
+ : "label.unsaved_changes");
+ setQuitDialog(JvOptionPane.newOptionDialog()
.setResponseHandler(JOptionPane.YES_OPTION, defaultOkQuit)
- .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit)
- .showDialogOnTopAsync(
- new StringBuilder(MessageManager
- .getString("label.quit_jalview"))
- .append("\n")
- .append(MessageManager
- .getString("label.unsaved_changes"))
- .toString(),
- MessageManager.getString("action.quit"),
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE, null, new Object[]
- { MessageManager.getString("action.quit"),
- MessageManager.getString("action.cancel") },
- MessageManager.getString("action.quit"), true);
+ .setResponseHandler(JOptionPane.NO_OPTION, cancelQuit));
+ JvOptionPane qd = getQuitDialog();
+ qd.showDialogOnTopAsync(
+ new StringBuilder(
+ MessageManager.getString("label.quit_jalview"))
+ .append("\n").append(messageString).toString(),
+ MessageManager.getString("action.quit"),
+ JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
+ new Object[]
+ { MessageManager.getString("action.quit"),
+ MessageManager.getString("action.cancel") },
+ MessageManager.getString("action.quit"), true);
}
got = gotQuitResponse();
+
+ // check for external viewer frames
+ if (got != QResponse.CANCEL_QUIT)
+ {
+ int count = Desktop.instance.structureViewersStillRunningCount();
+ if (count > 0)
+ {
+ String prompt = MessageManager
+ .formatMessage(count == 1 ? "label.confirm_quit_viewer"
+ : "label.confirm_quit_viewers");
+ String title = MessageManager.getString(
+ count == 1 ? "label.close_viewer" : "label.close_viewers");
+ String cancelQuitText = MessageManager
+ .getString("action.cancel_quit");
+ String[] buttonsText = { MessageManager.getString("action.yes"),
+ MessageManager.getString("action.no"), cancelQuitText };
+
+ int confirmResponse = JvOptionPane.showOptionDialog(
+ Desktop.instance, prompt, title,
+ JvOptionPane.YES_NO_CANCEL_OPTION,
+ JvOptionPane.WARNING_MESSAGE, null, buttonsText,
+ cancelQuit);
+
+ if (confirmResponse == JvOptionPane.CANCEL_OPTION)
+ {
+ // Cancel Quit
+ QuitHandler.setResponse(QResponse.CANCEL_QUIT);
+ }
+ else
+ {
+ // Close viewers/Leave viewers open
+ StructureViewerBase
+ .setQuitClose(confirmResponse == JvOptionPane.YES_OPTION);
+ }
+ }
+
+ }
+
+ got = gotQuitResponse();
+
boolean wait = false;
if (got == QResponse.CANCEL_QUIT)
{
{
executor.submit(next).get();
got = gotQuitResponse();
+ } catch (RejectedExecutionException e)
+ {
+ // QuitHander.abortQuit() probably called
+ // CANCEL_QUIT test will reset QuitHandler
+ Console.info("Quit aborted!");
+ got = QResponse.NULL;
+ setResponse(QResponse.NULL);
} catch (InterruptedException | ExecutionException e)
{
jalview.bin.Console
}
setResponse(got);
- if (gotQuitResponse() == QResponse.CANCEL_QUIT)
+ if (quitCancelled())
{
// reset if cancelled
+ Console.debug("Quit cancelled");
setResponse(QResponse.NULL);
return QResponse.CANCEL_QUIT;
}
}
else
{
- if (!(QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT
- || QuitHandler.gotQuitResponse() == QResponse.NULL))
+ if (!(quitCancelled()))
{
for (int i = 0; i < buttons.length; i++)
{
public static void abortQuit()
{
- setResponse(QResponse.CANCEL_QUIT);
+ setResponse(QResponse.NULL);
+ // executor.shutdownNow();
+ }
+
+ private static JvOptionPane quitDialog = null;
+
+ private static void setQuitDialog(JvOptionPane qd)
+ {
+ quitDialog = qd;
+ }
+
+ private static JvOptionPane getQuitDialog()
+ {
+ return quitDialog;
+ }
+
+ public static boolean quitCancelled()
+ {
+ return QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT
+ || QuitHandler.gotQuitResponse() == QResponse.NULL;
+ }
+
+ public static boolean quitting()
+ {
+ return QuitHandler.gotQuitResponse() == QResponse.QUIT
+ || QuitHandler.gotQuitResponse() == QResponse.FORCE_QUIT;
}
-}
\ No newline at end of file
+}
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
+import java.beans.PropertyVetoException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
return session;
}
+ private static boolean quitClose = false;
+
+ public static void setQuitClose(boolean b)
+ {
+ quitClose = b;
+ }
+
+ @Override
+ public boolean stillRunning()
+ {
+ AAStructureBindingModel binding = getBinding();
+ return binding != null && binding.isViewerRunning();
+ }
+
/**
* Close down this instance of Jalview's Chimera viewer, giving the user the
* option to close the associated Chimera window (process). They may wish to
public void closeViewer(boolean forceClose)
{
AAStructureBindingModel binding = getBinding();
- if (binding != null && binding.isViewerRunning())
+ if (stillRunning())
{
if (!forceClose)
{
String viewerName = getViewerName();
- String prompt = MessageManager
- .formatMessage("label.confirm_close_viewer", new Object[]
- { binding.getViewerTitle(viewerName, false), viewerName });
- prompt = JvSwingUtils.wrapTooltip(true, prompt);
- int confirm = JvOptionPane.showConfirmDialog(this, prompt,
- MessageManager.getString("label.close_viewer"),
- JvOptionPane.YES_NO_CANCEL_OPTION);
+
+ int confirm = JvOptionPane.CANCEL_OPTION;
+ if (QuitHandler.quitting())
+ {
+ // already asked about closing external windows
+ confirm = quitClose ? JvOptionPane.YES_OPTION
+ : JvOptionPane.NO_OPTION;
+ }
+ else
+ {
+ String prompt = MessageManager
+ .formatMessage("label.confirm_close_viewer", new Object[]
+ { binding.getViewerTitle(viewerName, false),
+ viewerName });
+ prompt = JvSwingUtils.wrapTooltip(true, prompt);
+ String title = MessageManager.getString("label.close_viewer");
+ confirm = showCloseDialog(title, prompt);
+ }
+
/*
* abort closure if user hits escape or Cancel
*/
{
// abort possible quit handling if CANCEL chosen
if (confirm == JvOptionPane.CANCEL_OPTION)
+ {
+ try
+ {
+ // this is a bit futile
+ this.setClosed(false);
+ } catch (PropertyVetoException e)
+ {
+ }
QuitHandler.abortQuit();
+ }
return;
}
forceClose = confirm == JvOptionPane.YES_OPTION;
dispose();
}
+ private int showCloseDialog(final String title, final String prompt)
+ {
+ int confirmResponse = JvOptionPane.CANCEL_OPTION;
+ confirmResponse = JvOptionPane.showConfirmDialog(this, prompt,
+ MessageManager.getString("label.close_viewer"),
+ JvOptionPane.YES_NO_CANCEL_OPTION,
+ JvOptionPane.WARNING_MESSAGE);
+ return confirmResponse;
+ }
+
@Override
public void showHelp_actionPerformed()
{
&& viewerActionMenu.getItemCount() > 0
&& viewerActionMenu.isVisible();
}
+
}
public enum DataSourceType
{
FILE, URL, PASTE, CLASSLOADER, RELATIVE_URL;
+
+ public boolean isDynamic()
+ {
+ return this != FILE;
+ }
}
import jalview.gui.AlignViewport;
import jalview.gui.Desktop;
import jalview.gui.JvOptionPane;
+import jalview.gui.QuitHandler;
import jalview.json.binding.biojson.v1.ColourSchemeMapper;
import jalview.project.Jalview2XML;
import jalview.schemes.ColourSchemeI;
MessageManager.getString("label.couldnt_read_data"),
JvOptionPane.WARNING_MESSAGE);
}
+ this.setShouldBeSaved();
return;
}
// TODO: cache any stream datasources as a temporary file (eg. PDBs
{
alignFrame.setFileName(file, format);
alignFrame.setFileObject(selectedFile); // BH 2018 SwingJS
- alignFrame.getViewport().setSavedUpToDate(true);
}
if (proxyColourScheme != null)
{
Desktop.instance.stopLoading();
}
+ this.setShouldBeSaved();
}
/**
return tempStructFile.toString();
}
+ /*
+ * set whether quit should ask to save when just loaded this source
+ */
+ private void setShouldBeSaved()
+ {
+ if (protocol == null)
+ return;
+ AlignFrame af = this.alignFrame;
+ if (af == null)
+ return;
+ AlignViewport avp = af.getViewport();
+ if (avp == null)
+ return;
+ avp.setSavedUpToDate(!protocol.isDynamic(),
+ QuitHandler.Message.UNSAVED_ALIGNMENTS);
+ }
+
}
import jalview.datamodel.SequenceCollectionI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.gui.QuitHandler;
import jalview.project.Jalview2XML;
import jalview.renderer.ResidueShader;
import jalview.renderer.ResidueShaderI;
public void setSavedUpToDate(boolean s)
{
+ setSavedUpToDate(s, QuitHandler.Message.UNSAVED_CHANGES);
+ }
+
+ public void setSavedUpToDate(boolean s, QuitHandler.Message m)
+ {
Console.debug(
"Setting " + this.getViewId() + " setSavedUpToDate to " + s);
savedUpToDate = s;
+ QuitHandler.setMessage(m);
}
public boolean savedUpToDate()