X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAlignFrame.java;h=cc81eef681a89e8823a45e44bd6ce4b530adbd0a;hb=c2b931a5a0ea81bdc93db1f0cf632b07717c5066;hp=f3a8ab579371e4d978c939dfd7f2cb41a06b35c0;hpb=19b16858301d7f1ad2788e7f8b0b9321ba6a6cc1;p=jalview.git diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index f3a8ab5..cc81eef 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -20,6 +20,58 @@ */ package jalview.gui; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.List; +import java.util.Vector; + +import javax.swing.ButtonGroup; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComponent; +import javax.swing.JEditorPane; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.event.InternalFrameAdapter; +import javax.swing.event.InternalFrameEvent; + import jalview.analysis.AlignmentSorter; import jalview.analysis.AlignmentUtils; import jalview.analysis.CrossRef; @@ -27,12 +79,13 @@ import jalview.analysis.Dna; import jalview.analysis.GeneticCodeI; import jalview.analysis.ParseProperties; import jalview.analysis.SequenceIdMatcher; -import jalview.api.AlignExportSettingI; +import jalview.api.AlignExportSettingsI; import jalview.api.AlignViewControllerGuiI; import jalview.api.AlignViewControllerI; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureSettingsControllerI; +import jalview.api.FeatureSettingsModelI; import jalview.api.SplitContainerI; import jalview.api.ViewStyleI; import jalview.api.analysis.SimilarityParamsI; @@ -46,6 +99,7 @@ import jalview.commands.RemoveGapColCommand; import jalview.commands.RemoveGapsCommand; import jalview.commands.SlideSequencesCommand; import jalview.commands.TrimRegionCommand; +import jalview.datamodel.AlignExportSettingsAdapter; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; @@ -55,7 +109,6 @@ import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; -import jalview.datamodel.HiddenSequences; import jalview.datamodel.PDBEntry; import jalview.datamodel.SeqCigar; import jalview.datamodel.Sequence; @@ -63,6 +116,13 @@ import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.gui.ColourMenuHelper.ColourChangeListener; import jalview.gui.ViewSelectionMenu.ViewSetProvider; +import jalview.hmmer.HMMAlign; +import jalview.hmmer.HMMBuild; +import jalview.hmmer.HMMERParamStore; +import jalview.hmmer.HMMERPreset; +import jalview.hmmer.HMMSearch; +import jalview.hmmer.HmmerCommand; +import jalview.hmmer.JackHMMER; import jalview.io.AlignmentProperties; import jalview.io.AnnotationFile; import jalview.io.BackupFiles; @@ -85,66 +145,35 @@ import jalview.io.ScoreMatrixFile; import jalview.io.TCoffeeScoreFile; import jalview.io.vcf.VCFLoader; import jalview.jbgui.GAlignFrame; +import jalview.project.Jalview2XML; import jalview.schemes.ColourSchemeI; import jalview.schemes.ColourSchemes; import jalview.schemes.ResidueColourScheme; import jalview.schemes.TCoffeeColourScheme; +import jalview.util.ImageMaker.TYPE; import jalview.util.MessageManager; +import jalview.util.Platform; import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.ViewportRanges; import jalview.ws.DBRefFetcher; import jalview.ws.DBRefFetcher.FetchFinishedListenerI; +import jalview.ws.ServiceChangeListener; +import jalview.ws.WSDiscovererI; +import jalview.ws.api.ServiceWithParameters; import jalview.ws.jws1.Discoverer; import jalview.ws.jws2.Jws2Discoverer; -import jalview.ws.jws2.jabaws2.Jws2Instance; +import jalview.ws.jws2.PreferredServiceRegistry; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.ParamDatastoreI; +import jalview.ws.params.WsParamSetI; import jalview.ws.seqfetcher.DbSourceProxy; +import jalview.ws.slivkaws.SlivkaWSDiscoverer; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Rectangle; -import java.awt.Toolkit; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.StringSelection; -import java.awt.datatransfer.Transferable; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DropTargetDragEvent; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.dnd.DropTargetEvent; -import java.awt.dnd.DropTargetListener; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.FocusAdapter; -import java.awt.event.FocusEvent; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import java.awt.print.PageFormat; -import java.awt.print.PrinterJob; -import java.beans.PropertyChangeEvent; -import java.io.File; -import java.io.FileWriter; -import java.io.PrintWriter; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Deque; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.List; -import java.util.Vector; - -import javax.swing.ButtonGroup; -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JEditorPane; -import javax.swing.JInternalFrame; -import javax.swing.JLayeredPane; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; /** * DOCUMENT ME! @@ -152,10 +181,11 @@ import javax.swing.SwingUtilities; * @author $author$ * @version $Revision$ */ -public class AlignFrame extends GAlignFrame implements DropTargetListener, - IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener +@SuppressWarnings("serial") +public class AlignFrame extends GAlignFrame + implements DropTargetListener, IProgressIndicator, + AlignViewControllerGuiI, ColourChangeListener, ServiceChangeListener { - public static final int DEFAULT_WIDTH = 700; public static final int DEFAULT_HEIGHT = 500; @@ -182,6 +212,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, String fileName = null; /** + * TODO: remove reference to 'FileObject' in AlignFrame - not correct mapping + */ + File fileObject; + + /** * Creates a new AlignFrame object with specific width and height. * * @param al @@ -333,6 +368,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ void init() { + // setBackground(Color.white); // BH 2019 + if (!Jalview.isHeadlessMode()) { progressBar = new ProgressBar(this.statusPanel, this.statusBar); @@ -381,7 +418,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (Desktop.desktop != null) { this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); - addServiceListeners(); + if (!Platform.isJS()) + { + addServiceListeners(); + } setGUINucleotide(); } @@ -500,6 +540,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } /** + * JavaScript will have this, maybe others. More dependable than a file name + * and maintains a reference to the actual bytes loaded. + * + * @param file + */ + public void setFileObject(File file) + { + this.fileObject = file; + } + + /** * Add a KeyListener with handlers for various KeyPressed and KeyReleased * events */ @@ -598,7 +649,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, case KeyEvent.VK_BACK_SPACE: if (!viewport.cursorMode) { - cut_actionPerformed(null); + cut_actionPerformed(); } else { @@ -650,7 +701,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, case KeyEvent.VK_F2: viewport.cursorMode = !viewport.cursorMode; - statusBar.setText(MessageManager + setStatus(MessageManager .formatMessage("label.keyboard_editing_mode", new String[] { (viewport.cursorMode ? "on" : "off") })); if (viewport.cursorMode) @@ -765,6 +816,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, ap.av.updateConservation(ap); ap.av.updateConsensus(ap); ap.av.updateStrucConsensus(ap); + ap.av.initInformationWorker(ap); } } @@ -783,55 +835,43 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return viewport; } + @Override + public void servicesChanged(WSDiscovererI discoverer, + Collection services) + { + buildWebServicesMenu(); + } + /* Set up intrinsic listeners for dynamically generated GUI bits. */ private void addServiceListeners() { - final java.beans.PropertyChangeListener thisListener; - Desktop.instance.addJalviewPropertyChangeListener("services", - thisListener = new java.beans.PropertyChangeListener() - { - @Override - public void propertyChange(PropertyChangeEvent evt) - { - // // System.out.println("Discoverer property change."); - // if (evt.getPropertyName().equals("services")) - { - SwingUtilities.invokeLater(new Runnable() - { - - @Override - public void run() - { - System.err.println( - "Rebuild WS Menu for service change"); - BuildWebServiceMenu(); - } - - }); - } - } - }); - addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - @Override - public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) - { - // System.out.println("deregistering discoverer listener"); - Desktop.instance.removeJalviewPropertyChangeListener("services", - thisListener); - closeMenuItem_actionPerformed(true); - }; - }); - // Finally, build the menu once to get current service state - new Thread(new Runnable() + WSDiscovererI discoverer = SlivkaWSDiscoverer.getInstance(); + discoverer.addServiceChangeListener(this); + } + if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { + WSDiscovererI discoverer = Jws2Discoverer.getDiscoverer(); + discoverer.addServiceChangeListener(this); + } + // legacy event listener for compatibility with jws1 + PropertyChangeListener legacyListener = (changeEvent) -> { + buildWebServicesMenu(); + }; + Desktop.instance.addJalviewPropertyChangeListener("services",legacyListener); + + addInternalFrameListener(new InternalFrameAdapter() { @Override - public void run() - { - BuildWebServiceMenu(); + public void internalFrameClosed(InternalFrameEvent e) { + System.out.println("deregistering discoverer listener"); + SlivkaWSDiscoverer.getInstance().removeServiceChangeListener(AlignFrame.this); + Jws2Discoverer.getDiscoverer().removeServiceChangeListener(AlignFrame.this); + Desktop.instance.removeJalviewPropertyChangeListener("services", legacyListener); + closeMenuItem_actionPerformed(true); } - }).start(); + }); + buildWebServicesMenu(); } /** @@ -907,6 +947,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, showConsensusHistogram.setSelected(av.isShowConsensusHistogram()); showSequenceLogo.setSelected(av.isShowSequenceLogo()); normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo()); + showInformationHistogram.setSelected(av.isShowInformationHistogram()); + showHMMSequenceLogo.setSelected(av.isShowHMMSequenceLogo()); + normaliseHMMSequenceLogo.setSelected(av.isNormaliseHMMSequenceLogo()); ColourMenuHelper.setColourSelected(colourMenu, av.getGlobalColourScheme()); @@ -948,6 +991,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { progressBar.setProgressBar(message, id); } + + @Override + public void removeProgressBar(long id) + { + progressBar.removeProgressBar(id); + } @Override public void registerHandler(final long id, @@ -991,9 +1040,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } @Override - public void fetchSequence_actionPerformed(ActionEvent e) + public void fetchSequence_actionPerformed() { - new jalview.gui.SequenceFetcher(this); + new SequenceFetcher(this); } @Override @@ -1003,6 +1052,257 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } @Override + public void hmmBuild_actionPerformed(boolean withDefaults) + { + if (!alignmentIsSufficient(1)) + { + return; + } + + /* + * get default parameters, and optionally show a dialog + * to allow them to be modified + */ + ParamDatastoreI store = HMMERParamStore.forBuild(viewport); + List args = store.getServiceParameters(); + + if (!withDefaults) + { + WsParamSetI set = new HMMERPreset(); + WsJobParameters params = new WsJobParameters(store, set, args); + if (params.showRunDialog()) + { + args = params.getJobParams(); + } + else + { + return; // user cancelled + } + } + new Thread(new HMMBuild(this, args)).start(); + } + + @Override + public void hmmAlign_actionPerformed(boolean withDefaults) + { + if (!(checkForHMM() && alignmentIsSufficient(2))) + { + return; + } + + /* + * get default parameters, and optionally show a dialog + * to allow them to be modified + */ + ParamDatastoreI store = HMMERParamStore.forAlign(viewport); + List args = store.getServiceParameters(); + + if (!withDefaults) + { + WsParamSetI set = new HMMERPreset(); + WsJobParameters params = new WsJobParameters(store, set, args); + if (params.showRunDialog()) + { + args = params.getJobParams(); + } + else + { + return; // user cancelled + } + } + new Thread(new HMMAlign(this, args)).start(); + } + + @Override + public void hmmSearch_actionPerformed(boolean withDefaults) + { + if (!checkForHMM()) + { + return; + } + + /* + * get default parameters, and (if requested) show + * dialog to allow modification + */ + ParamDatastoreI store = HMMERParamStore.forSearch(viewport); + List args = store.getServiceParameters(); + + if (!withDefaults) + { + WsParamSetI set = new HMMERPreset(); + WsJobParameters params = new WsJobParameters(store, set, args); + if (params.showRunDialog()) + { + args = params.getJobParams(); + } + else + { + return; // user cancelled + } + } + new Thread(new HMMSearch(this, args)).start(); + alignPanel.repaint(); + } + + @Override + public void jackhmmer_actionPerformed(boolean withDefaults) + { + + /* + * get default parameters, and (if requested) show + * dialog to allow modification + */ + + ParamDatastoreI store = HMMERParamStore.forJackhmmer(viewport); + List args = store.getServiceParameters(); + + if (!withDefaults) + { + WsParamSetI set = new HMMERPreset(); + WsJobParameters params = new WsJobParameters(store, set, args); + if (params.showRunDialog()) + { + args = params.getJobParams(); + } + else + { + return; // user cancelled + } + } + new Thread(new JackHMMER(this, args)).start(); + alignPanel.repaint(); + + } + + /** + * Checks if the alignment has at least one hidden Markov model, if not shows + * a dialog advising to run hmmbuild or load an HMM profile + * + * @return + */ + private boolean checkForHMM() + { + if (viewport.getAlignment().getHmmSequences().isEmpty()) + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("warn.no_hmm")); + return false; + } + return true; + } + + @Override + protected void filterByEValue_actionPerformed() + { + viewport.filterByEvalue(inputDouble("Enter E-Value Cutoff")); + } + + @Override + protected void filterByScore_actionPerformed() + { + viewport.filterByScore(inputDouble("Enter Bit Score Threshold")); + } + + private double inputDouble(String message) + { + String str = null; + Double d = null; + while (d == null || d <= 0) + { + str = JOptionPane.showInputDialog(this.alignPanel, message); + try + { + d = Double.valueOf(str); + } catch (NumberFormatException e) + { + } + } + return d; + } + + /** + * Checks if the alignment contains the required number of sequences. + * + * @param required + * @return + */ + public boolean alignmentIsSufficient(int required) + { + if (getViewport().getSequenceSelection().length < required) + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("label.not_enough_sequences")); + return false; + } + return true; + } + + /** + * Opens a file browser and adds the selected file, if in Fasta, Stockholm or + * Pfam format, to the list held under preference key "HMMSEARCH_DBS" (as a + * comma-separated list) + */ + @Override + public void addDatabase_actionPerformed() throws IOException + { + if (Cache.getProperty(Preferences.HMMSEARCH_DBS) == null) + { + Cache.setProperty(Preferences.HMMSEARCH_DBS, ""); + } + + String path = openFileChooser(false); + if (path != null && new File(path).exists()) + { + IdentifyFile identifier = new IdentifyFile(); + FileFormatI format = identifier.identify(path, DataSourceType.FILE); + if (format == FileFormat.Fasta || format == FileFormat.Stockholm + || format == FileFormat.Pfam) + { + String currentDbPaths = Cache + .getProperty(Preferences.HMMSEARCH_DBS); + currentDbPaths += Preferences.COMMA + path; + Cache.setProperty(Preferences.HMMSEARCH_DBS, currentDbPaths); + } + else + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("warn.invalid_format")); + } + } + } + + /** + * Opens a file chooser, optionally restricted to selecting folders + * (directories) only. Answers the path to the selected file or folder, or + * null if none is chosen. + * + * @param + * @return + */ + protected String openFileChooser(boolean forFolder) + { + // TODO duplicates GPreferences method - relocate to JalviewFileChooser? + String choice = null; + JFileChooser chooser = new JFileChooser(); + if (forFolder) + { + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + } + chooser.setDialogTitle( + MessageManager.getString("label.open_local_file")); + chooser.setToolTipText(MessageManager.getString("action.open")); + + int value = chooser.showOpenDialog(this); + + if (value == JFileChooser.APPROVE_OPTION) + { + choice = chooser.getSelectedFile().getPath(); + } + return choice; + } + + @Override public void reload_actionPerformed(ActionEvent e) { if (fileName != null) @@ -1043,11 +1343,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, Rectangle bounds = this.getBounds(); FileLoader loader = new FileLoader(); - DataSourceType protocol = fileName.startsWith("http:") - ? DataSourceType.URL - : DataSourceType.FILE; - AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName, - protocol, currentFileFormat); + + AlignFrame newframe = null; + + if (fileObject == null) + { + + DataSourceType protocol = (fileName.startsWith("http:") + ? DataSourceType.URL + : DataSourceType.FILE); + newframe = loader.LoadFileWaitTillLoaded(fileName, protocol, + currentFileFormat); + } + else + { + newframe = loader.LoadFileWaitTillLoaded(fileObject, + DataSourceType.FILE, currentFileFormat); + } newframe.setBounds(bounds); if (featureSettings != null && featureSettings.isShowing()) @@ -1092,7 +1404,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (fileName == null || (currentFileFormat == null) || fileName.startsWith("http")) { - saveAs_actionPerformed(null); + saveAs_actionPerformed(); } else { @@ -1101,13 +1413,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! + * Saves the alignment to a file with a name chosen by the user, if necessary + * warning if a file would be overwritten */ @Override - public void saveAs_actionPerformed(ActionEvent e) + public void saveAs_actionPerformed() { String format = currentFileFormat == null ? null : currentFileFormat.getName(); @@ -1121,214 +1431,236 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, int value = chooser.showSaveDialog(this); - if (value == JalviewFileChooser.APPROVE_OPTION) + if (value != JalviewFileChooser.APPROVE_OPTION) + { + return; + } + currentFileFormat = chooser.getSelectedFormat(); + // todo is this (2005) test now obsolete - value is never null? + while (currentFileFormat == null) { + JvOptionPane.showInternalMessageDialog(Desktop.desktop, + MessageManager + .getString("label.select_file_format_before_saving"), + MessageManager.getString("label.file_format_not_specified"), + JvOptionPane.WARNING_MESSAGE); currentFileFormat = chooser.getSelectedFormat(); - while (currentFileFormat == null) + value = chooser.showSaveDialog(this); + if (value != JalviewFileChooser.APPROVE_OPTION) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, - MessageManager.getString( - "label.select_file_format_before_saving"), - MessageManager.getString("label.file_format_not_specified"), - JvOptionPane.WARNING_MESSAGE); - currentFileFormat = chooser.getSelectedFormat(); - value = chooser.showSaveDialog(this); - if (value != JalviewFileChooser.APPROVE_OPTION) - { - return; - } + return; } + } - fileName = chooser.getSelectedFile().getPath(); + fileName = chooser.getSelectedFile().getPath(); - Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName()); + Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName()); + Cache.setProperty("LAST_DIRECTORY", fileName); + saveAlignment(fileName, currentFileFormat); + } + + boolean lastSaveSuccessful = false; + + FileFormatI lastFormatSaved; + + String lastFilenameSaved; + + /** + * Raise a dialog or status message for the last call to saveAlignment. + * + * @return true if last call to saveAlignment(file, format) was successful. + */ + public boolean isSaveAlignmentSuccessful() + { + + if (!lastSaveSuccessful) + { + JvOptionPane.showInternalMessageDialog(this, MessageManager + .formatMessage("label.couldnt_save_file", new Object[] + { lastFilenameSaved }), + MessageManager.getString("label.error_saving_file"), + JvOptionPane.WARNING_MESSAGE); + } + else + { + + setStatus(MessageManager.formatMessage( + "label.successfully_saved_to_file_in_format", new Object[] + { lastFilenameSaved, lastFormatSaved })); - Cache.setProperty("LAST_DIRECTORY", fileName); - saveAlignment(fileName, currentFileFormat); } + return lastSaveSuccessful; } - public boolean saveAlignment(String file, FileFormatI format) + /** + * Saves the alignment to the specified file path, in the specified format, + * which may be an alignment format, or Jalview project format. If the + * alignment has hidden regions, or the format is one capable of including + * non-sequence data (features, annotations, groups), then the user may be + * prompted to specify what to include in the output. + * + * @param file + * @param format + */ + public void saveAlignment(String file, FileFormatI format) { - boolean success = true; + lastSaveSuccessful = true; + lastFilenameSaved = file; + lastFormatSaved = format; if (FileFormat.Jalview.equals(format)) { String shortName = title; - - if (shortName.indexOf(java.io.File.separatorChar) > -1) + if (shortName.indexOf(File.separatorChar) > -1) { - shortName = shortName.substring( - shortName.lastIndexOf(java.io.File.separatorChar) + 1); + shortName = shortName + .substring(shortName.lastIndexOf(File.separatorChar) + 1); } - - success = new jalview.project.Jalview2XML().saveAlignment(this, file, + lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, shortName); statusBar.setText(MessageManager.formatMessage( "label.successfully_saved_to_file_in_format", new Object[] { fileName, format })); + return; } - else + + AlignExportSettingsI options = new AlignExportSettingsAdapter(false); + Runnable cancelAction = new Runnable() { - AlignmentExportData exportData = getAlignmentForExport(format, - viewport, null); - if (exportData.getSettings().isCancelled()) - { - return false; - } - FormatAdapter f = new FormatAdapter(alignPanel, - exportData.getSettings()); - String output = f.formatSequences(format, exportData.getAlignment(), // class - // cast - // exceptions - // will - // occur in the distant future - exportData.getOmitHidden(), exportData.getStartEndPostions(), - f.getCacheSuffixDefault(format), - viewport.getAlignment().getHiddenColumns()); - - if (output == null) + @Override + public void run() { - success = false; + lastSaveSuccessful = false; } - else + }; + Runnable outputAction = new Runnable() + { + @Override + public void run() { - // create backupfiles object and get new temp filename destination - BackupFiles backupfiles = new BackupFiles(file); - - try - { - PrintWriter out = new PrintWriter( - new FileWriter(backupfiles.getTempFilePath())); - - out.print(output); - out.close(); - this.setTitle(file); - statusBar.setText(MessageManager.formatMessage( - "label.successfully_saved_to_file_in_format", new Object[] - { fileName, format.getName() })); - } catch (Exception ex) + // todo defer this to inside formatSequences (or later) + AlignmentExportData exportData = viewport + .getAlignExportData(options); + String output = new FormatAdapter(alignPanel, options) + .formatSequences(format, exportData.getAlignment(), + exportData.getOmitHidden(), + exportData.getStartEndPostions(), + viewport.getAlignment().getHiddenColumns()); + if (output == null) { - success = false; - ex.printStackTrace(); + lastSaveSuccessful = false; } + else + { + // create backupfiles object and get new temp filename destination + boolean doBackup = BackupFiles.getEnabled(); + BackupFiles backupfiles = doBackup ? new BackupFiles(file) : null; + try + { + String tempFilePath = doBackup ? backupfiles.getTempFilePath() + : file; + PrintWriter out = new PrintWriter(new FileWriter(tempFilePath)); - backupfiles.setWriteSuccess(success); - // do the backup file roll and rename the temp file to actual file - success = backupfiles.rollBackupsAndRenameTempFile(); + out.print(output); + out.close(); + AlignFrame.this.setTitle(file); + statusBar.setText(MessageManager.formatMessage( + "label.successfully_saved_to_file_in_format", + new Object[] + { fileName, format.getName() })); + lastSaveSuccessful = true; + } catch (Exception ex) + { + lastSaveSuccessful = false; + ex.printStackTrace(); + } + if (doBackup) + { + backupfiles.setWriteSuccess(lastSaveSuccessful); + // do the backup file roll and rename the temp file to actual file + lastSaveSuccessful = backupfiles.rollBackupsAndRenameTempFile(); + } + } } - } + }; - if (!success) - { - JvOptionPane.showInternalMessageDialog(this, MessageManager - .formatMessage("label.couldnt_save_file", new Object[] - { fileName }), - MessageManager.getString("label.error_saving_file"), - JvOptionPane.WARNING_MESSAGE); - } - - return success; - } - - private void warningMessage(String warning, String title) - { - if (new jalview.util.Platform().isHeadless()) + /* + * show dialog with export options if applicable; else just do it + */ + if (AlignExportOptions.isNeeded(viewport, format)) { - System.err.println("Warning: " + title + "\nWarning: " + warning); - + AlignExportOptions choices = new AlignExportOptions( + alignPanel.getAlignViewport(), format, options); + choices.setResponseAction(0, outputAction); + choices.setResponseAction(1, cancelAction); + choices.showDialog(); } else { - JvOptionPane.showInternalMessageDialog(this, warning, title, - JvOptionPane.WARNING_MESSAGE); + outputAction.run(); } - return; } /** - * DOCUMENT ME! + * Outputs the alignment to textbox in the requested format, if necessary + * first prompting the user for whether to include hidden regions or + * non-sequence data * - * @param e - * DOCUMENT ME! + * @param fileFormatName */ @Override - protected void outputText_actionPerformed(ActionEvent e) + protected void outputText_actionPerformed(String fileFormatName) { FileFormatI fileFormat = FileFormats.getInstance() - .forName(e.getActionCommand()); - AlignmentExportData exportData = getAlignmentForExport(fileFormat, - viewport, null); - if (exportData.getSettings().isCancelled()) - { - return; - } - CutAndPasteTransfer cap = new CutAndPasteTransfer(); - cap.setForInput(null); - try - { - FileFormatI format = fileFormat; - cap.setText(new FormatAdapter(alignPanel, exportData.getSettings()) - .formatSequences(format, exportData.getAlignment(), - exportData.getOmitHidden(), - exportData.getStartEndPostions(), - viewport.getAlignment().getHiddenColumns())); - Desktop.addInternalFrame(cap, MessageManager - .formatMessage("label.alignment_output_command", new Object[] - { e.getActionCommand() }), 600, 500); - } catch (OutOfMemoryError oom) - { - new OOMWarning("Outputting alignment as " + e.getActionCommand(), - oom); - cap.dispose(); - } - - } - - public static AlignmentExportData getAlignmentForExport( - FileFormatI format, AlignViewportI viewport, - AlignExportSettingI exportSettings) - { - AlignmentI alignmentToExport = null; - AlignExportSettingI settings = exportSettings; - String[] omitHidden = null; - - HiddenSequences hiddenSeqs = viewport.getAlignment() - .getHiddenSequences(); - - alignmentToExport = viewport.getAlignment(); - - boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0; - if (settings == null) + .forName(fileFormatName); + AlignExportSettingsI options = new AlignExportSettingsAdapter(false); + Runnable outputAction = new Runnable() { - settings = new AlignExportSettings(hasHiddenSeqs, - viewport.hasHiddenColumns(), format); - } - // settings.isExportAnnotations(); - - if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns()) - { - omitHidden = viewport.getViewAsString(false, - settings.isExportHiddenSequences()); - } + @Override + public void run() + { + // todo defer this to inside formatSequences (or later) + AlignmentExportData exportData = viewport + .getAlignExportData(options); + CutAndPasteTransfer cap = new CutAndPasteTransfer(); + cap.setForInput(null); + try + { + FileFormatI format = fileFormat; + cap.setText(new FormatAdapter(alignPanel, options) + .formatSequences(format, exportData.getAlignment(), + exportData.getOmitHidden(), + exportData.getStartEndPostions(), + viewport.getAlignment().getHiddenColumns())); + Desktop.addInternalFrame(cap, MessageManager.formatMessage( + "label.alignment_output_command", new Object[] + { fileFormat.getName() }), 600, 500); + } catch (OutOfMemoryError oom) + { + new OOMWarning("Outputting alignment as " + fileFormat.getName(), + oom); + cap.dispose(); + } + } + }; - int[] alignmentStartEnd = new int[2]; - if (hasHiddenSeqs && settings.isExportHiddenSequences()) + /* + * show dialog with export options if applicable; else just do it + */ + if (AlignExportOptions.isNeeded(viewport, fileFormat)) { - alignmentToExport = hiddenSeqs.getFullAlignment(); + AlignExportOptions choices = new AlignExportOptions( + alignPanel.getAlignViewport(), fileFormat, options); + choices.setResponseAction(0, outputAction); + choices.showDialog(); } else { - alignmentToExport = viewport.getAlignment(); + outputAction.run(); } - alignmentStartEnd = viewport.getAlignment().getHiddenColumns() - .getVisibleStartAndEndIndex(alignmentToExport.getWidth()); - AlignmentExportData ed = new AlignmentExportData(alignmentToExport, - omitHidden, alignmentStartEnd, settings); - return ed; } /** @@ -1357,33 +1689,39 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! + * Creates a PNG image of the alignment and writes it to the given file. If + * the file is null, the user is prompted to choose a file. + * + * @param f */ @Override public void createPNG(File f) { - alignPanel.makePNG(f); + alignPanel.makeAlignmentImage(TYPE.PNG, f); } /** - * DOCUMENT ME! + * Creates an EPS image of the alignment and writes it to the given file. If + * the file is null, the user is prompted to choose a file. * - * @param e - * DOCUMENT ME! + * @param f */ @Override public void createEPS(File f) { - alignPanel.makeEPS(f); + alignPanel.makeAlignmentImage(TYPE.EPS, f); } + /** + * Creates an SVG image of the alignment and writes it to the given file. If + * the file is null, the user is prompted to choose a file. + * + * @param f + */ @Override public void createSVG(File f) { - alignPanel.makeSVG(f); + alignPanel.makeAlignmentImage(TYPE.SVG, f); } @Override @@ -1421,25 +1759,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void associatedData_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { - // Pick the tree file - JalviewFileChooser chooser = new JalviewFileChooser( + final JalviewFileChooser chooser = new JalviewFileChooser( jalview.bin.Cache.getProperty("LAST_DIRECTORY")); chooser.setFileView(new JalviewFileView()); - chooser.setDialogTitle( - MessageManager.getString("label.load_jalview_annotations")); - chooser.setToolTipText( - MessageManager.getString("label.load_jalview_annotations")); - - int value = chooser.showOpenDialog(null); - - if (value == JalviewFileChooser.APPROVE_OPTION) + String tooltip = MessageManager + .getString("label.load_jalview_annotations"); + chooser.setDialogTitle(tooltip); + chooser.setToolTipText(tooltip); + chooser.setResponseHandler(0, new Runnable() { - String choice = chooser.getSelectedFile().getPath(); - jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice); - loadJalviewDataFile(choice, null, null, null); - } + @Override + public void run() + { + String choice = chooser.getSelectedFile().getPath(); + jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice); + loadJalviewDataFile(chooser.getSelectedFile(), null, null, null); + } + }); + chooser.showOpenDialog(this); } /** @@ -1478,9 +1818,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, closeView(alignPanel); } } - if (closeAllTabs) { + if (featureSettings != null && featureSettings.isOpen()) + { + 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 @@ -1844,7 +2188,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * DOCUMENT ME! */ @Override - protected void copy_actionPerformed(ActionEvent e) + protected void copy_actionPerformed() { if (viewport.getSelectionGroup() == null) { @@ -1896,7 +2240,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, Desktop.jalviewClipboard = new Object[] { seqs, viewport.getAlignment().getDataset(), hiddenColumns }; - statusBar.setText(MessageManager.formatMessage( + setStatus(MessageManager.formatMessage( "label.copied_sequences_to_clipboard", new Object[] { Integer.valueOf(seqs.length).toString() })); } @@ -1906,9 +2250,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param e * DOCUMENT ME! + * @throws InterruptedException + * @throws IOException */ @Override protected void pasteNew_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { paste(true); } @@ -1918,9 +2265,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param e * DOCUMENT ME! + * @throws InterruptedException + * @throws IOException */ @Override protected void pasteThis_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { paste(false); } @@ -1930,8 +2280,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param newAlignment * true to paste to a new alignment, otherwise add to this. + * @throws InterruptedException + * @throws IOException */ - void paste(boolean newAlignment) + void paste(boolean newAlignment) throws IOException, InterruptedException { boolean externalPaste = true; try @@ -2019,7 +2371,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, && Desktop.jalviewClipboard[1] != alignment.getDataset(); // importDs==true instructs us to copy over new dataset sequences from // an existing alignment - Vector newDs = (importDs) ? new Vector() : null; // used to create + Vector newDs = (importDs) ? new Vector<>() : null; // used to + // create // minimum dataset set for (int i = 0; i < sequences.length; i++) @@ -2158,7 +2511,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { // propagate alignment changed. - viewport.getRanges().setEndSeq(alignment.getHeight()); + viewport.getRanges().setEndSeq(alignment.getHeight() - 1); if (annotationAdded) { // Duplicate sequence annotation in all views. @@ -2259,7 +2612,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, System.out.println("Exception whilst pasting: " + ex); // could be anything being pasted in here } - } @Override @@ -2313,26 +2665,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! + * Action Cut (delete and copy) the selected region */ @Override - protected void cut_actionPerformed(ActionEvent e) + protected void cut_actionPerformed() { - copy_actionPerformed(null); - delete_actionPerformed(null); + copy_actionPerformed(); + delete_actionPerformed(); } /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! + * Performs menu option to Delete the currently selected region */ @Override - protected void delete_actionPerformed(ActionEvent evt) + protected void delete_actionPerformed() { SequenceGroup sg = viewport.getSelectionGroup(); @@ -2341,51 +2687,60 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return; } - /* - * If the cut affects all sequences, warn, remove highlighted columns - */ - if (sg.getSize() == viewport.getAlignment().getHeight()) + Runnable okAction = new Runnable() { - boolean isEntireAlignWidth = (((sg.getEndRes() - sg.getStartRes()) - + 1) == viewport.getAlignment().getWidth()) ? true : false; - if (isEntireAlignWidth) + @Override + public void run() { - int confirm = JvOptionPane.showConfirmDialog(this, - MessageManager.getString("warn.delete_all"), // $NON-NLS-1$ - MessageManager.getString("label.delete_all"), // $NON-NLS-1$ - JvOptionPane.OK_CANCEL_OPTION); + SequenceI[] cut = sg.getSequences() + .toArray(new SequenceI[sg.getSize()]); + + addHistoryItem(new EditCommand( + MessageManager.getString("label.cut_sequences"), Action.CUT, + cut, sg.getStartRes(), + sg.getEndRes() - sg.getStartRes() + 1, + viewport.getAlignment())); - if (confirm == JvOptionPane.CANCEL_OPTION - || confirm == JvOptionPane.CLOSED_OPTION) + viewport.setSelectionGroup(null); + viewport.sendSelection(); + viewport.getAlignment().deleteGroup(sg); + + viewport.firePropertyChange("alignment", null, + viewport.getAlignment().getSequences()); + if (viewport.getAlignment().getHeight() < 1) { - return; + try + { + AlignFrame.this.setClosed(true); + } catch (Exception ex) + { + } } } - viewport.getColumnSelection().removeElements(sg.getStartRes(), - sg.getEndRes() + 1); - } - SequenceI[] cut = sg.getSequences() - .toArray(new SequenceI[sg.getSize()]); - - addHistoryItem(new EditCommand( - MessageManager.getString("label.cut_sequences"), Action.CUT, - cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1, - viewport.getAlignment())); - - viewport.setSelectionGroup(null); - viewport.sendSelection(); - viewport.getAlignment().deleteGroup(sg); + }; - viewport.firePropertyChange("alignment", null, - viewport.getAlignment().getSequences()); - if (viewport.getAlignment().getHeight() < 1) + /* + * If the cut affects all sequences, prompt for confirmation + */ + boolean wholeHeight = sg.getSize() == viewport.getAlignment() + .getHeight(); + boolean wholeWidth = (((sg.getEndRes() - sg.getStartRes()) + + 1) == viewport.getAlignment().getWidth()) ? true : false; + if (wholeHeight && wholeWidth) + { + JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop); + dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION + Object[] options = new Object[] { + MessageManager.getString("action.ok"), + MessageManager.getString("action.cancel") }; + dialog.showDialog(MessageManager.getString("warn.delete_all"), + MessageManager.getString("label.delete_all"), + JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, + options, options[0]); + } + else { - try - { - this.setClosed(true); - } catch (Exception ex) - { - } + okAction.run(); } } @@ -2558,7 +2913,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, column, viewport.getAlignment()); } - statusBar.setText(MessageManager + setStatus(MessageManager .formatMessage("label.removed_columns", new String[] { Integer.valueOf(trimRegion.getSize()).toString() })); @@ -2608,7 +2963,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, addHistoryItem(removeGapCols); - statusBar.setText(MessageManager + setStatus(MessageManager .formatMessage("label.removed_empty_columns", new Object[] { Integer.valueOf(removeGapCols.getSize()).toString() })); @@ -2969,7 +3324,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * @param toggleSeqs * @param toggleCols */ - private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols) + protected void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols) { boolean hide = false; @@ -3186,9 +3541,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void featureSettings_actionPerformed(ActionEvent e) { + showFeatureSettingsUI(); + } + + @Override + public FeatureSettingsControllerI showFeatureSettingsUI() + { if (featureSettings != null) { - featureSettings.close(); + featureSettings.closeOldSettings(); featureSettings = null; } if (!showSeqFeatures.isSelected()) @@ -3198,6 +3559,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, showSeqFeatures_actionPerformed(null); } featureSettings = new FeatureSettings(this); + return featureSettings; } /** @@ -3237,15 +3599,42 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void alignmentProperties() { - JEditorPane editPane = new JEditorPane("text/html", ""); - editPane.setEditable(false); + JComponent pane; StringBuffer contents = new AlignmentProperties(viewport.getAlignment()) + .formatAsHtml(); - editPane.setText( - MessageManager.formatMessage("label.html_content", new Object[] - { contents.toString() })); + String content = MessageManager.formatMessage("label.html_content", + new Object[] + { contents.toString() }); + contents = null; + + if (Platform.isJS()) + { + JLabel textLabel = new JLabel(); + textLabel.setText(content); + textLabel.setBackground(Color.WHITE); + + pane = new JPanel(new BorderLayout()); + ((JPanel) pane).setOpaque(true); + pane.setBackground(Color.WHITE); + ((JPanel) pane).add(textLabel, BorderLayout.NORTH); + } + else + /** + * Java only + * + * @j2sIgnore + */ + { + JEditorPane editPane = new JEditorPane("text/html", ""); + editPane.setEditable(false); + editPane.setText(content); + pane = editPane; + } + JInternalFrame frame = new JInternalFrame(); - frame.getContentPane().add(new JScrollPane(editPane)); + + frame.getContentPane().add(new JScrollPane(pane)); Desktop.addInternalFrame(frame, MessageManager .formatMessage("label.alignment_properties", new Object[] @@ -3284,7 +3673,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { overview.dispose(); alignPanel.setOverviewPanel(null); - }; + } }); if (getKeyListeners().length > 0) { @@ -3354,8 +3743,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * otherwise set the chosen colour scheme (or null for 'None') */ ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name, - viewport, - viewport.getAlignment(), viewport.getHiddenRepSequences()); + viewport, viewport.getAlignment(), + viewport.getHiddenRepSequences()); changeColour(cs); } @@ -3509,6 +3898,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, alignPanel.paintAlignment(true, false); } + @Override + public void sortEValueMenuItem_actionPerformed(ActionEvent e) + { + SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray(); + AlignmentSorter.sortByEValue(viewport.getAlignment()); + addHistoryItem(new OrderCommand("Group Sort", oldOrder, + viewport.getAlignment())); + alignPanel.paintAlignment(true, false); + + } + + @Override + public void sortBitScoreMenuItem_actionPerformed(ActionEvent e) + { + SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray(); + AlignmentSorter.sortByBitScore(viewport.getAlignment()); + addHistoryItem(new OrderCommand("Group Sort", oldOrder, + viewport.getAlignment())); + alignPanel.paintAlignment(true, false); + + } + /** * DOCUMENT ME! * @@ -3718,35 +4129,33 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (viewport.getAlignment().getAlignmentAnnotation() - .hashCode() != _annotationScoreVectorHash) + .hashCode() == _annotationScoreVectorHash) + { + return; + } + + sortByAnnotScore.removeAll(); + Set scoreSorts = new HashSet<>(); + for (SequenceI sqa : viewport.getAlignment().getSequences()) { - sortByAnnotScore.removeAll(); - // almost certainly a quicker way to do this - but we keep it simple - Hashtable scoreSorts = new Hashtable(); - AlignmentAnnotation aann[]; - for (SequenceI sqa : viewport.getAlignment().getSequences()) + AlignmentAnnotation[] anns = sqa.getAnnotation(); + for (int i = 0; anns != null && i < anns.length; i++) { - aann = sqa.getAnnotation(); - for (int i = 0; aann != null && i < aann.length; i++) + AlignmentAnnotation aa = anns[i]; + if (aa != null && aa.hasScore() && aa.sequenceRef != null) { - if (aann[i].hasScore() && aann[i].sequenceRef != null) - { - scoreSorts.put(aann[i].label, aann[i].label); - } + scoreSorts.add(aa.label); } } - Enumeration labels = scoreSorts.keys(); - while (labels.hasMoreElements()) - { - addSortByAnnotScoreMenuItem(sortByAnnotScore, - (String) labels.nextElement()); - } - sortByAnnotScore.setVisible(scoreSorts.size() > 0); - scoreSorts.clear(); - - _annotationScoreVectorHash = viewport.getAlignment() - .getAlignmentAnnotation().hashCode(); } + for (String label : scoreSorts) + { + addSortByAnnotScoreMenuItem(sortByAnnotScore, label); + } + sortByAnnotScore.setVisible(!scoreSorts.isEmpty()); + + _annotationScoreVectorHash = viewport.getAlignment() + .getAlignmentAnnotation().hashCode(); } /** @@ -3906,33 +4315,38 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, chooser.setToolTipText( MessageManager.getString("label.load_tree_file")); - int value = chooser.showOpenDialog(null); - - if (value == JalviewFileChooser.APPROVE_OPTION) + chooser.setResponseHandler(0, new Runnable() { - String filePath = chooser.getSelectedFile().getPath(); - Cache.setProperty("LAST_DIRECTORY", filePath); - NewickFile fin = null; - try - { - fin = new NewickFile(filePath, DataSourceType.FILE); - viewport.setCurrentTree(showNewickTree(fin, filePath).getTree()); - } catch (Exception ex) - { - JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(), - MessageManager.getString("label.problem_reading_tree_file"), - JvOptionPane.WARNING_MESSAGE); - ex.printStackTrace(); - } - if (fin != null && fin.hasWarningMessage()) + @Override + public void run() { - JvOptionPane.showMessageDialog(Desktop.desktop, - fin.getWarningMessage(), - MessageManager - .getString("label.possible_problem_with_tree_file"), - JvOptionPane.WARNING_MESSAGE); + String filePath = chooser.getSelectedFile().getPath(); + Cache.setProperty("LAST_DIRECTORY", filePath); + NewickFile fin = null; + try + { + fin = new NewickFile(new FileParse(chooser.getSelectedFile(), + DataSourceType.FILE)); + viewport.setCurrentTree(showNewickTree(fin, filePath).getTree()); + } catch (Exception ex) + { + JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(), + MessageManager + .getString("label.problem_reading_tree_file"), + JvOptionPane.WARNING_MESSAGE); + ex.printStackTrace(); + } + if (fin != null && fin.hasWarningMessage()) + { + JvOptionPane.showMessageDialog(Desktop.desktop, + fin.getWarningMessage(), + MessageManager.getString( + "label.possible_problem_with_tree_file"), + JvOptionPane.WARNING_MESSAGE); + } } - } + }); + chooser.showOpenDialog(this); } public TreePanel showNewickTree(NewickFile nf, String treeTitle) @@ -3996,182 +4410,79 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return tp; } - private boolean buildingMenu = false; - /** - * Generates menu items and listener event actions for web service clients - * + * Schedule the web services menu rebuild to the event dispatch thread. */ - public void BuildWebServiceMenu() + public void buildWebServicesMenu() { - while (buildingMenu) - { - try + SwingUtilities.invokeLater(() -> { + Cache.log.info("Rebuiling WS menu"); + webService.removeAll(); + if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true)) { - System.err.println("Waiting for building menu to finish."); - Thread.sleep(10); - } catch (Exception e) + SlivkaWSDiscoverer discoverer = SlivkaWSDiscoverer.getInstance(); + JMenu submenu = new JMenu("Slivka"); + buildWebServicesMenu(discoverer, submenu); + webService.add(submenu); + } + if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { + WSDiscovererI jws2servs = Jws2Discoverer.getDiscoverer(); + JMenu submenu = new JMenu("JABAWS"); + buildLegacyWebServicesMenu(submenu); + buildWebServicesMenu(jws2servs, submenu); + webService.add(submenu); } - } - final AlignFrame me = this; - buildingMenu = true; - new Thread(new Runnable() + }); + } + + private void buildLegacyWebServicesMenu(JMenu menu) + { + JMenu secstrmenu = new JMenu("Secondary Structure Prediction"); + if (Discoverer.services != null && Discoverer.services.size() > 0) { - @Override - public void run() + var secstrpred = Discoverer.services.get("SecStrPred"); + if (secstrpred != null) { - final List legacyItems = new ArrayList<>(); - try - { - // System.err.println("Building ws menu again " - // + Thread.currentThread()); - // TODO: add support for context dependent disabling of services based - // on - // alignment and current selection - // TODO: add additional serviceHandle parameter to specify abstract - // handler - // class independently of AbstractName - // TODO: add in rediscovery GUI function to restart discoverer - // TODO: group services by location as well as function and/or - // introduce - // object broker mechanism. - final Vector wsmenu = new Vector<>(); - final IProgressIndicator af = me; - - /* - * do not i18n these strings - they are hard-coded in class - * compbio.data.msa.Category, Jws2Discoverer.isRecalculable() and - * SequenceAnnotationWSClient.initSequenceAnnotationWSClient() - */ - final JMenu msawsmenu = new JMenu("Alignment"); - final JMenu secstrmenu = new JMenu( - "Secondary Structure Prediction"); - final JMenu seqsrchmenu = new JMenu("Sequence Database Search"); - final JMenu analymenu = new JMenu("Analysis"); - final JMenu dismenu = new JMenu("Protein Disorder"); - // JAL-940 - only show secondary structure prediction services from - // the legacy server - if (// Cache.getDefault("SHOW_JWS1_SERVICES", true) - // && - Discoverer.services != null && (Discoverer.services.size() > 0)) - { - // TODO: refactor to allow list of AbstractName/Handler bindings to - // be - // stored or retrieved from elsewhere - // No MSAWS used any more: - // Vector msaws = null; // (Vector) - // Discoverer.services.get("MsaWS"); - Vector secstrpr = (Vector) Discoverer.services - .get("SecStrPred"); - if (secstrpr != null) - { - // Add any secondary structure prediction services - for (int i = 0, j = secstrpr.size(); i < j; i++) - { - final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr - .get(i); - jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer - .getServiceClient(sh); - int p = secstrmenu.getItemCount(); - impl.attachWSMenuEntry(secstrmenu, me); - int q = secstrmenu.getItemCount(); - for (int litm = p; litm < q; litm++) - { - legacyItems.add(secstrmenu.getItem(litm)); - } - } - } - } - - // Add all submenus in the order they should appear on the web - // services menu - wsmenu.add(msawsmenu); - wsmenu.add(secstrmenu); - wsmenu.add(dismenu); - wsmenu.add(analymenu); - // No search services yet - // wsmenu.add(seqsrchmenu); - - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - try - { - webService.removeAll(); - // first, add discovered services onto the webservices menu - if (wsmenu.size() > 0) - { - for (int i = 0, j = wsmenu.size(); i < j; i++) - { - webService.add(wsmenu.get(i)); - } - } - else - { - webService.add(me.webServiceNoServices); - } - // TODO: move into separate menu builder class. - boolean new_sspred = false; - if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) - { - Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer(); - if (jws2servs != null) - { - if (jws2servs.hasServices()) - { - jws2servs.attachWSMenuEntry(webService, me); - for (Jws2Instance sv : jws2servs.getServices()) - { - if (sv.description.toLowerCase().contains("jpred")) - { - for (JMenuItem jmi : legacyItems) - { - jmi.setVisible(false); - } - } - } - - } - if (jws2servs.isRunning()) - { - JMenuItem tm = new JMenuItem( - "Still discovering JABA Services"); - tm.setEnabled(false); - webService.add(tm); - } - } - } - build_urlServiceMenu(me.webService); - build_fetchdbmenu(webService); - for (JMenu item : wsmenu) - { - if (item.getItemCount() == 0) - { - item.setEnabled(false); - } - else - { - item.setEnabled(true); - } - } - } catch (Exception e) - { - Cache.log.debug( - "Exception during web service menu building process.", - e); - } - } - }); - } catch (Exception e) + for (ext.vamsas.ServiceHandle sh : secstrpred) { + var menuProvider = Discoverer.getServiceClient(sh); + menuProvider.attachWSMenuEntry(secstrmenu, this); } - buildingMenu = false; } - }).start(); + } + menu.add(secstrmenu); + } + /** + * Constructs the web services menu for the given discoverer under the + * specified menu. This method must be called on the EDT + * + * @param discoverer + * the discoverer used to build the menu + * @param menu + * parent component which the elements will be attached to + */ + private void buildWebServicesMenu(WSDiscovererI discoverer, JMenu menu) + { + if (discoverer.hasServices()) + { + PreferredServiceRegistry.getRegistry().populateWSMenuEntry( + discoverer.getServices(), sv -> buildWebServicesMenu(), menu, + this, null); + } + if (discoverer.isRunning()) + { + JMenuItem item = new JMenuItem("Service discovery in progress."); + item.setEnabled(false); + menu.add(item); + } + else if (!discoverer.hasServices()) + { + JMenuItem item = new JMenuItem("No services available."); + item.setEnabled(false); + menu.add(item); + } } /** @@ -4179,7 +4490,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param webService */ - private void build_urlServiceMenu(JMenu webService) + protected void build_urlServiceMenu(JMenu webService) { // TODO: remove this code when 2.7 is released // DEBUG - alignmentView @@ -4352,13 +4663,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * Try to load a features file onto the alignment. * * @param file - * contents or path to retrieve file + * contents or path to retrieve file or a File object * @param sourceType * access mode of file (see jalview.io.AlignFile) * @return true if features file was parsed correctly. */ - public boolean parseFeaturesFile(String file, DataSourceType sourceType) + public boolean parseFeaturesFile(Object file, DataSourceType sourceType) { + // BH 2018 return avc.parseFeaturesFile(file, sourceType, Cache.getDefault("RELAXEDSEQIDMATCHING", false)); @@ -4405,8 +4717,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // Java's Transferable for native dnd evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); Transferable t = evt.getTransferable(); + final AlignFrame thisaf = this; - final List files = new ArrayList<>(); + final List files = new ArrayList<>(); List protocols = new ArrayList<>(); try @@ -4434,20 +4747,33 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * Object[] { String,SequenceI} */ ArrayList filesmatched = new ArrayList<>(); - ArrayList filesnotmatched = new ArrayList<>(); + ArrayList filesnotmatched = new ArrayList<>(); for (int i = 0; i < files.size(); i++) { - String file = files.get(i).toString(); + // BH 2018 + Object file = files.get(i); + String fileName = file.toString(); String pdbfn = ""; - DataSourceType protocol = FormatAdapter.checkProtocol(file); + DataSourceType protocol = (file instanceof File + ? DataSourceType.FILE + : FormatAdapter.checkProtocol(fileName)); if (protocol == DataSourceType.FILE) { - File fl = new File(file); + File fl; + if (file instanceof File) + { + fl = (File) file; + Platform.cacheFileData(fl); + } + else + { + fl = new File(fileName); + } pdbfn = fl.getName(); } else if (protocol == DataSourceType.URL) { - URL url = new URL(file); + URL url = new URL(fileName); pdbfn = url.getFile(); } if (pdbfn.length() > 0) @@ -4469,7 +4795,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (mtch != null) { - FileFormatI type = null; + FileFormatI type; try { type = new IdentifyFile().identify(file, protocol); @@ -4516,13 +4842,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, for (SequenceI toassoc : (SequenceI[]) fm[2]) { PDBEntry pe = new AssociatePdbFileWithSeq() - .associatePdbWithSeq((String) fm[0], + .associatePdbWithSeq(fm[0].toString(), (DataSourceType) fm[1], toassoc, false, Desktop.instance); if (pe != null) { System.err.println("Associated file : " - + ((String) fm[0]) + " with " + + (fm[0].toString()) + " with " + toassoc.getDisplayId(true)); assocfiles++; } @@ -4539,7 +4865,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ for (Object[] o : filesmatched) { - filesnotmatched.add((String) o[0]); + filesnotmatched.add(o[0]); } } } @@ -4561,7 +4887,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { return; } - for (String fn : filesnotmatched) + for (Object fn : filesnotmatched) { loadJalviewDataFile(fn, null, null, null); } @@ -4587,10 +4913,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param file * either a filename or a URL string. + * @throws InterruptedException + * @throws IOException */ - public void loadJalviewDataFile(String file, DataSourceType sourceType, + public void loadJalviewDataFile(Object file, DataSourceType sourceType, FileFormatI format, SequenceI assocSeq) { + // BH 2018 was String file try { if (sourceType == null) @@ -4621,7 +4950,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, changeColour( new TCoffeeColourScheme(viewport.getAlignment())); isAnnotation = true; - statusBar.setText(MessageManager.getString( + setStatus(MessageManager.getString( "label.successfully_pasted_tcoffee_scores_to_alignment")); } else @@ -4664,7 +4993,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, new FileParse(file, sourceType)); sm.parse(); // todo: i18n this message - statusBar.setText(MessageManager.formatMessage( + setStatus(MessageManager.formatMessage( "label.successfully_loaded_matrix", sm.getMatrixName())); } @@ -4682,7 +5011,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { if (parseFeaturesFile(file, sourceType)) { - alignPanel.paintAlignment(true, true); + SplitFrame splitFrame = (SplitFrame) getSplitViewContainer(); + if (splitFrame != null) + { + splitFrame.repaint(); + } + else + { + alignPanel.paintAlignment(true, true); + } } } else @@ -4693,7 +5030,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (isAnnotation) { - alignPanel.adjustAnnotationHeight(); viewport.updateSequenceIdColours(); buildSortByAnnotationScoresMenu(); @@ -4738,6 +5074,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, viewport = alignPanel.av; avc.setViewportAndAlignmentPanel(viewport, alignPanel); setMenusFromViewport(viewport); + if (featureSettings != null && featureSettings.isOpen() + && featureSettings.fr.getViewport() != viewport) + { + if (viewport.isShowSequenceFeatures()) + { + // refresh the featureSettings to reflect UI change + showFeatureSettingsUI(); + } + else + { + // close feature settings for this view. + featureSettings.close(); + } + } + } /* @@ -4790,8 +5141,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (e.isPopupTrigger()) { String msg = MessageManager.getString("label.enter_view_name"); - String reply = JvOptionPane.showInternalInputDialog(this, msg, msg, - JvOptionPane.QUESTION_MESSAGE); + String ttl = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex()); + String reply = JvOptionPane.showInputDialog(msg, ttl); if (reply != null) { @@ -4906,7 +5257,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, trimrs.setSelected(trimrs.isSelected()); Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, Boolean.valueOf(trimrs.isSelected()).toString()); - }; + } }); rfetch.add(trimrs); JMenuItem fetchr = new JMenuItem( @@ -4935,6 +5286,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void finished() { + + for (FeatureSettingsModelI srcSettings : dbRefFetcher + .getFeatureSettingsModels()) + { + + alignPanel.av.mergeFeaturesStyle(srcSettings); + } AlignFrame.this.setMenusForViewport(); } }); @@ -4946,22 +5304,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, }); rfetch.add(fetchr); - final AlignFrame me = this; new Thread(new Runnable() { @Override public void run() { final jalview.ws.SequenceFetcher sf = jalview.gui.SequenceFetcher - .getSequenceFetcherSingleton(me); + .getSequenceFetcherSingleton(); javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - String[] dbclasses = sf.getOrderedSupportedSources(); - // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class); - // jalview.util.QuickSort.sort(otherdb, otherdb); + String[] dbclasses = sf.getNonAlignmentSources(); List otherdb; JMenu dfetch = new JMenu(); JMenu ifetch = new JMenu(); @@ -4978,12 +5333,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { continue; } - // List dbs=otherdb; - // otherdb=new ArrayList(); - // for (DbSourceProxy db:dbs) - // { - // if (!db.isA(DBRefSource.ALIGNMENTDB) - // } if (mname == null) { mname = "From " + dbclass; @@ -5020,6 +5369,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void finished() { + FeatureSettingsModelI srcSettings = dassource[0] + .getFeatureColourScheme(); + alignPanel.av.mergeFeaturesStyle( + srcSettings); AlignFrame.this.setMenusForViewport(); } }); @@ -5626,6 +5979,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } } + /** + * Sets the status of the HMMER menu + */ + public void updateHMMERStatus() + { + hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable()); + } + @Override protected void loadVcf_actionPerformed() { @@ -5634,17 +5995,34 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle(MessageManager.getString("label.load_vcf_file")); chooser.setToolTipText(MessageManager.getString("label.load_vcf_file")); + final AlignFrame us = this; + chooser.setResponseHandler(0, new Runnable() + { + @Override + public void run() + { + String choice = chooser.getSelectedFile().getPath(); + Cache.setProperty("LAST_DIRECTORY", choice); + SequenceI[] seqs = viewport.getAlignment().getSequencesArray(); + new VCFLoader(choice).loadVCF(seqs, us); + } + }); + chooser.showOpenDialog(null); + + } - int value = chooser.showOpenDialog(null); + private Rectangle lastFeatureSettingsBounds = null; - if (value == JalviewFileChooser.APPROVE_OPTION) - { - String choice = chooser.getSelectedFile().getPath(); - Cache.setProperty("LAST_DIRECTORY", choice); - SequenceI[] seqs = viewport.getAlignment().getSequencesArray(); - new VCFLoader(choice).loadVCF(seqs, this); - } + @Override + public void setFeatureSettingsGeometry(Rectangle bounds) + { + lastFeatureSettingsBounds = bounds; + } + @Override + public Rectangle getFeatureSettingsGeometry() + { + return lastFeatureSettingsBounds; } }