+
+ public static final String debugScaleMessage = "Desktop graphics transform scale=";
+
+ private static boolean debugScaleMessageDone = false;
+
+ public static void debugScaleMessage(Graphics g)
+ {
+ if (debugScaleMessageDone)
+ {
+ return;
+ }
+ // output used by tests to check HiDPI scaling settings in action
+ try
+ {
+ Graphics2D gg = (Graphics2D) g;
+ if (gg != null)
+ {
+ AffineTransform t = gg.getTransform();
+ double scaleX = t.getScaleX();
+ double scaleY = t.getScaleY();
+ jalview.bin.Console.debug(debugScaleMessage + scaleX + " (X)");
+ jalview.bin.Console.debug(debugScaleMessage + scaleY + " (Y)");
+ debugScaleMessageDone = true;
+ }
+ else
+ {
+ jalview.bin.Console.debug("Desktop graphics null");
+ }
+ } catch (Exception e)
+ {
+ 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);
+ }
+