X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FDesktop.java;h=3931a644b08c86d9e38574b9a4ca4125cf884197;hb=refs%2Fheads%2FJAL-4152-typed-singleton-provider;hp=4b25ef2bfa5d127ecb4c98561e1a08fdf33e3768;hpb=1cb6ca4f5c149e6563ccbc45e104c4716f76764e;p=jalview.git diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 4b25ef2..3931a64 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -20,11 +20,13 @@ */ package jalview.gui; +import java.util.Locale; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Point; import java.awt.Rectangle; @@ -47,20 +49,26 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.awt.geom.AffineTransform; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.lang.reflect.Field; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.ListIterator; import java.util.Vector; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import java.util.concurrent.Semaphore; import javax.swing.AbstractAction; @@ -111,6 +119,7 @@ import jalview.io.FormatAdapter; import jalview.io.IdentifyFile; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; +import jalview.jbgui.APQHandlers; import jalview.jbgui.GDesktop; import jalview.jbgui.GSplitFrame; import jalview.jbgui.GStructureViewer; @@ -118,12 +127,14 @@ import jalview.project.Jalview2XML; import jalview.structure.StructureSelectionManager; import jalview.urls.IdOrgSettings; import jalview.util.BrowserLauncher; +import jalview.util.ChannelProperties; import jalview.util.ImageMaker.TYPE; +import jalview.util.LaunchUtils; import jalview.util.MessageManager; import jalview.util.Platform; -import jalview.util.ShortcutKeyMaskExWrapper; import jalview.util.UrlConstants; import jalview.viewmodel.AlignmentViewport; +import jalview.ws.WSDiscovererI; import jalview.ws.params.ParamManager; import jalview.ws.utils.UrlDownloadClient; @@ -140,12 +151,29 @@ public class Desktop extends GDesktop StructureSelectionManagerProvider, ApplicationSingletonI { - private static final String CITATION = "

Development managed by The Barton Group, University of Dundee, Scotland, UK.
" - + "

For help, see the FAQ at www.jalview.org/faq and/or join the jalview-discuss@jalview.org mailing list" - + "

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" - + "
Bioinformatics doi: 10.1093/bioinformatics/btp033"; + private static final String CITATION; + static { + URL bg_logo_url = ChannelProperties.getImageURL("bg_logo." + String.valueOf(SplashScreen.logoSize)); + URL uod_logo_url = ChannelProperties.getImageURL("uod_banner." + String.valueOf(SplashScreen.logoSize)); + boolean logo = (bg_logo_url != null || uod_logo_url != null); + StringBuilder sb = new StringBuilder(); + sb.append( + "

Jalview is free software released under GPLv3.

Development is managed by The Barton Group, University of Dundee, Scotland, UK."); + if (logo) + { + sb.append("
"); + } + sb.append(bg_logo_url == null ? "" : "\"Barton"); + sb.append(uod_logo_url == null ? "" + : " \"University"); + sb.append( + "

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" + + "
Bioinformatics doi: 10.1093/bioinformatics/btp033"); + CITATION = sb.toString(); + } private static final String DEFAULT_AUTHORS = "The Jalview Authors (See AUTHORS file for current list)"; @@ -159,12 +187,15 @@ public class Desktop extends GDesktop private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES"; - protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT"; + public static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT"; public static HashMap savingFiles = new HashMap(); + @SuppressWarnings("deprecation") private JalviewChangeSupport changeSupport = new JalviewChangeSupport(); + public static boolean nosplash = false; + /** * news reader - null if it was never started. */ @@ -176,6 +207,7 @@ public class Desktop extends GDesktop * @param listener * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener) */ + @Deprecated public void addJalviewPropertyChangeListener( PropertyChangeListener listener) { @@ -188,6 +220,7 @@ public class Desktop extends GDesktop * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String, * java.beans.PropertyChangeListener) */ + @Deprecated public void addJalviewPropertyChangeListener(String propertyName, PropertyChangeListener listener) { @@ -200,6 +233,7 @@ public class Desktop extends GDesktop * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String, * java.beans.PropertyChangeListener) */ + @Deprecated public void removeJalviewPropertyChangeListener(String propertyName, PropertyChangeListener listener) { @@ -225,8 +259,7 @@ public class Desktop extends GDesktop public static Desktop getInstance() { return Jalview.isHeadlessMode() ? null - : (Desktop) ApplicationSingletonProvider - .getInstance(Desktop.class); + : ApplicationSingletonProvider.getInstance(Desktop.class); } public static StructureSelectionManager getStructureSelectionManager() @@ -378,7 +411,7 @@ public class Desktop extends GDesktop */ private Desktop() { - Cache.initLogger(); + super(); try { /** @@ -388,36 +421,77 @@ public class Desktop extends GDesktop */ doConfigureStructurePrefs(); - setTitle("Jalview " + Cache.getProperty("VERSION")); - /* - if (!Platform.isAMac()) - { - // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - } - else + setTitle(ChannelProperties.getProperty("app_name") + " " + Cache.getProperty("VERSION")); + + /** + * Set taskbar "grouped windows" name for linux desktops (works in GNOME and + * KDE). This uses sun.awt.X11.XToolkit.awtAppClassName which is not officially + * documented or guaranteed to exist, so we access it via reflection. There + * appear to be unfathomable criteria about what this string can contain, and it + * if doesn't meet those criteria then "java" (KDE) or "jalview-bin-Jalview" + * (GNOME) is used. "Jalview", "Jalview Develop" and "Jalview Test" seem okay, + * but "Jalview non-release" does not. The reflection access may generate a + * warning: WARNING: An illegal reflective access operation has occurred + * WARNING: Illegal reflective access by jalview.gui.Desktop () to field + * sun.awt.X11.XToolkit.awtAppClassName which I don't think can be avoided. + */ + if (Platform.isLinux()) + { + if (LaunchUtils.getJavaVersion() >= 11) { - this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + jalview.bin.Console.info( + "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."); } - */ - try { - APQHandlers.setAPQHandlers(this); - } catch (Throwable t) - { - System.out.println("Error setting APQHandlers: " + t.toString()); - // t.printStackTrace(); - } + Toolkit xToolkit = Toolkit.getDefaultToolkit(); + Field[] declaredFields = xToolkit.getClass().getDeclaredFields(); + Field awtAppClassNameField = null; - addWindowListener(new WindowAdapter() - { + if (Arrays.stream(declaredFields).anyMatch(f -> f.getName().equals("awtAppClassName"))) { + awtAppClassNameField = xToolkit.getClass().getDeclaredField("awtAppClassName"); + } - @Override - public void windowClosing(WindowEvent ev) + String title = ChannelProperties.getProperty("app_name"); + if (awtAppClassNameField != null) { + awtAppClassNameField.setAccessible(true); + awtAppClassNameField.set(xToolkit, title); + } + else { - quit(); + jalview.bin.Console.debug("XToolkit: awtAppClassName not found"); } - }); + } catch (Exception e) + { + jalview.bin.Console.debug("Error setting awtAppClassName"); + jalview.bin.Console.trace(Cache.getStackTraceString(e)); + } + } + + /** + * APQHandlers sets handlers for About, Preferences and Quit actions peculiar to + * macOS's application menu. APQHandlers will check to see if a handler is + * supported before setting it. + */ + try { + APQHandlers.setAPQHandlers(this); + } catch (Exception e) { + System.out.println("Cannot set APQHandlers"); + // e.printStackTrace(); + } catch (Throwable t) { + jalview.bin.Console.warn("Error setting APQHandlers: " + t.toString()); + jalview.bin.Console.trace(Cache.getStackTraceString(t)); + } + + setIconImages(ChannelProperties.getIconList()); + + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent ev) { + quit(); + } + }); boolean selmemusage = Cache.getDefault("SHOW_MEMUSAGE", false); @@ -442,6 +516,7 @@ public class Desktop extends GDesktop getContentPane().add(desktopPane, BorderLayout.CENTER); desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); + // This line prevents Windows Look&Feel resizing all new windows to // maximum // if previous window was maximised @@ -465,8 +540,6 @@ public class Desktop extends GDesktop setBounds(xPos, yPos, 900, 650); } - getIdentifiersOrgData(); - if (!Platform.isJS()) /** * Java only @@ -478,51 +551,59 @@ public class Desktop extends GDesktop jconsole.setHeader(Cache.getVersionDetailsForConsole()); showConsole(showjconsole); - showNews.setVisible(false); + showNews.setVisible(false); // not sure if we should only do this for interactive session? experimentalFeatures.setSelected(showExperimental()); - checkURLLinks(); - - // Spawn a thread that shows the splashscreen + getIdentifiersOrgData(); - SwingUtilities.invokeLater(new Runnable() + if (Jalview.isInteractive()) { - @Override - public void run() - { - new SplashScreen(true); + // disabled for SeqCanvasTest + checkURLLinks(); + + // Spawn a thread that shows the splashscreen + if (!nosplash) { + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + new SplashScreen(true); + } + }); } - }); - // Thread off a new instance of the file chooser - this reduces the time - // it - // takes to open it later on. - new Thread(new Runnable() - { - @Override - public void run() + // Thread off a new instance of the file chooser - this reduces the + // time + // it + // takes to open it later on. + new Thread(new Runnable() { - Cache.log.debug("Filechooser init thread started."); - String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT"); - JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), - fileFormat); - Cache.log.debug("Filechooser init thread finished."); - } - }).start(); - // Add the service change listener - changeSupport.addJalviewPropertyChangeListener("services", - new PropertyChangeListener() - { - - @Override - public void propertyChange(PropertyChangeEvent evt) + @Override + public void run() + { + jalview.bin.Console.debug("Filechooser init thread started."); + String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT"); + JalviewFileChooser.forRead( + Cache.getProperty("LAST_DIRECTORY"), fileFormat); + jalview.bin.Console.debug("Filechooser init thread finished."); + } + }).start(); + // Add the service change listener + changeSupport.addJalviewPropertyChangeListener("services", + new PropertyChangeListener() { - Cache.log.debug("Firing service changed event for " - + evt.getNewValue()); - JalviewServicesChanged(evt); - } - }); + + @Override + public void propertyChange(PropertyChangeEvent evt) + { + jalview.bin.Console.debug("Firing service changed event for " + + evt.getNewValue()); + JalviewServicesChanged(evt); + } + }); + } } this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this)); @@ -547,7 +628,6 @@ public class Desktop extends GDesktop showPasteMenu(evt.getX(), evt.getY()); } } - @Override public void mouseReleased(MouseEvent evt) { @@ -562,7 +642,6 @@ public class Desktop extends GDesktop { t.printStackTrace(); } - } /** @@ -581,74 +660,64 @@ public class Desktop extends GDesktop public void doConfigureStructurePrefs() { // configure services - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(this); - if (Cache.getDefault(Preferences.ADD_SS_ANN, true)) - { - ssm.setAddTempFacAnnot( - Cache.getDefault(Preferences.ADD_TEMPFACT_ANN, true)); - ssm.setProcessSecondaryStructure( - Cache.getDefault(Preferences.STRUCT_FROM_PDB, true)); - ssm.setSecStructServices( - Cache.getDefault(Preferences.USE_RNAVIEW, true)); - } - else - { + StructureSelectionManager ssm = StructureSelectionManager.getStructureSelectionManager(this); + if (Cache.getDefault(Preferences.ADD_SS_ANN, true)) { + ssm.setAddTempFacAnnot(Cache.getDefault(Preferences.ADD_TEMPFACT_ANN, true)); + ssm.setProcessSecondaryStructure(Cache.getDefault(Preferences.STRUCT_FROM_PDB, true)); + // JAL-3915 - RNAView is no longer an option so this has no effect + ssm.setSecStructServices(Cache.getDefault(Preferences.USE_RNAVIEW, false)); + } else { ssm.setAddTempFacAnnot(false); ssm.setProcessSecondaryStructure(false); ssm.setSecStructServices(false); } } - public void checkForNews() - { + public void checkForNews() { final Desktop me = this; // Thread off the news reader, in case there are connection problems. - new Thread(new Runnable() - { + new Thread(new Runnable() { @Override public void run() { - Cache.log.debug("Starting news thread."); + jalview.bin.Console.debug("Starting news thread."); jvnews = new BlogReader(me); showNews.setVisible(true); - Cache.log.debug("Completed news thread."); + jalview.bin.Console.debug("Completed news thread."); } }).start(); } - public void getIdentifiersOrgData() - { - // Thread off the identifiers fetcher - new Thread(new Runnable() - { - @Override - public void run() - { - Cache.log.debug("Downloading data from identifiers.org"); - try - { - UrlDownloadClient.download(IdOrgSettings.getUrl(), - IdOrgSettings.getDownloadLocation()); - } catch (IOException e) + public void getIdentifiersOrgData() { + if (Cache.getProperty("NOIDENTIFIERSSERVICE") == null) { + // Thread off the identifiers fetcher + new Thread(new Runnable() { + @Override + public void run() { - Cache.log.debug("Exception downloading identifiers.org data" - + e.getMessage()); + jalview.bin.Console.debug("Downloading data from identifiers.org"); + try + { + UrlDownloadClient.download(IdOrgSettings.getUrl(), + IdOrgSettings.getDownloadLocation()); + } catch (IOException e) + { + jalview.bin.Console.debug("Exception downloading identifiers.org data" + + e.getMessage()); + } } - } - }).start(); - + }).start(); + } } @Override - protected void showNews_actionPerformed(ActionEvent e) - { + protected void showNews_actionPerformed(ActionEvent e) { showNews(showNews.isSelected()); } void showNews(boolean visible) { - Cache.log.debug((visible ? "Showing" : "Hiding") + " news."); + jalview.bin.Console.debug((visible ? "Showing" : "Hiding") + " news."); showNews.setSelected(visible); if (visible && !jvnews.isVisible()) { @@ -684,19 +753,15 @@ public class Desktop extends GDesktop String y = Cache.getProperty(windowName + "SCREEN_Y"); String width = Cache.getProperty(windowName + "SCREEN_WIDTH"); String height = Cache.getProperty(windowName + "SCREEN_HEIGHT"); - if ((x != null) && (y != null) && (width != null) && (height != null)) - { - int ix = Integer.parseInt(x), iy = Integer.parseInt(y), - iw = Integer.parseInt(width), ih = Integer.parseInt(height); - if (Cache.getProperty("SCREENGEOMETRY_WIDTH") != null) - { + if ((x != null) && (y != null) && (width != null) && (height != null)) { + int ix = Integer.parseInt(x), iy = Integer.parseInt(y), iw = Integer.parseInt(width), + ih = Integer.parseInt(height); + if (Cache.getProperty("SCREENGEOMETRY_WIDTH") != null) { // attempt #1 - try to cope with change in screen geometry - this // version doesn't preserve original jv aspect ratio. // take ratio of current screen size vs original screen size. - double sw = ((1f * screenSize.width) / (1f * Integer - .parseInt(Cache.getProperty("SCREENGEOMETRY_WIDTH")))); - double sh = ((1f * screenSize.height) / (1f * Integer - .parseInt(Cache.getProperty("SCREENGEOMETRY_HEIGHT")))); + double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(Cache.getProperty("SCREENGEOMETRY_WIDTH")))); + double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(Cache.getProperty("SCREENGEOMETRY_HEIGHT")))); // rescale the bounds depending upon the current screen geometry. ix = (int) (ix * sw); iw = (int) (iw * sw); @@ -704,17 +769,17 @@ public class Desktop extends GDesktop ih = (int) (ih * sh); while (ix >= screenSize.width) { - Cache.log.debug( + jalview.bin.Console.debug( "Window geometry location recall error: shifting horizontal to within screenbounds."); ix -= screenSize.width; } while (iy >= screenSize.height) { - Cache.log.debug( + jalview.bin.Console.debug( "Window geometry location recall error: shifting vertical to within screenbounds."); iy -= screenSize.height; } - Cache.log.debug( + jalview.bin.Console.debug( "Got last known dimensions for " + windowName + ": x:" + ix + " y:" + iy + " width:" + iw + " height:" + ih); } @@ -767,56 +832,7 @@ public class Desktop extends GDesktop } } -// /** -// * Add an internal frame to the Jalview desktop that is allowed to be resized, -// * has a minimum size of 300px and might or might not be visible -// * -// * @param frame -// * Frame to show -// * @param title -// * Visible Title -// * @param makeVisible -// * When true, display frame immediately, otherwise, caller must call -// * setVisible themselves. -// * @param w -// * width -// * @param h -// * height -// */ -// @Deprecated -// public static synchronized void addInternalFrame( -// final JInternalFrame frame, String title, boolean makeVisible, -// int w, int h) -// { -// // textbox, web services, sequenceFetcher, featureSettings -// getInstance().addFrame(frame, title, makeVisible, w, h, -// FRAME_ALLOW_RESIZE, FRAME_SET_MIN_SIZE_300); -// } -// -// /** -// * Add an internal frame to the Jalview desktop that is visible, has a minimum -// * size of 300px, and may or may not be resizable -// * -// * @param frame -// * Frame to show -// * @param title -// * Visible Title -// * @param w -// * width -// * @param h -// * height -// * @param resizable -// * Allow resize -// */ -// @Deprecated -// public static synchronized void addInternalFrame( -// final JInternalFrame frame, String title, int w, int h, -// boolean resizable) -// { -// // annotation, font, calculation, user-defined colors -// getInstance().addFrame(frame, title, FRAME_MAKE_VISIBLE, w, h, -// resizable, FRAME_SET_MIN_SIZE_300); -// } + /** * Adds and opens the given frame to the desktop that is visible, allowed to @@ -835,7 +851,8 @@ public class Desktop extends GDesktop final JInternalFrame frame, String title, int w, int h) { // 58 classes - getInstance().addFrame(frame, title, Desktop.FRAME_MAKE_VISIBLE, w, h, + + addInternalFrame(frame, title, Desktop.FRAME_MAKE_VISIBLE, w, h, FRAME_ALLOW_RESIZE, FRAME_SET_MIN_SIZE_300); } @@ -863,8 +880,21 @@ public class Desktop extends GDesktop final JInternalFrame frame, String title, boolean makeVisible, int w, int h, boolean resizable, boolean ignoreMinSize) { - // 15 classes - getInstance().addFrame(frame, title, makeVisible, w, h, resizable, + // 15 classes call this method directly. + + + // TODO: allow callers to determine X and Y position of frame (eg. via + // bounds object). + // TODO: consider fixing method to update entries in the window submenu with + // the current window title + + frame.setTitle(title); + if (frame.getWidth() < 1 || frame.getHeight() < 1) + { + frame.setSize(w, h); + } + if (getInstance() != null) + getInstance().addFrame(frame, makeVisible, resizable, ignoreMinSize); } @@ -881,31 +911,14 @@ public class Desktop extends GDesktop public final static boolean FRAME_ALLOW_ANY_SIZE = true; public final static boolean FRAME_SET_MIN_SIZE_300 = false; - - private void addFrame(JInternalFrame frame, String title, - boolean makeVisible, int w, int h, boolean resizable, + + private void addFrame(JInternalFrame frame, + boolean makeVisible, boolean resizable, boolean ignoreMinSize) { - // TODO: allow callers to determine X and Y position of frame (eg. via - // bounds object). - // TODO: consider fixing method to update entries in the window submenu with - // the current window title - - frame.setTitle(title); - if (frame.getWidth() < 1 || frame.getHeight() < 1) - { - frame.setSize(w, h); - } - // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN - // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN - // IF JALVIEW IS RUNNING HEADLESS - // /////////////////////////////////////////////// - if (Jalview.isHeadlessMode()) - { - return; - } openFrameCount++; + boolean isEmbedded = (Platform.getEmbeddedAttribute(frame, "id") != null); boolean hasEmbeddedSize = (Platform.getDimIfEmbedded(frame, -1, -1) != null); @@ -914,6 +927,7 @@ public class Desktop extends GDesktop if (!ignoreMinSize) { + // Set default dimension for Alignment Frame window. // The Alignment Frame window could be added from a number of places, // hence, @@ -935,6 +949,7 @@ public class Desktop extends GDesktop frame.setMaximizable(resizable); frame.setIconifiable(resizable); frame.setOpaque(Platform.isJS()); + if (!isEmbedded && frame.getX() < 1 && frame.getY() < 1) { frame.setLocation(xOffset * openFrameCount, @@ -945,7 +960,7 @@ public class Desktop extends GDesktop * add an entry for the new frame in the Window menu * (and remove it when the frame is closed) */ - final JMenuItem menuItem = new JMenuItem(title); + final JMenuItem menuItem = new JMenuItem(frame.getTitle()); frame.addInternalFrameListener(new InternalFrameAdapter() { @Override @@ -999,6 +1014,7 @@ public class Desktop extends GDesktop } catch (java.beans.PropertyVetoException ex) { // System.err.println(ex.toString()); + } } }); @@ -1018,8 +1034,8 @@ public class Desktop extends GDesktop { } catch (java.lang.ClassCastException cex) { - Cache.log.warn( - "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869", + jalview.bin.Console.warn( + "Squashed a possible GUI implementation error. If you can recreate this, please look at https://issues.jalview.org/browse/JAL-869", cex); } } @@ -1032,6 +1048,7 @@ public class Desktop extends GDesktop */ private static void setKeyBindings(JInternalFrame frame) { + @SuppressWarnings("serial") final Action closeAction = new AbstractAction() { @Override @@ -1044,10 +1061,8 @@ public class Desktop extends GDesktop /* * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action */ - KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, - InputEvent.CTRL_DOWN_MASK); - KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, - ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()); + KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK); + KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, Platform.SHORTCUT_KEY_MASK); InputMap inputMap = frame .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); @@ -1230,7 +1245,7 @@ public class Desktop extends GDesktop * JS: (pending JAL-3038) a plain text field */ JComponent history; - String urlBase = "http://www."; + String urlBase = "https://www."; if (Platform.isJS()) { history = new JTextField(urlBase, 35); @@ -1266,26 +1281,16 @@ public class Desktop extends GDesktop public void run() { @SuppressWarnings("unchecked") - String url = (history instanceof JTextField - ? ((JTextField) history).getText() - : ((JComboBox) history).getSelectedItem() - .toString()); - - if (url.toLowerCase().endsWith(".jar")) - { - if (viewport != null) - { - new FileLoader().LoadFile(viewport, url, DataSourceType.URL, - FileFormat.Jalview); - } - else - { - new FileLoader().LoadFile(url, DataSourceType.URL, - FileFormat.Jalview); + String url = (history instanceof JTextField ? ((JTextField) history).getText() + : ((JComboBox) history).getEditor().getItem().toString().trim()); + + if (url.toLowerCase(Locale.ROOT).endsWith(".jar")) { + if (viewport != null) { + new FileLoader().LoadFile(viewport, url, DataSourceType.URL, FileFormat.Jalview); + } else { + new FileLoader().LoadFile(url, DataSourceType.URL, FileFormat.Jalview); } - } - else - { + } else { FileFormatI format = null; try { @@ -1386,9 +1391,9 @@ public class Desktop extends GDesktop private void storeLastKnownDimensions(String string, Rectangle jc) { - Cache.log.debug("Storing last known dimensions for " + string + ": x:" - + jc.x + " y:" + jc.y + " width:" + jc.width + " height:" - + jc.height); + jalview.bin.Console.debug("Storing last known dimensions for " + string + + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width + + " height:" + jc.height); Cache.setProperty(string + "SCREEN_X", jc.x + ""); Cache.setProperty(string + "SCREEN_Y", jc.y + ""); @@ -1425,39 +1430,28 @@ public class Desktop extends GDesktop public String getAboutMessage() { StringBuilder message = new StringBuilder(1024); - message.append("

Version: ") - .append(Cache.getProperty("VERSION")).append("

") - .append("Built: ") - .append(Cache.getDefault("BUILD_DATE", "unknown")) - .append(" from ").append(Cache.getBuildDetailsForSplash()) - .append(""); + message.append("
").append("

Version: ") + .append(Cache.getProperty("VERSION")).append("

").append("Built: ") + .append(Cache.getDefault("BUILD_DATE", "unknown")).append(" from ") + .append(Cache.getBuildDetailsForSplash()).append(""); String latestVersion = Cache.getDefault("LATEST_VERSION", "Checking"); - if (latestVersion.equals("Checking")) - { + if (latestVersion.equals("Checking")) { // JBP removed this message for 2.11: May be reinstated in future version // message.append("
...Checking latest version...
"); - } - else if (!latestVersion.equals(Cache.getProperty("VERSION"))) - { + } else if (!latestVersion.equals(Cache.getProperty("VERSION"))) { boolean red = false; - if (Cache.getProperty("VERSION").toLowerCase() - .indexOf("automated build") == -1) - { + if (Cache.getProperty("VERSION").toLowerCase(Locale.ROOT).indexOf("automated build") == -1) { red = true; // Displayed when code version and jnlp version do not match and code // version is not a development build message.append("
"); } - message.append("
!! Version ") - .append(Cache.getDefault("LATEST_VERSION", "..Checking..")) - .append(" is available for download from ") - .append(Cache.getDefault("www.jalview.org", - "http://www.jalview.org")) - .append(" !!"); - if (red) - { + message.append("
!! Version ").append(Cache.getDefault("LATEST_VERSION", "..Checking..")) + .append(" is available for download from ") + .append(Cache.getDefault("www.jalview.org", "https://www.jalview.org")).append(" !!"); + if (red) { message.append("
"); } } @@ -1465,6 +1459,8 @@ public class Desktop extends GDesktop message.append(Cache.getDefault("AUTHORFNAMES", DEFAULT_AUTHORS)); message.append(CITATION); + message.append("
"); + return message.toString(); } @@ -1472,15 +1468,11 @@ public class Desktop extends GDesktop * Action on requesting Help documentation */ @Override - public void documentationMenuItem_actionPerformed() - { - try - { - if (Platform.isJS()) - { - BrowserLauncher.openURL("http://www.jalview.org/help.html"); - } - else + public void documentationMenuItem_actionPerformed() { + try { + if (Platform.isJS()) { + BrowserLauncher.openURL("https://www.jalview.org/help.html"); + } else /** * Java only * @@ -1489,8 +1481,7 @@ public class Desktop extends GDesktop { Help.showHelpWindow(); } - } catch (Exception ex) - { + } catch (Exception ex) { System.err.println("Error opening help: " + ex.getMessage()); } } @@ -1551,9 +1542,9 @@ public class Desktop extends GDesktop protected void garbageCollect_actionPerformed(ActionEvent e) { // We simply collect the garbage - Cache.log.debug("Collecting garbage..."); + jalview.bin.Console.debug("Collecting garbage..."); System.gc(); - Cache.log.debug("Finished garbage collection."); + jalview.bin.Console.debug("Finished garbage collection."); } /* @@ -1609,7 +1600,8 @@ public class Desktop extends GDesktop return; } - AlignmentViewport source = null, target = null; + AlignViewportI source = null; + AlignViewportI target = null; if (frames[0] instanceof AlignFrame) { source = ((AlignFrame) frames[0]).getCurrentView(); @@ -1685,9 +1677,8 @@ public class Desktop extends GDesktop * DOCUMENT ME! */ @Override - protected void preferences_actionPerformed(ActionEvent e) - { - new Preferences(); + protected void preferences_actionPerformed(ActionEvent e) { + Preferences.openPreferences(); } /** @@ -1730,8 +1721,7 @@ public class Desktop extends GDesktop } } - if (approveSave || autoSave) - { + if (approveSave || autoSave) { final Desktop me = this; final java.io.File chosenFile = projectFile; new Thread(new Runnable() @@ -1766,7 +1756,7 @@ public class Desktop extends GDesktop + chosenFile.getName(), oom); } catch (Exception ex) { - Cache.log.error("Problems whilst trying to save to " + jalview.bin.Console.error("Problems whilst trying to save to " + chosenFile.getName(), ex); JvOptionPane.showMessageDialog(me, MessageManager.formatMessage( @@ -1838,7 +1828,7 @@ public class Desktop extends GDesktop new OOMWarning("Whilst loading project from " + choice, oom); } catch (Exception ex) { - Cache.log.error( + jalview.bin.Console.error( "Problems whilst loading project from " + choice, ex); JvOptionPane.showMessageDialog(getDesktopPane(), MessageManager.formatMessage( @@ -1850,7 +1840,7 @@ public class Desktop extends GDesktop JvOptionPane.WARNING_MESSAGE); } } - }).start(); + }, "Project Loader").start(); } }); @@ -2152,6 +2142,7 @@ public class Desktop extends GDesktop { source.showFeatureSettingsUI(); } + } public JInternalFrame[] getAllFrames() @@ -2345,6 +2336,9 @@ public class Desktop extends GDesktop 10, getHeight() - fm.getHeight()); } } + + // output debug scale message. Important for jalview.bin.HiDPISettingTest2 + Desktop.debugScaleMessage(Desktop.getDesktopPane().getGraphics()); } } @@ -2440,7 +2434,7 @@ public class Desktop extends GDesktop openGroovyConsole(); } catch (Exception ex) { - Cache.log.error("Groovy Shell Creation failed.", ex); + jalview.bin.Console.error("Groovy Shell Creation failed.", ex); JvOptionPane.showInternalMessageDialog(desktopPane, MessageManager.getString("label.couldnt_create_groovy_shell"), @@ -2499,12 +2493,10 @@ public class Desktop extends GDesktop */ protected void addQuitHandler() { - getRootPane() - .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( - KeyStroke - .getKeyStroke(KeyEvent.VK_Q, - jalview.util.ShortcutKeyMaskExWrapper - .getMenuShortcutKeyMaskEx()), + + getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, + Platform.SHORTCUT_KEY_MASK), "Quit"); getRootPane().getActionMap().put("Quit", new AbstractAction() { @@ -2577,6 +2569,13 @@ public class Desktop extends GDesktop progressBars.put(Long.valueOf(id), addProgressPanel(message)); } } + + @Override + public void removeProgressBar(long id) + { + //TODO + throw new UnsupportedOperationException("not implemented"); + } /* * (non-Javadoc) @@ -2689,17 +2688,29 @@ public class Desktop extends GDesktop this.inBatchMode = inBatchMode; } + /** + * start service discovery and wait till it is done + */ public void startServiceDiscovery() { startServiceDiscovery(false); } + /** + * start service discovery threads - blocking or non-blocking + * + * @param blocking + */ public void startServiceDiscovery(boolean blocking) { - boolean alive = true; - Thread t0 = null, t1 = null, t2 = null; + jalview.bin.Console.debug("Starting service discovery"); + + var tasks = new ArrayList>(); // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release - if (true) + + System.out.println("loading services"); + + /** @j2sIgnore */ { // todo: changesupport handlers need to be transferred if (discoverer == null) @@ -2710,31 +2721,30 @@ public class Desktop extends GDesktop } // JAL-940 - disabled JWS1 service configuration - always start discoverer // until we phase out completely - (t0 = new Thread(discoverer)).start(); + var f = new FutureTask(discoverer, null); + new Thread(f).start(); + tasks.add(f); } if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - t2 = jalview.ws.jws2.Jws2Discoverer.getInstance() - .startDiscoverer(changeSupport); + tasks.add(jalview.ws.jws2.Jws2Discoverer.getInstance().startDiscoverer()); } - Thread t3 = null; + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - // TODO: do rest service discovery + tasks.add(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance().startDiscoverer()); } if (blocking) { - while (alive) - { + for (Future task : tasks) { try { - Thread.sleep(15); + // block until all discovery tasks are done + task.get(); } catch (Exception e) { + e.printStackTrace(); } - alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive()) - || (t3 != null && t3.isAlive()) - || (t0 != null && t0.isAlive()); } } } @@ -2748,8 +2758,10 @@ public class Desktop extends GDesktop { if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector) { - final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance() - .getErrorMessages(); + final WSDiscovererI discoverer = jalview.ws.jws2.Jws2Discoverer + .getInstance(); + final String ermsg = discoverer.getErrorMessages(); + // CONFLICT:ALT:? final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance() if (ermsg != null) { if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true)) @@ -2805,7 +2817,7 @@ public class Desktop extends GDesktop } else { - Cache.log.error( + jalview.bin.Console.error( "Errors reported by JABA discovery service. Check web services preferences.\n" + ermsg); } @@ -2898,15 +2910,8 @@ public class Desktop extends GDesktop { if (url != null) { - if (Cache.log != null) - { - Cache.log.error("Couldn't handle string " + url + " as a URL."); - } - else - { - System.err.println( - "Couldn't handle string " + url + " as a URL."); - } + // TODO does error send to stderr if no log exists ? + jalview.bin.Console.error("Couldn't handle string " + url + " as a URL."); } // ignore any exceptions due to dud links. } @@ -2961,7 +2966,7 @@ public class Desktop extends GDesktop SwingUtilities.invokeAndWait(prompter); } catch (Exception q) { - Cache.log.warn("Unexpected Exception in dialog thread.", q); + jalview.bin.Console.warn("Unexpected Exception in dialog thread.", q); } } }); @@ -3000,7 +3005,7 @@ public class Desktop extends GDesktop public void exportImage(Graphics g) throws Exception { paintAll(g); - Cache.log.info("Successfully written snapshot to file " + jalview.bin.Console.info("Successfully written snapshot to file " + of.getAbsolutePath()); } }; @@ -3215,7 +3220,8 @@ public class Desktop extends GDesktop "application/x-java-url; class=java.net.URL"); } catch (ClassNotFoundException cfe) { - Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe); + jalview.bin.Console.debug("Couldn't instantiate the URL dataflavor.", + cfe); } if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour)) @@ -3230,7 +3236,7 @@ public class Desktop extends GDesktop { protocols.add(DataSourceType.URL); files.add(url.toString()); - Cache.log.debug("Drop handled as URL dataflavor " + jalview.bin.Console.debug("Drop handled as URL dataflavor " + files.get(files.size() - 1)); return; } @@ -3244,13 +3250,13 @@ public class Desktop extends GDesktop } } catch (Throwable ex) { - Cache.log.debug("URL drop handler failed.", ex); + jalview.bin.Console.debug("URL drop handler failed.", ex); } } if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { // Works on Windows and MacOSX - Cache.log.debug("Drop handled as javaFileListFlavor"); + jalview.bin.Console.debug("Drop handled as javaFileListFlavor"); for (File file : (List) t .getTransferData(DataFlavor.javaFileListFlavor)) { @@ -3265,14 +3271,15 @@ public class Desktop extends GDesktop String data = null; if (t.isDataFlavorSupported(uriListFlavor)) { - Cache.log.debug("Drop handled as uriListFlavor"); + jalview.bin.Console.debug("Drop handled as uriListFlavor"); // This is used by Unix drag system data = (String) t.getTransferData(uriListFlavor); } if (data == null) { // fallback to text: workaround - on OSX where there's a JVM bug - Cache.log.debug("standard URIListFlavor failed. Trying text"); + jalview.bin.Console + .debug("standard URIListFlavor failed. Trying text"); // try text fallback DataFlavor textDf = new DataFlavor( "text/plain;class=java.lang.String"); @@ -3281,7 +3288,7 @@ public class Desktop extends GDesktop data = (String) t.getTransferData(textDf); } - Cache.log.debug("Plain text drop content returned " + jalview.bin.Console.debug("Plain text drop content returned " + (data == null ? "Null - failed" : data)); } @@ -3289,7 +3296,7 @@ public class Desktop extends GDesktop { while (protocols.size() < files.size()) { - Cache.log.debug("Adding missing FILE protocol for " + jalview.bin.Console.debug("Adding missing FILE protocol for " + files.get(protocols.size())); protocols.add(DataSourceType.FILE); } @@ -3304,7 +3311,7 @@ public class Desktop extends GDesktop continue; } java.net.URI uri = new java.net.URI(s); - if (uri.getScheme().toLowerCase().startsWith("http")) + if (uri.getScheme().toLowerCase(Locale.ROOT).startsWith("http")) { protocols.add(DataSourceType.URL); files.add(uri.toString()); @@ -3319,7 +3326,7 @@ public class Desktop extends GDesktop } } - if (Cache.log.isDebugEnabled()) + if (jalview.bin.Console.isDebugEnabled()) { if (data == null || !added) { @@ -3327,39 +3334,39 @@ public class Desktop extends GDesktop if (t.getTransferDataFlavors() != null && t.getTransferDataFlavors().length > 0) { - Cache.log.debug( + jalview.bin.Console.debug( "Couldn't resolve drop data. Here are the supported flavors:"); for (DataFlavor fl : t.getTransferDataFlavors()) { - Cache.log.debug( + jalview.bin.Console.debug( "Supported transfer dataflavor: " + fl.toString()); Object df = t.getTransferData(fl); if (df != null) { - Cache.log.debug("Retrieves: " + df); + jalview.bin.Console.debug("Retrieves: " + df); } else { - Cache.log.debug("Retrieved nothing"); + jalview.bin.Console.debug("Retrieved nothing"); } } } else { - Cache.log.debug("Couldn't resolve dataflavor for drop: " - + t.toString()); + jalview.bin.Console.debug("Couldn't resolve dataflavor for drop: " + + t.toString()); } } } } if (Platform.isWindowsAndNotJS()) { - Cache.log.debug("Scanning dropped content for Windows Link Files"); + jalview.bin.Console.debug("Scanning dropped content for Windows Link Files"); // resolve any .lnk files in the file drop for (int f = 0; f < files.size(); f++) { - String source = files.get(f).toString().toLowerCase(); + String source = files.get(f).toString().toLowerCase(Locale.ROOT); if (protocols.get(f).equals(DataSourceType.FILE) && (source.endsWith(".lnk") || source.endsWith(".url") || source.endsWith(".site"))) @@ -3370,16 +3377,16 @@ public class Desktop extends GDesktop File lf = (obj instanceof File ? (File) obj : new File((String) obj)); // process link file to get a URL - Cache.log.debug("Found potential link file: " + lf); + jalview.bin.Console.debug("Found potential link file: " + lf); WindowsShortcut wscfile = new WindowsShortcut(lf); String fullname = wscfile.getRealFilename(); protocols.set(f, FormatAdapter.checkProtocol(fullname)); files.set(f, fullname); - Cache.log.debug("Parsed real filename " + fullname + jalview.bin.Console.debug("Parsed real filename " + fullname + " to extract protocol: " + protocols.get(f)); } catch (Exception ex) { - Cache.log.error( + jalview.bin.Console.error( "Couldn't parse " + files.get(f) + " as a link file.", ex); } @@ -3435,4 +3442,32 @@ public class Desktop extends GDesktop return result; } + 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)); + } + } }