import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
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;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
+import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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;
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.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
+import jalview.bin.Jalview.ExitCode;
+import jalview.bin.argparser.Arg;
import jalview.datamodel.Alignment;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
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;
* Send this message to stderr as the warning that follows (due to
* reflection) also goes to stderr.
*/
- System.err.println(
+ 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";
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);
* @j2sIgnore
*/
{
- jconsole = new Console(this, showjconsole);
- jconsole.setHeader(Cache.getVersionDetailsForConsole());
- showConsole(showjconsole);
-
showNews.setVisible(false);
experimentalFeatures.setSelected(showExperimental());
}
// 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.");
}
});
desktop.addMouseListener(ma);
+
+ if (Platform.isJS())
+ {
+ // used for jalviewjsTest
+ jalview.bin.Console.info("JALVIEWJS: CREATED DESKTOP");
+ }
+
}
/**
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
}
} catch (Exception ex)
{
- System.out.println(
+ jalview.bin.Console.outPrintln(
"Unable to paste alignment from system clipboard:\n" + ex);
}
}
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);
@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());
// 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).
- Jalview.exit("Desktop exiting.", 0);
+ Jalview.exit("Desktop exiting.", ExitCode.OK);
}
private void storeLastKnownDimensions(String string, Rectangle jc)
}
} catch (Exception ex)
{
- System.err.println("Error opening help: " + ex.getMessage());
+ jalview.bin.Console
+ .errPrintln("Error opening help: " + ex.getMessage());
}
}
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"));
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"),
{
if (groovyConsole == null)
{
- groovyConsole = new groovy.ui.Console();
+ groovyConsole = new groovy.console.ui.Console();
groovyConsole.setVariable("Jalview", this);
groovyConsole.run();
/**
* 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
{
if (dialogPause)
{
- try
- {
- block.acquire();
- } catch (InterruptedException x)
- {
- }
+ acquireDialogQueue();
}
if (instance == null)
{
});
}
+ 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;
}
/**
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);
+ }
}
/**
myTopFrame.setDisplayedView(myTopFrame.alignPanel);
}
- public static groovy.ui.Console getGroovyConsole()
+ public static groovy.console.ui.Console getGroovyConsole()
{
return groovyConsole;
}
{
if (Platform.isAMacAndNotJS())
{
- System.err.println(
+ jalview.bin.Console.errPrintln(
"Please ignore plist error - occurs due to problem with java 8 on OSX");
}
}
jalview.bin.Console.debug(Cache.getStackTraceString(e));
}
}
+
+ /**
+ * closes the current instance window, disposes and forgets about it.
+ */
+ public static void closeDesktop()
+ {
+ if (Desktop.instance != null)
+ {
+ Desktop.instance.closeAll_actionPerformed(null);
+ Desktop.instance.setVisible(false);
+ Desktop us = Desktop.instance;
+ Desktop.instance = null;
+ // call dispose in a separate thread - try to avoid indirect deadlocks
+ 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<AlignFrame, JInternalFrame> 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);
+ }
+
}