From: Ben Soares Date: Thu, 24 Aug 2023 17:43:19 +0000 (+0100) Subject: Merge branch 'bug/JAL-4214_system_freeze_when_opening_file_using_gui_in_linux' into... X-Git-Tag: Release_2_11_4_0~205 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=1f66bdde8f5379d17fe56001443e0e6fde1150d1;hp=-c;p=jalview.git Merge branch 'bug/JAL-4214_system_freeze_when_opening_file_using_gui_in_linux' into merge/big_merge_of_bens_stuff_before_2_11_3_0 --- 1f66bdde8f5379d17fe56001443e0e6fde1150d1 diff --combined src/jalview/gui/AlignFrame.java index 25376af,9e4b180..d225c2e --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@@ -49,7 -49,6 +49,7 @@@ import java.beans.PropertyChangeEvent import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.URL; import java.util.ArrayList; @@@ -624,12 -623,12 +624,12 @@@ public class AlignFrame extends GAlignF // if (viewport.cursorMode) // { // alignPanel.seqPanel.insertNucAtCursor(false,"A"); - // //System.out.println("A"); + // //jalview.bin.Console.outPrintln("A"); // } // break; /* * case KeyEvent.VK_CLOSE_BRACKET: if (viewport.cursorMode) { - * System.out.println("closing bracket"); } break; + * jalview.bin.Console.outPrintln("closing bracket"); } break; */ case KeyEvent.VK_DELETE: case KeyEvent.VK_BACK_SPACE: @@@ -830,8 -829,7 +830,8 @@@ @Override public void propertyChange(PropertyChangeEvent evt) { - // // System.out.println("Discoverer property change."); + // // jalview.bin.Console.outPrintln("Discoverer property + // change."); // if (evt.getPropertyName().equals("services")) { SwingUtilities.invokeLater(new Runnable() @@@ -840,7 -838,7 +840,7 @@@ @Override public void run() { - System.err.println( + jalview.bin.Console.errPrintln( "Rebuild WS Menu for service change"); BuildWebServiceMenu(); } @@@ -855,7 -853,7 +855,7 @@@ public void internalFrameClosed( javax.swing.event.InternalFrameEvent evt) { - // System.out.println("deregistering discoverer listener"); + // jalview.bin.Console.outPrintln("deregistering discoverer listener"); Desktop.instance.removeJalviewPropertyChangeListener("services", thisListener); closeMenuItem_actionPerformed(true); @@@ -1252,16 -1250,8 +1252,16 @@@ */ public void saveAlignment(String file, FileFormatI format) { + saveAlignment(file, format, false); + } + + public void saveAlignment(String file, FileFormatI format, boolean stdout) + { lastSaveSuccessful = true; - lastFilenameSaved = file; + if (!stdout) + { + lastFilenameSaved = file; + } lastFormatSaved = format; if (FileFormat.Jalview.equals(format)) @@@ -1272,7 -1262,6 +1272,7 @@@ shortName = shortName .substring(shortName.lastIndexOf(File.separatorChar) + 1); } + // TODO deal with stdout=true lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, shortName); @@@ -1308,7 -1297,7 +1308,7 @@@ else { // create backupfiles object and get new temp filename destination - boolean doBackup = BackupFiles.getEnabled(); + boolean doBackup = BackupFiles.getEnabled() && !stdout; BackupFiles backupfiles = null; if (doBackup) { @@@ -1320,9 -1309,7 +1320,9 @@@ String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file; Console.trace("ALIGNFRAME setting PrintWriter"); - PrintWriter out = new PrintWriter(new FileWriter(tempFilePath)); + PrintWriter out = stdout + ? new PrintWriter(new OutputStreamWriter(System.out)) + : new PrintWriter(new FileWriter(tempFilePath)); if (backupfiles != null) { @@@ -1331,28 -1318,13 +1331,28 @@@ } out.print(output); - Console.trace("ALIGNFRAME about to close file"); - out.close(); - Console.trace("ALIGNFRAME closed file"); - AlignFrame.this.setTitle(file); - statusBar.setText(MessageManager.formatMessage( - "label.successfully_saved_to_file_in_format", new Object[] - { fileName, format.getName() })); + out.flush(); + if (!stdout) + { + Console.trace("ALIGNFRAME about to close file"); + out.close(); + Console.trace("ALIGNFRAME closed file"); + } + AlignFrame.this.setTitle(stdout ? "STDOUT" : file); + if (stdout) + { + statusBar.setText(MessageManager.formatMessage( + "label.successfully_printed_to_stdout_in_format", + new Object[] + { format.getName() })); + } + else + { + statusBar.setText(MessageManager.formatMessage( + "label.successfully_saved_to_file_in_format", + new Object[] + { fileName, format.getName() })); + } lastSaveSuccessful = true; } catch (IOException e) { @@@ -1669,6 -1641,8 +1669,8 @@@ closeAllTabs = true; } + Desktop.closeModal(this); + try { if (alignPanels != null) @@@ -1698,6 -1672,7 +1700,7 @@@ featureSettings.close(); featureSettings = null; } + /* * this will raise an INTERNAL_FRAME_CLOSED event and this method will * be called recursively, with the frame now in 'closed' state @@@ -2499,7 -2474,7 +2502,7 @@@ } catch (Exception ex) { ex.printStackTrace(); - System.out.println("Exception whilst pasting: " + ex); + jalview.bin.Console.outPrintln("Exception whilst pasting: " + ex); // could be anything being pasted in here } @@@ -2547,7 -2522,7 +2550,7 @@@ } catch (Exception ex) { ex.printStackTrace(); - System.out.println("Exception whilst pasting: " + ex); + jalview.bin.Console.outPrintln("Exception whilst pasting: " + ex); // could be anything being pasted in here } catch (OutOfMemoryError oom) { @@@ -3183,20 -3158,11 +3186,20 @@@ @Override public void wrapMenuItem_actionPerformed(ActionEvent e) { - scaleAbove.setVisible(wrapMenuItem.isSelected()); - scaleLeft.setVisible(wrapMenuItem.isSelected()); - scaleRight.setVisible(wrapMenuItem.isSelected()); - viewport.setWrapAlignment(wrapMenuItem.isSelected()); + setWrapFormat(wrapMenuItem.isSelected(), false); + } + + public void setWrapFormat(boolean b, boolean setMenuItem) + { + scaleAbove.setVisible(b); + scaleLeft.setVisible(b); + scaleRight.setVisible(b); + viewport.setWrapAlignment(b); alignPanel.updateLayout(); + if (setMenuItem) + { + wrapMenuItem.setSelected(b); + } } @Override @@@ -3534,7 -3500,7 +3537,7 @@@ } JInternalFrame frame = new JInternalFrame(); - + frame.setFrameIcon(null); frame.getContentPane().add(new JScrollPane(pane)); Desktop.addInternalFrame(frame, MessageManager @@@ -3562,12 -3528,12 +3565,12 @@@ return alignPanel.overviewPanel; } JInternalFrame frame = new JInternalFrame(); + frame.setFrameIcon(null); final OverviewPanel overview = new OverviewPanel(alignPanel, frame, showHidden); frame.setContentPane(overview); Desktop.addInternalFrame(frame, "", true, frame.getWidth(), frame.getHeight(), true, true); - frame.setFrameIcon(null); frame.pack(); frame.setLayer(JLayeredPane.PALETTE_LAYER); final AlignmentPanel thePanel = this.alignPanel; @@@ -3841,7 -3807,6 +3844,7 @@@ else { JInternalFrame frame = new JInternalFrame(); + frame.setFrameIcon(null); frame.setContentPane(new PairwiseAlignPanel(viewport)); Desktop.addInternalFrame(frame, MessageManager.getString("action.pairwise_alignment"), 600, @@@ -4303,10 -4268,10 +4306,10 @@@ { NewickFile fin = new NewickFile( new FileParse(cm.getNewick(), DataSourceType.PASTE)); - String title = cm.getAnnotLabel() + " " + cm.getTreeMethod() + " tree" - + aa.sequenceRef != null + String title = aa.label + " " + cm.getTreeMethod() + " tree" + + (aa.sequenceRef != null ? (" for " + aa.sequenceRef.getDisplayId(false)) - : ""; + : ""); showColumnWiseTree(fin, aa, title, w, h, x, y); } catch (Throwable xx) @@@ -4326,7 -4291,7 +4329,7 @@@ { return null; } - TreePanel tp = new TreePanel(alignPanel, nf, aa, title); + TreePanel tp = new TreePanel(alignPanel, nf, aa, treeTitle); tp.setSize(w, h); @@@ -4335,7 -4300,7 +4338,7 @@@ tp.setLocation(x, y); } - Desktop.addInternalFrame(tp, title, w, h); + Desktop.addInternalFrame(tp, treeTitle, w, h); return tp; } catch (Throwable xx) { @@@ -4357,8 -4322,7 +4360,8 @@@ { try { - System.err.println("Waiting for building menu to finish."); + jalview.bin.Console + .errPrintln("Waiting for building menu to finish."); Thread.sleep(10); } catch (Exception e) { @@@ -4374,7 -4338,7 +4377,7 @@@ final List legacyItems = new ArrayList<>(); try { - // System.err.println("Building ws menu again " + // jalview.bin.Console.errPrintln("Building ws menu again " // + Thread.currentThread()); // TODO: add support for context dependent disabling of services based // on @@@ -4912,7 -4876,7 +4915,7 @@@ Desktop.instance); if (pe != null) { - System.err.println("Associated file : " + jalview.bin.Console.errPrintln("Associated file : " + (fm[0].toString()) + " with " + toassoc.getDisplayId(true)); assocfiles++; @@@ -5945,7 -5909,7 +5948,7 @@@ viewport.getAlignment())); } catch (Exception ex) { - System.err.println(ex.getMessage()); + jalview.bin.Console.errPrintln(ex.getMessage()); return; } } @@@ -5967,7 -5931,7 +5970,7 @@@ console.runScript(); } catch (Exception ex) { - System.err.println((ex.toString())); + jalview.bin.Console.errPrintln((ex.toString())); JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager.getString("label.couldnt_run_groovy_script"), MessageManager.getString("label.groovy_support_failed"), @@@ -5976,8 -5940,7 +5979,8 @@@ } else { - System.err.println("Can't run Groovy script as console not found"); + jalview.bin.Console + .errPrintln("Can't run Groovy script as console not found"); } } diff --combined src/jalview/gui/Desktop.java index 66055a4,5e6f40e..035da25 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@@ -51,6 -51,7 +51,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,6 -64,7 +64,7 @@@ 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.ExecutorService; import java.util.concurrent.Executors; @@@ -439,7 -441,7 +441,7 @@@ public class Desktop extends jalview.jb * 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"; @@@ -572,16 -574,15 +574,16 @@@ } // 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."); @@@ -874,7 -875,7 +876,7 @@@ } } catch (Exception ex) { - System.out.println( + jalview.bin.Console.outPrintln( "Unable to paste alignment from system clipboard:\n" + ex); } } @@@ -1079,36 -1080,7 +1081,36 @@@ 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); @@@ -1268,9 -1240,7 +1270,9 @@@ @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()); @@@ -1633,7 -1603,7 +1635,7 @@@ } } catch (Exception ex) { - System.err.println("Error opening help: " + ex.getMessage()); + jalview.bin.Console.errPrintln("Error opening help: " + ex.getMessage()); } } @@@ -1864,7 -1834,7 +1866,7 @@@ 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")); @@@ -3413,7 -3383,7 +3415,7 @@@ { if (Platform.isAMacAndNotJS()) { - System.err.println( + jalview.bin.Console.errPrintln( "Please ignore plist error - occurs due to problem with java 8 on OSX"); } } @@@ -3655,37 -3625,25 +3657,39 @@@ { Desktop.instance.closeAll_actionPerformed(null); Desktop.instance.setVisible(false); - Desktop.instance.dispose(); + 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 + * 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) + for (JInternalFrame frame : frames) { if (frame instanceof IProgressIndicator) { - if (((IProgressIndicator)frame).operationInProgress()) + if (((IProgressIndicator) frame).operationInProgress()) { return true; } @@@ -3693,4 -3651,37 +3697,37 @@@ } 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); + } + } diff --combined src/jalview/gui/JvOptionPane.java index eaaa2a1,90d812c..5b926c3 --- a/src/jalview/gui/JvOptionPane.java +++ b/src/jalview/gui/JvOptionPane.java @@@ -32,6 -32,7 +32,7 @@@ import java.awt.Toolkit import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; + import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseMotionAdapter; import java.beans.PropertyChangeEvent; @@@ -51,8 -52,11 +52,11 @@@ import javax.swing.JDialog import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLayeredPane; + import javax.swing.JMenu; + import javax.swing.JMenuBar; import javax.swing.JOptionPane; import javax.swing.JPanel; + import javax.swing.JRootPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.InternalFrameEvent; @@@ -718,7 -722,7 +722,7 @@@ public class JvOptionPane extends JOpti private static void outputMessage(Object message) { - System.out.println(">>> JOption Message : " + message.toString()); + jalview.bin.Console.outPrintln(">>> JOption Message : " + message.toString()); } public static Object getMockResponse() @@@ -1072,53 -1076,53 +1076,53 @@@ if (parentComponent != this && !(parentComponent == null && Desktop.instance == null)) { + // note the parent goes back to a JRootPane so is probably + // Desktop.getDesktop() JInternalFrame jif = this.createInternalFrame( parentComponent != null ? parentComponent : Desktop.instance, title); + // connect to the alignFrame using a map in Desktop + if (parentComponent instanceof AlignFrame) + { + Desktop.addModal((AlignFrame) parentComponent, jif); + } jif.setFrameIcon(null); jif.addInternalFrameListener(new InternalFrameListener() { @Override public void internalFrameActivated(InternalFrameEvent arg0) { - System.err.println("##### internalFrameActivated"); } @Override public void internalFrameClosed(InternalFrameEvent arg0) { - System.err.println("##### internalFrameClosed"); JvOptionPane.this.internalDialogHandleResponse(); } @Override public void internalFrameClosing(InternalFrameEvent arg0) { - System.err.println("##### internalFrameClosing"); } @Override public void internalFrameDeactivated(InternalFrameEvent arg0) { - System.err.println("##### internalFrameDeactivated"); } @Override public void internalFrameDeiconified(InternalFrameEvent arg0) { - System.err.println("##### internalFrameDeiconified"); } @Override public void internalFrameIconified(InternalFrameEvent arg0) { - System.err.println("##### internalFrameIconified"); } @Override public void internalFrameOpened(InternalFrameEvent arg0) { - System.err.println("##### internalFrameOpened"); } }); jif.setVisible(true); @@@ -1137,13 -1141,7 +1141,13 @@@ private void internalDialogHandleResponse() { - String responseString = (String) this.getValue(); + Object value = this.getValue(); + if (value == null + || (value instanceof Integer && (Integer) value == -1)) + { + return; + } + String responseString = value.toString(); int response = ourOptions.indexOf(responseString); if (!Platform.isJS()) @@@ -1513,13 -1511,27 +1517,27 @@@ lp.add(modalInterceptor); f.toFront(); + // disable the main menu bar if in Linux + JMenuBar menubar = null; + if (Platform.isLinux()) + { + JRootPane rootpane = Desktop.getDesktop().getRootPane(); + menubar = rootpane.getJMenuBar(); + } + // We need to explicitly dispatch events when we are blocking the event // dispatch thread. EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); try { - boolean stillModal = true; - while (!f.isClosed() && stillModal) + if (menubar != null) + { + // don't allow clicks on main menu on linux due to a hanging bug. + // see JAL-4214. + setMenusEnabled(menubar, false); + } + + while (!f.isClosed()) { if (EventQueue.isDispatchThread()) { @@@ -1529,53 -1541,53 +1547,53 @@@ // This mimics EventQueue.dispatchEvent(). We can't use // EventQueue.dispatchEvent() directly, because it is // protected, unfortunately. - System.out.println( - "##### ev source=" + ev.getSource().getClass() + ""); if (ev instanceof ActiveEvent) { - System.err.println("##### 1"); ((ActiveEvent) ev).dispatch(); } + else if (ev instanceof KeyEvent && ((KeyEvent) ev).isControlDown() + && menubar != null) + { + // temporarily enable menus to send Ctrl+? KeyEvents + setMenusEnabled(menubar, true); + ((Component) ev.getSource()).dispatchEvent(ev); + setMenusEnabled(menubar, false); + } else if (ev.getSource() instanceof MenuComponent) { - System.err.println("##### 2"); ((MenuComponent) ev.getSource()).dispatchEvent(ev); } else if (ev.getSource() instanceof Component) { - System.err.println("##### 3"); - if (ev.getSource().equals(Desktop.getDesktop().getRootPane())) - { - stillModal = false; - } - else - { - ((Component) ev.getSource()).dispatchEvent(ev); - } + ((Component) ev.getSource()).dispatchEvent(ev); } // Other events are ignored as per spec in // EventQueue.dispatchEvent - System.err.println("##### 4"); } else { // Give other threads a chance to become active. - System.err.println("##### 5"); Thread.yield(); } } } catch (InterruptedException ex) { // If we get interrupted, then leave the modal state. - System.err.println("##### 6"); } finally { - System.err.println("##### 7"); + // re-enable the main menu bar + if (menubar != null) + { + setMenusEnabled(menubar, true); + } + // Clean up the modal interceptor. lp.remove(modalInterceptor); + // unpaint the frame f.setVisible(false); + // close the frame try { f.setClosed(true); @@@ -1661,4 -1673,14 +1679,14 @@@ return jvop; } + + private static void setMenusEnabled(JMenuBar menubar, boolean b) + { + for (int i = 0; i < menubar.getMenuCount(); i++) + { + JMenu menu = menubar.getMenu(i); + menu.setEnabled(b); + } + } + }