X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FDesktop.java;h=c80a6bae7fa0ce690991fe2350e4e53af36eef42;hb=afe4b88500a5d61bc8d312909cfdde2b7cdd53df;hp=dfef0d2c9e15fc56fbf53272c9e67b0a3303e0b2;hpb=0d37fef8a89c67845c14f2383e89003c9a2c5b62;p=jalview.git
diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java
index dfef0d2..c80a6ba 100644
--- a/src/jalview/gui/Desktop.java
+++ b/src/jalview/gui/Desktop.java
@@ -22,6 +22,7 @@ package jalview.gui;
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
@@ -51,6 +52,7 @@ import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@@ -63,8 +65,8 @@ import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
+import java.util.Map;
import java.util.Vector;
-import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
@@ -86,10 +88,14 @@ import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
import javax.swing.JTextField;
+import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
@@ -97,13 +103,23 @@ import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
+import javax.swing.text.JTextComponent;
import org.stackoverflowusers.file.WindowsShortcut;
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
+import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
+import jalview.bin.Jalview.ExitCode;
+import jalview.bin.argparser.Arg;
+import jalview.bin.groovy.JalviewObject;
+import jalview.bin.groovy.JalviewObjectI;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
import jalview.gui.ImageExporter.ImageWriterI;
import jalview.gui.QuitHandler.QResponse;
import jalview.io.BackupFiles;
@@ -117,6 +133,7 @@ import jalview.io.FormatAdapter;
import jalview.io.IdentifyFile;
import jalview.io.JalviewFileChooser;
import jalview.io.JalviewFileView;
+import jalview.io.exceptions.ImageOutputException;
import jalview.jbgui.GSplitFrame;
import jalview.jbgui.GStructureViewer;
import jalview.project.Jalview2XML;
@@ -124,6 +141,8 @@ import jalview.structure.StructureSelectionManager;
import jalview.urls.IdOrgSettings;
import jalview.util.BrowserLauncher;
import jalview.util.ChannelProperties;
+import jalview.util.IdUtils;
+import jalview.util.IdUtils.IdType;
import jalview.util.ImageMaker.TYPE;
import jalview.util.LaunchUtils;
import jalview.util.MessageManager;
@@ -143,7 +162,7 @@ import jalview.ws.utils.UrlDownloadClient;
*/
public class Desktop extends jalview.jbgui.GDesktop
implements DropTargetListener, ClipboardOwner, IProgressIndicator,
- jalview.api.StructureSelectionManagerProvider
+ jalview.api.StructureSelectionManagerProvider, JalviewObjectI
{
private static final String CITATION;
static
@@ -167,7 +186,7 @@ public class Desktop extends jalview.jbgui.GDesktop
: " ");
sb.append(
- "
For help, see www.jalview.org/faq and join discourse.jalview.org");
+ "
For help, see www.jalview.org/faq and join discourse.jalview.org");
sb.append("
If you use Jalview, please cite:"
+ "
Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
+ "
Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
@@ -191,6 +210,16 @@ public class Desktop extends jalview.jbgui.GDesktop
public static HashMap savingFiles = new HashMap();
+ private static int DRAG_MODE = JDesktopPane.OUTLINE_DRAG_MODE;
+
+ public static void setLiveDragMode(boolean b)
+ {
+ DRAG_MODE = b ? JDesktopPane.LIVE_DRAG_MODE
+ : JDesktopPane.OUTLINE_DRAG_MODE;
+ if (desktop != null)
+ desktop.setDragMode(DRAG_MODE);
+ }
+
private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
public static boolean nosplash = false;
@@ -420,9 +449,14 @@ public class Desktop extends jalview.jbgui.GDesktop
{
if (LaunchUtils.getJavaVersion() >= 11)
{
- jalview.bin.Console.info(
+ /*
+ * Send this message to stderr as the warning that follows (due to
+ * reflection) also goes to stderr.
+ */
+ jalview.bin.Console.errPrintln(
"Linux platform only! You may have the following warning next: \"WARNING: An illegal reflective access operation has occurred\"\nThis is expected and cannot be avoided, sorry about that.");
}
+ final String awtAppClassName = "awtAppClassName";
try
{
Toolkit xToolkit = Toolkit.getDefaultToolkit();
@@ -430,10 +464,10 @@ public class Desktop extends jalview.jbgui.GDesktop
Field awtAppClassNameField = null;
if (Arrays.stream(declaredFields)
- .anyMatch(f -> f.getName().equals("awtAppClassName")))
+ .anyMatch(f -> f.getName().equals(awtAppClassName)))
{
awtAppClassNameField = xToolkit.getClass()
- .getDeclaredField("awtAppClassName");
+ .getDeclaredField(awtAppClassName);
}
String title = ChannelProperties.getProperty("app_name");
@@ -444,11 +478,12 @@ public class Desktop extends jalview.jbgui.GDesktop
}
else
{
- jalview.bin.Console.debug("XToolkit: awtAppClassName not found");
+ jalview.bin.Console
+ .debug("XToolkit: " + awtAppClassName + " not found");
}
} catch (Exception e)
{
- jalview.bin.Console.debug("Error setting awtAppClassName");
+ jalview.bin.Console.debug("Error setting " + awtAppClassName);
jalview.bin.Console.trace(Cache.getStackTraceString(e));
}
}
@@ -468,7 +503,28 @@ public class Desktop extends jalview.jbgui.GDesktop
boolean selmemusage = Cache.getDefault("SHOW_MEMUSAGE", false);
- boolean showjconsole = Cache.getDefault("SHOW_JAVA_CONSOLE", false);
+ boolean showjconsole = Cache.getArgCacheDefault(Arg.JAVACONSOLE,
+ "SHOW_JAVA_CONSOLE", false);
+
+ // start dialogue queue for single dialogues
+ startDialogQueue();
+
+ if (!Platform.isJS())
+ /**
+ * Java only
+ *
+ * @j2sIgnore
+ */
+ {
+ Desktop.instance.acquireDialogQueue();
+
+ jconsole = new Console(this);
+ jconsole.setHeader(Cache.getVersionDetailsForConsole());
+ showConsole(showjconsole);
+
+ Desktop.instance.releaseDialogQueue();
+ }
+
desktop = new MyDesktopPane(selmemusage);
showMemusage.setSelected(selmemusage);
@@ -487,16 +543,20 @@ public class Desktop extends jalview.jbgui.GDesktop
}
getContentPane().add(desktop, BorderLayout.CENTER);
- desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
+ desktop.setDragMode(DRAG_MODE);
// 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)
@@ -518,10 +578,6 @@ public class Desktop extends jalview.jbgui.GDesktop
* @j2sIgnore
*/
{
- jconsole = new Console(this, showjconsole);
- jconsole.setHeader(Cache.getVersionDetailsForConsole());
- showConsole(showjconsole);
-
showNews.setVisible(false);
experimentalFeatures.setSelected(showExperimental());
@@ -544,15 +600,16 @@ public class Desktop extends jalview.jbgui.GDesktop
}
// Thread off a new instance of the file chooser - this reduces the time
- // it
- // takes to open it later on.
+ // it takes to open it later on.
new Thread(new Runnable()
{
@Override
public void run()
{
jalview.bin.Console.debug("Filechooser init thread started.");
- String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
+ String fileFormat = FileLoader.getUseDefaultFileFormat()
+ ? Cache.getProperty("DEFAULT_FILE_FORMAT")
+ : null;
JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
fileFormat);
jalview.bin.Console.debug("Filechooser init thread finished.");
@@ -598,6 +655,13 @@ public class Desktop extends jalview.jbgui.GDesktop
}
});
desktop.addMouseListener(ma);
+
+ if (Platform.isJS())
+ {
+ // used for jalviewjsTest
+ jalview.bin.Console.info("JALVIEWJS: CREATED DESKTOP");
+ }
+
}
/**
@@ -697,11 +761,12 @@ public class Desktop extends jalview.jbgui.GDesktop
@Override
public void run()
{
- long now = System.currentTimeMillis();
+ long progressId = IdUtils.newId(IdType.PROGRESS);
Desktop.instance.setProgressBar(
- MessageManager.getString("status.refreshing_news"), now);
+ MessageManager.getString("status.refreshing_news"),
+ progressId);
jvnews.refreshNews();
- Desktop.instance.setProgressBar(null, now);
+ Desktop.instance.setProgressBar(null, progressId);
jvnews.showNews();
}
}).start();
@@ -742,17 +807,17 @@ public class Desktop extends jalview.jbgui.GDesktop
iw = (int) (iw * sw);
iy = (int) (iy * sh);
ih = (int) (ih * sh);
- while (ix >= screenSize.width)
+ if (ix >= screenSize.width)
{
jalview.bin.Console.debug(
"Window geometry location recall error: shifting horizontal to within screenbounds.");
- ix -= screenSize.width;
+ ix = ix % screenSize.width;
}
- while (iy >= screenSize.height)
+ if (iy >= screenSize.height)
{
jalview.bin.Console.debug(
"Window geometry location recall error: shifting vertical to within screenbounds.");
- iy -= screenSize.height;
+ iy = iy % screenSize.height;
}
jalview.bin.Console.debug(
"Got last known dimensions for " + windowName + ": x:" + ix
@@ -784,26 +849,64 @@ public class Desktop extends jalview.jbgui.GDesktop
public void paste()
{
- try
+ // quick patch for JAL-4150 - needs some more work and test coverage
+ // TODO - unify below and AlignFrame.paste()
+ // TODO - write tests and fix AlignFrame.paste() which doesn't track if
+ // clipboard has come from a different alignment window than the one where
+ // paste has been called! JAL-4151
+
+ if (Desktop.jalviewClipboard != null)
{
- Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
- Transferable contents = c.getContents(this);
+ // The clipboard was filled from within Jalview, we must use the
+ // sequences
+ // And dataset from the copied alignment
+ SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];
+ // be doubly sure that we create *new* sequence objects.
+ SequenceI[] sequences = new SequenceI[newseq.length];
+ for (int i = 0; i < newseq.length; i++)
+ {
+ sequences[i] = new Sequence(newseq[i]);
+ }
+ Alignment alignment = new Alignment(sequences);
+ // dataset is inherited
+ alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);
+ AlignFrame af = new AlignFrame(alignment, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ String newtitle = new String("Copied sequences");
+
+ if (Desktop.jalviewClipboard[2] != null)
+ {
+ HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2];
+ af.viewport.setHiddenColumns(hc);
+ }
- if (contents != null)
+ Desktop.addInternalFrame(af, newtitle, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+
+ }
+ else
+ {
+ try
{
- String file = (String) contents
- .getTransferData(DataFlavor.stringFlavor);
+ Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
+ Transferable contents = c.getContents(this);
+
+ if (contents != null)
+ {
+ String file = (String) contents
+ .getTransferData(DataFlavor.stringFlavor);
- FileFormatI format = new IdentifyFile().identify(file,
- DataSourceType.PASTE);
+ FileFormatI format = new IdentifyFile().identify(file,
+ DataSourceType.PASTE);
- new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
+ new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
+ }
+ } catch (Exception ex)
+ {
+ jalview.bin.Console.outPrintln(
+ "Unable to paste alignment from system clipboard:\n" + ex);
}
- } catch (Exception ex)
- {
- System.out.println(
- "Unable to paste alignment from system clipboard:\n" + ex);
}
}
@@ -958,7 +1061,7 @@ public class Desktop extends jalview.jbgui.GDesktop
{
if (itf instanceof AlignFrame)
{
- Jalview.setCurrentAlignFrame((AlignFrame) itf);
+ Jalview.getInstance().setCurrentAlignFrame((AlignFrame) itf);
}
itf.requestFocus();
}
@@ -1006,7 +1109,38 @@ public class Desktop extends jalview.jbgui.GDesktop
setKeyBindings(frame);
- desktop.add(frame);
+ // Since the latest FlatLaf patch, we occasionally have problems showing
+ // structureViewer frames...
+ int tries = 3;
+ boolean shown = false;
+ Exception last = null;
+ do
+ {
+ try
+ {
+ desktop.add(frame);
+ shown = true;
+ } catch (IllegalArgumentException iaex)
+ {
+ last = iaex;
+ tries--;
+ jalview.bin.Console.info("Squashed IllegalArgument Exception ("
+ + tries + " left) for " + frame.getTitle(), iaex);
+ try
+ {
+ Thread.sleep(5);
+ } catch (InterruptedException iex)
+ {
+ }
+ ;
+ }
+ } while (!shown && tries > 0);
+ if (!shown)
+ {
+ jalview.bin.Console.error(
+ "Serious Problem whilst showing window " + frame.getTitle(),
+ last);
+ }
windowMenu.add(menuItem);
@@ -1166,7 +1300,9 @@ public class Desktop extends jalview.jbgui.GDesktop
@Override
public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
{
- String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
+ String fileFormat = FileLoader.getUseDefaultFileFormat()
+ ? Cache.getProperty("DEFAULT_FILE_FORMAT")
+ : null;
JalviewFileChooser chooser = JalviewFileChooser.forRead(
Cache.getProperty("LAST_DIRECTORY"), fileFormat,
BackupFiles.getEnabled());
@@ -1201,7 +1337,6 @@ public class Desktop extends jalview.jbgui.GDesktop
new FileLoader().LoadFile(viewport, selectedFile, DataSourceType.FILE,
format);
- return null;
});
chooser.showOpenDialog(this);
}
@@ -1257,7 +1392,7 @@ public class Desktop extends jalview.jbgui.GDesktop
Object[] options = new Object[] { MessageManager.getString("action.ok"),
MessageManager.getString("action.cancel") };
- Callable action = () -> {
+ Runnable action = () -> {
@SuppressWarnings("unchecked")
String url = (history instanceof JTextField
? ((JTextField) history).getText()
@@ -1296,8 +1431,7 @@ public class Desktop extends jalview.jbgui.GDesktop
JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
MessageManager.getString("label.url_not_found"),
JvOptionPane.WARNING_MESSAGE);
-
- return null; // Void
+ return;
}
if (viewport != null)
@@ -1310,7 +1444,6 @@ public class Desktop extends jalview.jbgui.GDesktop
new FileLoader().LoadFile(url, DataSourceType.URL, format);
}
}
- return null; // Void
};
String dialogOption = MessageManager
.getString("label.input_alignment_from_url");
@@ -1347,57 +1480,82 @@ public class Desktop extends jalview.jbgui.GDesktop
desktopQuit(true, false);
}
- public QuitHandler.QResponse desktopQuit(boolean ui, boolean disposeFlag)
+ /**
+ * close everything, stash window geometries, and shut down all associated
+ * threads/workers
+ *
+ * @param dispose
+ * - sets the dispose on close flag - JVM may terminate when set
+ * @param terminateJvm
+ * - quit with prejudice - stops the JVM.
+ */
+ public void quitTheDesktop(boolean dispose, boolean terminateJvm)
{
- final Callable doDesktopQuit = () -> {
- Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
- Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
- Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
- storeLastKnownDimensions("", new Rectangle(getBounds().x,
- getBounds().y, getWidth(), getHeight()));
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
+ Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
+ storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
+ getWidth(), getHeight()));
- if (jconsole != null)
- {
- storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
- jconsole.stopConsole();
- }
+ if (jconsole != null)
+ {
+ storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
+ jconsole.stopConsole();
+ }
- if (jvnews != null)
- {
- storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
+ 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);
- if (dialogExecutor != null)
- {
- dialogExecutor.shutdownNow();
- }
+ if (dialogExecutor != null)
+ {
+ dialogExecutor.shutdownNow();
+ }
- closeAll_actionPerformed(null);
+ if (groovyConsole != null)
+ {
+ // suppress a possible repeat prompt to save script
+ groovyConsole.setDirty(false);
+ groovyConsole.exit();
+ }
- if (groovyConsole != null)
- {
- // suppress a possible repeat prompt to save script
- groovyConsole.setDirty(false);
- groovyConsole.exit();
- }
+ if (terminateJvm)
+ {
+ // note that shutdown hook will not be run
+ jalview.bin.Console.debug("Force Quit selected by user");
+ Runtime.getRuntime().halt(0);
+ }
- if (QuitHandler.gotQuitResponse() == QResponse.FORCE_QUIT)
- {
- // note that shutdown hook will not be run
- jalview.bin.Console.debug("Force Quit selected by user");
- Runtime.getRuntime().halt(0);
- }
+ jalview.bin.Console.debug("Quit selected by user");
+ if (dispose)
+ {
+ instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ // instance.dispose();
+ }
+ }
- jalview.bin.Console.debug("Quit selected by user");
- if (disposeFlag)
+ public QuitHandler.QResponse desktopQuit(boolean ui, boolean disposeFlag)
+ {
+ final Runnable doDesktopQuit = () -> {
+
+ // FIRST !! check for aborted quit
+ if (QuitHandler.quitCancelled())
{
- instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
- // instance.dispose();
+ jalview.bin.Console
+ .debug("Quit was cancelled - Desktop aborting quit");
+ return;
}
- instance.quit();
- return null; // Void
+ // Proceed with quitting
+ quitTheDesktop(disposeFlag,
+ QuitHandler.gotQuitResponse() == QResponse.FORCE_QUIT);
+ // and exit the JVM
+ instance.quit();
};
return QuitHandler.getQuitResponse(ui, doDesktopQuit, doDesktopQuit,
@@ -1405,7 +1563,14 @@ public class Desktop extends jalview.jbgui.GDesktop
}
/**
- * Don't call this directly, use desktopQuit() above. Exits the program.
+ * Exits the program and the JVM.
+ *
+ * Don't call this directly
+ *
+ * - use desktopQuit() above to tidy up first.
+ *
+ * - use closeDesktop() to shutdown Jalview without shutting down the JVM
+ *
*/
@Override
public void quit()
@@ -1413,7 +1578,7 @@ public class Desktop extends jalview.jbgui.GDesktop
// this will run the shutdownHook but QuitHandler.getQuitResponse() should
// not run a second time if gotQuitResponse flag has been set (i.e. user
// confirmed quit of some kind).
- System.exit(0);
+ Jalview.exit("Desktop exiting.", ExitCode.OK);
}
private void storeLastKnownDimensions(String string, Rectangle jc)
@@ -1526,7 +1691,8 @@ public class Desktop extends jalview.jbgui.GDesktop
}
} catch (Exception ex)
{
- System.err.println("Error opening help: " + ex.getMessage());
+ jalview.bin.Console
+ .errPrintln("Error opening help: " + ex.getMessage());
}
}
@@ -1544,8 +1710,8 @@ public class Desktop extends jalview.jbgui.GDesktop
{
}
}
- Jalview.setCurrentAlignFrame(null);
- System.out.println("ALL CLOSED");
+ Jalview.getInstance().setCurrentAlignFrame(null);
+ jalview.bin.Console.info("ALL CLOSED");
/*
* reset state of singleton objects as appropriate (clear down session state
@@ -1559,6 +1725,22 @@ public class Desktop extends jalview.jbgui.GDesktop
}
}
+ 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)
{
@@ -1741,7 +1923,8 @@ public class Desktop extends jalview.jbgui.GDesktop
boolean autoSave = projectFile != null && !saveAs
&& BackupFiles.getEnabled();
- // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
+ // jalview.bin.Console.outPrintln("autoSave="+autoSave+",
+ // projectFile='"+projectFile+"',
// saveAs="+saveAs+", Backups
// "+(BackupFiles.getEnabled()?"enabled":"disabled"));
@@ -1776,7 +1959,8 @@ public class Desktop extends jalview.jbgui.GDesktop
// TODO: refactor to Jalview desktop session controller action.
setProgressBar(MessageManager.formatMessage(
"label.saving_jalview_project", new Object[]
- { chosenFile.getName() }), chosenFile.hashCode());
+ { chosenFile.getName() }),
+ IdUtils.newId(IdType.PROGRESS, chosenFile));
Cache.setProperty("LAST_DIRECTORY", chosenFile.getParent());
// TODO catch and handle errors for savestate
// TODO prevent user from messing with the Desktop whilst we're saving
@@ -1810,7 +1994,7 @@ public class Desktop extends jalview.jbgui.GDesktop
MessageManager.getString("label.couldnt_save_project"),
JvOptionPane.WARNING_MESSAGE);
}
- setProgressBar(null, chosenFile.hashCode());
+ setProgressBar(null, IdUtils.newId(IdType.PROGRESS, chosenFile));
}
}).start();
}
@@ -1880,7 +2064,6 @@ public class Desktop extends jalview.jbgui.GDesktop
}
}
}, "Project Loader").start();
- return null;
});
chooser.showOpenDialog(this);
@@ -1987,7 +2170,7 @@ public class Desktop extends jalview.jbgui.GDesktop
return null;
}
List aps = new ArrayList<>();
- AlignFrame[] frames = getAlignFrames();
+ AlignFrame[] frames = Desktop.getDesktopAlignFrames();
if (frames == null)
{
return null;
@@ -2024,7 +2207,7 @@ public class Desktop extends jalview.jbgui.GDesktop
List viewp = new ArrayList<>();
if (desktop != null)
{
- AlignFrame[] frames = Desktop.getAlignFrames();
+ AlignFrame[] frames = Desktop.getDesktopAlignFrames();
for (AlignFrame afr : frames)
{
@@ -2385,12 +2568,12 @@ public class Desktop extends jalview.jbgui.GDesktop
*
* @return an array of AlignFrame, or null if none found
*/
- public static AlignFrame[] getAlignFrames()
+ @Override
+ public AlignFrame[] getAlignFrames()
{
- if (Jalview.isHeadlessMode())
+ if (desktop == null)
{
- // Desktop.desktop is null in headless mode
- return new AlignFrame[] { Jalview.currentAlignFrame };
+ return null;
}
JInternalFrame[] frames = Desktop.desktop.getAllFrames();
@@ -2432,6 +2615,25 @@ public class Desktop extends jalview.jbgui.GDesktop
}
/**
+ * static version
+ */
+ public static AlignFrame[] getDesktopAlignFrames()
+ {
+ if (Jalview.isHeadlessMode())
+ {
+ // Desktop.desktop is null in headless mode
+ return Jalview.getInstance().getAlignFrames();
+ }
+
+ if (instance != null && desktop != null)
+ {
+ return instance.getAlignFrames();
+ }
+
+ return null;
+ }
+
+ /**
* Returns an array of any AppJmol frames in the Desktop (or null if none).
*
* @return
@@ -2473,7 +2675,7 @@ public class Desktop extends jalview.jbgui.GDesktop
openGroovyConsole();
} catch (Exception ex)
{
- jalview.bin.Console.error("Groovy Shell Creation failed.", ex);
+ jalview.bin.Console.error("Groovy Console creation failed.", ex);
JvOptionPane.showInternalMessageDialog(Desktop.desktop,
MessageManager.getString("label.couldnt_create_groovy_shell"),
@@ -2489,8 +2691,11 @@ public class Desktop extends jalview.jbgui.GDesktop
{
if (groovyConsole == null)
{
- groovyConsole = new groovy.ui.Console();
- groovyConsole.setVariable("Jalview", this);
+ JalviewObjectI j = new JalviewObject(this);
+ groovyConsole = new groovy.console.ui.Console();
+ groovyConsole.setVariable(JalviewObjectI.jalviewObjectName, j);
+ groovyConsole.setVariable(JalviewObjectI.currentAlFrameName,
+ getCurrentAlignFrame());
groovyConsole.run();
/*
@@ -2563,7 +2768,7 @@ public class Desktop extends jalview.jbgui.GDesktop
*/
groovyShell.setEnabled(!enabled);
- AlignFrame[] alignFrames = getAlignFrames();
+ AlignFrame[] alignFrames = getDesktopAlignFrames();
if (alignFrames != null)
{
for (AlignFrame af : alignFrames)
@@ -2874,7 +3079,16 @@ public class Desktop extends jalview.jbgui.GDesktop
*/
public static void showUrl(final String url)
{
- showUrl(url, Desktop.instance);
+ if (url != null && !url.trim().equals(""))
+ {
+ jalview.bin.Console.info("Opening URL: " + url);
+ showUrl(url, Desktop.instance);
+ }
+ else
+ {
+ jalview.bin.Console.warn("Ignoring attempt to show an empty URL.");
+ }
+
}
/**
@@ -2898,7 +3112,7 @@ public class Desktop extends jalview.jbgui.GDesktop
{
progress.setProgressBar(MessageManager
.formatMessage("status.opening_params", new Object[]
- { url }), this.hashCode());
+ { url }), IdUtils.newId(IdType.PROGRESS, this));
}
jalview.util.BrowserLauncher.openURL(url);
} catch (Exception ex)
@@ -2913,7 +3127,8 @@ public class Desktop extends jalview.jbgui.GDesktop
}
if (progress != null)
{
- progress.setProgressBar(null, this.hashCode());
+ progress.setProgressBar(null,
+ IdUtils.newId(IdType.PROGRESS, this));
}
}
}).start();
@@ -2960,7 +3175,7 @@ public class Desktop extends jalview.jbgui.GDesktop
/**
* 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
@@ -2970,9 +3185,9 @@ public class Desktop extends jalview.jbgui.GDesktop
/**
* pause the queue
*/
- private java.util.concurrent.Semaphore block = new Semaphore(0);
+ private Semaphore block = new Semaphore(0);
- private static groovy.ui.Console groovyConsole;
+ private static groovy.console.ui.Console groovyConsole;
/**
* add another dialog thread to the queue
@@ -2988,12 +3203,7 @@ public class Desktop extends jalview.jbgui.GDesktop
{
if (dialogPause)
{
- try
- {
- block.acquire();
- } catch (InterruptedException x)
- {
- }
+ acquireDialogQueue();
}
if (instance == null)
{
@@ -3011,12 +3221,41 @@ public class Desktop extends jalview.jbgui.GDesktop
});
}
+ private boolean dialogQueueStarted = false;
+
public void startDialogQueue()
{
+ if (dialogQueueStarted)
+ {
+ return;
+ }
// set the flag so we don't pause waiting for another permit and semaphore
// the current task to begin
- dialogPause = false;
+ releaseDialogQueue();
+ dialogQueueStarted = true;
+ }
+
+ public void acquireDialogQueue()
+ {
+ try
+ {
+ block.acquire();
+ dialogPause = true;
+ } catch (InterruptedException e)
+ {
+ jalview.bin.Console.debug("Interruption when acquiring DialogueQueue",
+ e);
+ }
+ }
+
+ public void releaseDialogQueue()
+ {
+ if (!dialogPause)
+ {
+ return;
+ }
block.release();
+ dialogPause = false;
}
/**
@@ -3051,7 +3290,15 @@ public class Desktop extends jalview.jbgui.GDesktop
String title = "View of desktop";
ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
title);
- exporter.doExport(of, this, width, height, title);
+ try
+ {
+ exporter.doExport(of, this, width, height, title);
+ } catch (ImageOutputException ioex)
+ {
+ jalview.bin.Console.error(
+ "Unexpected error whilst writing Jalview desktop snapshot as EPS",
+ ioex);
+ }
}
/**
@@ -3202,7 +3449,7 @@ public class Desktop extends jalview.jbgui.GDesktop
myTopFrame.setDisplayedView(myTopFrame.alignPanel);
}
- public static groovy.ui.Console getGroovyConsole()
+ public static groovy.console.ui.Console getGroovyConsole()
{
return groovyConsole;
}
@@ -3259,7 +3506,7 @@ public class Desktop extends jalview.jbgui.GDesktop
{
if (Platform.isAMacAndNotJS())
{
- System.err.println(
+ jalview.bin.Console.errPrintln(
"Please ignore plist error - occurs due to problem with java 8 on OSX");
}
}
@@ -3491,4 +3738,183 @@ public class Desktop extends jalview.jbgui.GDesktop
jalview.bin.Console.debug(Cache.getStackTraceString(e));
}
}
+
+ /**
+ * closes the current instance window, but leaves the JVM running. Bypasses
+ * any shutdown prompts, but does not set window dispose on close in case JVM
+ * terminates.
+ */
+ public static void closeDesktop()
+ {
+ if (Desktop.instance != null)
+ {
+ Desktop us = Desktop.instance;
+ Desktop.instance.quitTheDesktop(false, false);
+ // call dispose in a separate thread - try to avoid indirect deadlocks
+ if (us != null)
+ {
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ ExecutorService dex = us.dialogExecutor;
+ if (dex != null)
+ {
+ dex.shutdownNow();
+ us.dialogExecutor = null;
+ us.block.drainPermits();
+ }
+ us.dispose();
+ }
+ }).start();
+ }
+ }
+ }
+
+ /**
+ * checks if any progress bars are being displayed in any of the windows
+ * managed by the desktop
+ *
+ * @return
+ */
+ public boolean operationsAreInProgress()
+ {
+ JInternalFrame[] frames = getAllFrames();
+ for (JInternalFrame frame : frames)
+ {
+ if (frame instanceof IProgressIndicator)
+ {
+ if (((IProgressIndicator) frame).operationInProgress())
+ {
+ return true;
+ }
+ }
+ }
+ return operationInProgress();
+ }
+
+ /**
+ * keep track of modal JvOptionPanes open as modal dialogs for AlignFrames.
+ * The way the modal JInternalFrame is made means it cannot be a child of an
+ * AlignFrame, so closing the AlignFrame might leave the modal open :(
+ */
+ private static Map alignFrameModalMap = new HashMap<>();
+
+ protected static void addModal(AlignFrame af, JInternalFrame jif)
+ {
+ alignFrameModalMap.put(af, jif);
+ }
+
+ protected static void closeModal(AlignFrame af)
+ {
+ if (!alignFrameModalMap.containsKey(af))
+ {
+ return;
+ }
+ JInternalFrame jif = alignFrameModalMap.get(af);
+ if (jif != null)
+ {
+ try
+ {
+ jif.setClosed(true);
+ } catch (PropertyVetoException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ alignFrameModalMap.remove(af);
+ }
+
+ public void nonBlockingDialog(String title, String message, String button,
+ int type, boolean scrollable, boolean modal)
+ {
+ nonBlockingDialog(title, message, null, button, type, scrollable, false,
+ modal, -1);
+ }
+
+ public void nonBlockingDialog(String title, String message,
+ String boxtext, String button, int type, boolean scrollable,
+ boolean html, boolean modal, int timeout)
+ {
+ nonBlockingDialog(32, 2, title, message, boxtext, button, type,
+ scrollable, html, modal, timeout);
+ }
+
+ public void nonBlockingDialog(int width, int height, String title,
+ String message, String boxtext, String button, int type,
+ boolean scrollable, boolean html, boolean modal, int timeout)
+ {
+ if (type < 0)
+ {
+ type = JvOptionPane.WARNING_MESSAGE;
+ }
+ JLabel jl = new JLabel(message);
+
+ JTextComponent jtc = null;
+ if (html)
+ {
+ JTextPane jtp = new JTextPane();
+ jtp.setContentType("text/html");
+ jtp.setEditable(false);
+ jtp.setAutoscrolls(true);
+ jtp.setText(boxtext);
+
+ jtc = jtp;
+ }
+ else
+ {
+ JTextArea jta = new JTextArea(height, width);
+ // jta.setLineWrap(true);
+ jta.setEditable(false);
+ jta.setWrapStyleWord(true);
+ jta.setAutoscrolls(true);
+ jta.setText(boxtext);
+
+ jtc = jta;
+ }
+
+ JScrollPane jsp = scrollable
+ ? new JScrollPane(jtc, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)
+ : null;
+
+ JvOptionPane jvp = JvOptionPane.newOptionDialog(this);
+
+ JPanel jp = new JPanel();
+ jp.setLayout(new BoxLayout(jp, BoxLayout.Y_AXIS));
+
+ if (message != null)
+ {
+ jl.setAlignmentX(Component.LEFT_ALIGNMENT);
+ jp.add(jl);
+ }
+ if (boxtext != null)
+ {
+ if (scrollable)
+ {
+ jsp.setAlignmentX(Component.LEFT_ALIGNMENT);
+ jp.add(jsp);
+ }
+ else
+ {
+ jtc.setAlignmentX(Component.LEFT_ALIGNMENT);
+ jp.add(jtc);
+ }
+ }
+
+ jvp.setResponseHandler(JOptionPane.YES_OPTION, () -> {
+ });
+ jvp.setTimeout(timeout);
+ JButton jb = new JButton(button);
+ jvp.showDialogOnTopAsync(this, jp, title, JOptionPane.YES_OPTION, type,
+ null, new Object[]
+ { button }, button, modal, new JButton[] { jb }, false);
+ }
+
+ @Override
+ public AlignFrame getCurrentAlignFrame()
+ {
+ return Jalview.getInstance().getCurrentAlignFrame();
+ }
}