From b87512d6e28a2a93ea2f08dcfbee320856c5c8de Mon Sep 17 00:00:00 2001 From: BobHanson Date: Thu, 9 Apr 2020 13:03:44 -0500 Subject: [PATCH] temp push --- src/jalview/api/AlignFrameI.java | 13 + src/jalview/api/JalviewApp.java | 82 + src/jalview/appletgui/AlignFrame.java | 5 +- src/jalview/appletgui/AlignmentPanel.java | 8 + src/jalview/appletgui/AnnotationColourChooser.java | 7 +- src/jalview/appletgui/AnnotationLabels.java | 4 +- src/jalview/appletgui/AnnotationPanel.java | 4 +- src/jalview/appletgui/EmbmenuFrame.java | 15 +- src/jalview/appletgui/FeatureColourChooser.java | 2 +- src/jalview/appletgui/FeatureSettings.java | 2 +- src/jalview/appletgui/FontChooser.java | 6 +- src/jalview/appletgui/IdPanel.java | 4 +- src/jalview/appletgui/OverviewCanvas.java | 75 +- src/jalview/appletgui/OverviewPanel.java | 35 +- src/jalview/appletgui/ScalePanel.java | 4 +- src/jalview/appletgui/SeqCanvas.java | 8 +- src/jalview/appletgui/TreePanel.java | 6 +- src/jalview/bin/AlignViewController.java | 473 ++++++ src/jalview/bin/AppletParams.java | 447 +++++ src/jalview/bin/ArgsParser.java | 101 +- src/jalview/bin/AssociatePdbFileWithSeq.java | 91 + src/jalview/bin/Jalview.java | 1737 ++++++++++++++++---- src/jalview/bin/JalviewAppLoader.java | 1484 +++++++++++++++++ src/jalview/bin/JalviewJSApi.java | 52 + src/jalview/bin/JalviewLite.java | 1209 +++++--------- src/jalview/datamodel/features/FeatureStore.java | 986 ++++++----- .../datamodel/features/SequenceFeatures.java | 50 +- .../datamodel/features/SequenceFeaturesI.java | 21 +- src/jalview/ext/ensembl/EnsemblCds.java | 2 +- src/jalview/ext/ensembl/EnsemblGene.java | 4 +- src/jalview/ext/ensembl/EnsemblSeqProxy.java | 4 +- src/jalview/gui/APQHandlers.java | 2 +- src/jalview/gui/AlignExportOptions.java | 2 +- src/jalview/gui/AlignFrame.java | 636 ++++--- src/jalview/gui/AlignViewport.java | 192 ++- src/jalview/gui/AnnotationColourChooser.java | 2 +- src/jalview/gui/AnnotationLabels.java | 2 +- src/jalview/gui/AppJmol.java | 2 +- src/jalview/gui/AssociatePdbFileWithSeq.java | 77 +- src/jalview/gui/CalculationChooser.java | 165 +- src/jalview/gui/ChimeraViewFrame.java | 4 +- src/jalview/gui/ColourMenuHelper.java | 4 +- src/jalview/gui/CrossRefAction.java | 2 +- src/jalview/gui/CutAndPasteTransfer.java | 6 +- src/jalview/gui/Desktop.java | 591 ++++--- src/jalview/gui/FeatureEditor.java | 4 +- src/jalview/gui/FeatureRenderer.java | 13 +- src/jalview/gui/FeatureSettings.java | 52 +- src/jalview/gui/Finder.java | 4 +- src/jalview/gui/IdPanel.java | 4 +- src/jalview/gui/JalviewDialog.java | 6 +- src/jalview/gui/JvSwingUtils.java | 19 +- src/jalview/gui/LineartOptions.java | 4 +- src/jalview/gui/OOMWarning.java | 2 +- src/jalview/gui/PopupMenu.java | 74 +- src/jalview/gui/PromptUserConfig.java | 2 +- src/jalview/gui/SeqPanel.java | 63 +- src/jalview/gui/SequenceFetcher.java | 2 +- src/jalview/gui/SplashScreen.java | 12 +- src/jalview/gui/SplitFrame.java | 19 +- src/jalview/gui/StructureChooser.java | 6 +- src/jalview/gui/StructureViewer.java | 144 +- src/jalview/gui/StructureViewerBase.java | 2 +- src/jalview/gui/UserDefinedColours.java | 10 +- src/jalview/gui/UserQuestionnaireCheck.java | 2 +- src/jalview/gui/VamsasApplication.java | 18 +- src/jalview/gui/WebserviceInfo.java | 2 +- src/jalview/gui/WsJobParameters.java | 10 +- src/jalview/gui/WsParamSetManager.java | 4 +- src/jalview/gui/WsPreferences.java | 28 +- src/jalview/io/FeaturesFile.java | 119 +- src/jalview/io/FileLoader.java | 258 +-- src/jalview/io/VamsasAppDatastore.java | 6 +- src/jalview/io/WSWUBlastClient.java | 2 +- src/jalview/io/gff/Gff3Helper.java | 4 +- src/jalview/io/gff/InterProScanHelper.java | 2 +- src/jalview/io/gff/SequenceOntologyFactory.java | 57 +- src/jalview/io/vamsas/Sequencemapping.java | 2 +- src/jalview/javascript/JSFunctionExec.java | 114 +- src/jalview/javascript/JalviewLiteJsApi.java | 164 +- src/jalview/javascript/MouseOverListener.java | 25 +- src/jalview/jbgui/GDesktop.java | 106 +- src/jalview/jbgui/GSequenceLink.java | 4 +- src/jalview/project/Jalview2XML.java | 38 +- .../structure/StructureSelectionManager.java | 165 +- src/jalview/util/Platform.java | 19 + src/jalview/util/ShortcutKeyMaskExWrapper.java | 56 +- src/jalview/util/StringUtils.java | 82 +- src/jalview/viewmodel/AlignmentViewport.java | 37 +- .../seqfeatures/FeatureRendererModel.java | 12 +- src/jalview/ws/DBRefFetcher.java | 5 +- src/jalview/ws/SequenceFetcher.java | 104 +- src/jalview/ws/SequenceFetcherFactory.java | 28 +- src/jalview/ws/jws1/Discoverer.java | 134 +- src/jalview/ws/jws1/JPredClient.java | 2 +- src/jalview/ws/jws1/MsaWSClient.java | 4 +- src/jalview/ws/jws1/SeqSearchWSClient.java | 4 +- src/jalview/ws/jws2/Jws2Client.java | 4 +- src/jalview/ws/jws2/Jws2Discoverer.java | 63 +- src/jalview/ws/jws2/MsaWSClient.java | 4 +- .../ws/jws2/SequenceAnnotationWSClient.java | 4 +- src/jalview/ws/jws2/jabaws2/Jws2Instance.java | 2 +- src/jalview/ws/rest/RestClient.java | 2 +- src/jalview/ws/seqfetcher/ASequenceFetcher.java | 128 +- src/jalview/ws/seqfetcher/DbSourceProxyRoot.java | 11 + test/jalview/analysis/FinderTest.java | 2 +- test/jalview/ext/jmol/JmolParserTest.java | 6 +- test/jalview/ext/jmol/JmolViewerTest.java | 2 +- test/jalview/ext/rbvi/chimera/FeatureRenderer.java | 300 ++++ .../ext/rbvi/chimera/JalviewChimeraView.java | 2 +- test/jalview/gui/AlignFrameTest.java | 4 +- test/jalview/gui/AlignViewportTest.java | 14 +- test/jalview/gui/AlignmentPanelTest.java | 2 +- test/jalview/gui/AnnotationChooserTest.java | 10 +- test/jalview/gui/AnnotationColumnChooserTest.java | 10 +- test/jalview/gui/AnnotationRowFilterTest.java | 4 +- test/jalview/gui/CalculationChooserTest.java | 4 +- test/jalview/gui/FreeUpMemoryTest.java | 14 +- test/jalview/gui/SeqPanelTest.java | 18 +- test/jalview/io/AnnotatedPDBFileInputTest.java | 6 +- test/jalview/io/CrossRef2xmlTests.java | 6 +- test/jalview/io/Jalview2xmlBase.java | 4 +- test/jalview/io/JalviewExportPropertiesTests.java | 2 +- test/jalview/project/Jalview2xmlTests.java | 32 +- test/jalview/schemes/ColourSchemesTest.java | 2 +- .../structure/StructureSelectionManagerTest.java | 2 +- test/jalview/ws/PDBSequenceFetcherTest.java | 6 +- test/jalview/ws/dbsources/RemoteFormatTest.java | 4 +- test/mc_view/PDBfileTest.java | 6 +- 129 files changed, 8174 insertions(+), 3193 deletions(-) create mode 100644 src/jalview/api/AlignFrameI.java create mode 100644 src/jalview/api/JalviewApp.java create mode 100644 src/jalview/bin/AlignViewController.java create mode 100644 src/jalview/bin/AppletParams.java create mode 100644 src/jalview/bin/AssociatePdbFileWithSeq.java create mode 100644 src/jalview/bin/JalviewAppLoader.java create mode 100644 src/jalview/bin/JalviewJSApi.java create mode 100644 src/jalview/ws/seqfetcher/DbSourceProxyRoot.java create mode 100644 test/jalview/ext/rbvi/chimera/FeatureRenderer.java diff --git a/src/jalview/api/AlignFrameI.java b/src/jalview/api/AlignFrameI.java new file mode 100644 index 0000000..c675a6e --- /dev/null +++ b/src/jalview/api/AlignFrameI.java @@ -0,0 +1,13 @@ +package jalview.api; + +/** + * Common methods for jalview.appletgui.AlignFrame and jalview.gui.AlignFrame in + * relation to JalviewJS and the JalviewLiteJSApi + * + * @author hansonr + * + */ +public interface AlignFrameI +{ + +} diff --git a/src/jalview/api/JalviewApp.java b/src/jalview/api/JalviewApp.java new file mode 100644 index 0000000..0548c85 --- /dev/null +++ b/src/jalview/api/JalviewApp.java @@ -0,0 +1,82 @@ +package jalview.api; + +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.NewickFile; +import jalview.javascript.JSFunctionExec; +import jalview.javascript.MouseOverStructureListener; +import jalview.structure.SelectionSource; +import jalview.structure.VamsasSource; + +import java.applet.AppletContext; +import java.io.IOException; +import java.net.URL; +import java.util.Hashtable; +import java.util.Vector; + +import netscape.javascript.JSObject; + +public interface JalviewApp +{ + public String getParameter(String name); + + public boolean getDefaultParameter(String name, boolean def); + + public URL getDocumentBase(); + + public URL getCodeBase(); + + public void setAlignPdbStructures(boolean defaultParameter); + + public void newStructureView(PDBEntry pdb, SequenceI[] seqs, + String[] chains, DataSourceType protocol); + + public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs, + String[][] chains, String[] protocols); + + public void updateForAnnotations(); + + public AlignViewportI getViewport(); + + public void setFeatureGroupState(String[] groups, boolean state); + + public boolean parseFeaturesFile(String param, DataSourceType protocol); + + public void newFeatureSettings(); + + public boolean loadScoreFile(String sScoreFile) throws IOException; + + public void loadTree(NewickFile fin, String treeFile) throws IOException; + + public Vector getJsExecQueue(JSFunctionExec jsFunctionExec); + + public AppletContext getAppletContext(); + + public boolean isJsfallbackEnabled(); + + public JSObject getJSObject(); + + public StructureSelectionManagerProvider getStructureSelectionManagerProvider(); + + public void updateColoursFromMouseOver(Object source, + MouseOverStructureListener mouseOverStructureListener); + + public Object[] getSelectionForListener(SequenceGroup seqsel, ColumnSelection colsel, + HiddenColumns hidden, SelectionSource source, Object alignFrame); + + public String arrayToSeparatorList(String[] array); + + public Hashtable getJSHashes(); + + Hashtable> getJSMessages(); + + public Object getFrameForSource(VamsasSource source); + + public jalview.renderer.seqfeatures.FeatureRenderer getNewFeatureRenderer( + AlignViewportI vp); + +} diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index 1a46585..997f185 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -25,6 +25,7 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; import jalview.analysis.TreeBuilder; import jalview.analysis.scoremodels.PIDModel; import jalview.analysis.scoremodels.ScoreModels; +import jalview.api.AlignFrameI; import jalview.api.AlignViewControllerGuiI; import jalview.api.AlignViewControllerI; import jalview.api.AlignViewportI; @@ -121,7 +122,7 @@ import java.util.Vector; import org.jmol.viewer.Viewer; public class AlignFrame extends EmbmenuFrame implements ActionListener, - ItemListener, KeyListener, AlignViewControllerGuiI + ItemListener, KeyListener, AlignViewControllerGuiI, AlignFrameI { public AlignViewControllerI avc; @@ -882,7 +883,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } else if (source == autoCalculate) { - viewport.autoCalculateConsensus = autoCalculate.getState(); + viewport.setAutoCalculateConsensusAndConservation(autoCalculate.getState()); } else if (source == sortByTree) { diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java index 58569cd..df8fe87 100644 --- a/src/jalview/appletgui/AlignmentPanel.java +++ b/src/jalview/appletgui/AlignmentPanel.java @@ -43,6 +43,7 @@ import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.util.List; @@ -178,6 +179,7 @@ public class AlignmentPanel extends Panel return av; } + @Override public SequenceRenderer getSequenceRenderer() { return seqPanel.seqCanvas.sr; @@ -1158,4 +1160,10 @@ public class AlignmentPanel extends Panel } + @Override + public void overviewDone(BufferedImage miniMe) + { + overviewPanel.canvas.finalizeDraw(miniMe); + } + } diff --git a/src/jalview/appletgui/AnnotationColourChooser.java b/src/jalview/appletgui/AnnotationColourChooser.java index 9456986..6eca05e 100644 --- a/src/jalview/appletgui/AnnotationColourChooser.java +++ b/src/jalview/appletgui/AnnotationColourChooser.java @@ -22,6 +22,7 @@ package jalview.appletgui; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.SequenceGroup; +import jalview.gui.Preferences; import jalview.schemes.AnnotationColourGradient; import jalview.schemes.ColourSchemeI; import jalview.util.MessageManager; @@ -217,9 +218,9 @@ public class AnnotationColourChooser extends Panel implements private void setDefaultMinMax() { minColour.setBackground(av.applet.getDefaultColourParameter( - "ANNOTATIONCOLOUR_MIN", Color.orange)); + Preferences.ANNOTATIONCOLOUR_MIN, Color.orange)); maxColour.setBackground(av.applet - .getDefaultColourParameter("ANNOTATIONCOLOUR_MAX", Color.red)); + .getDefaultColourParameter(Preferences.ANNOTATIONCOLOUR_MAX, Color.red)); } @@ -350,7 +351,7 @@ public class AnnotationColourChooser extends Panel implements { try { - float f = Float.valueOf(thresholdValue.getText()).floatValue(); + float f = new Float(thresholdValue.getText()).floatValue(); slider.setValue((int) (f * 1000)); adjustmentValueChanged(null); } catch (NumberFormatException ex) diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index a0102b9..1366f31 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -457,8 +457,8 @@ public class AnnotationLabels extends Panel .getAlignmentAnnotation(); // DETECT RIGHT MOUSE BUTTON IN AWT - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { PopupMenu popup = new PopupMenu( diff --git a/src/jalview/appletgui/AnnotationPanel.java b/src/jalview/appletgui/AnnotationPanel.java index 3dae998..26d3a3b 100755 --- a/src/jalview/appletgui/AnnotationPanel.java +++ b/src/jalview/appletgui/AnnotationPanel.java @@ -354,8 +354,8 @@ public class AnnotationPanel extends Panel } } - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK && activeRow != -1) { if (av.getColumnSelection() == null diff --git a/src/jalview/appletgui/EmbmenuFrame.java b/src/jalview/appletgui/EmbmenuFrame.java index 8b2b279..b6b81fa 100644 --- a/src/jalview/appletgui/EmbmenuFrame.java +++ b/src/jalview/appletgui/EmbmenuFrame.java @@ -51,8 +51,8 @@ import java.util.Map; * @author Jim Procter and Andrew Waterhouse * */ -public class EmbmenuFrame extends Frame - implements MouseListener, AutoCloseable +@SuppressWarnings("serial") +public class EmbmenuFrame extends Frame implements MouseListener { protected static final Font FONT_ARIAL_PLAIN_11 = new Font("Arial", Font.PLAIN, 11); @@ -62,7 +62,7 @@ public class EmbmenuFrame extends Frame /** * map from labels to popup menus for the embedded menubar */ - protected Map embeddedPopup = new HashMap<>(); + protected Map embeddedPopup = new HashMap(); /** * the embedded menu is built on this and should be added to the frame at the @@ -202,7 +202,6 @@ public class EmbmenuFrame extends Frame return embeddedMenu; } - @Override public void mousePressed(MouseEvent evt) { PopupMenu popup = null; @@ -227,22 +226,18 @@ public class EmbmenuFrame extends Frame return embeddedPopup.get(source); } - @Override public void mouseClicked(MouseEvent evt) { } - @Override public void mouseReleased(MouseEvent evt) { } - @Override public void mouseEntered(MouseEvent evt) { } - @Override public void mouseExited(MouseEvent evt) { } @@ -270,11 +265,11 @@ public class EmbmenuFrame extends Frame /** * calls destroyMenus() */ - @Override - public void close() + public void finalize() throws Throwable { destroyMenus(); embeddedPopup = null; embeddedMenu = null; + super.finalize(); } } diff --git a/src/jalview/appletgui/FeatureColourChooser.java b/src/jalview/appletgui/FeatureColourChooser.java index 0d70660..5569ab0 100644 --- a/src/jalview/appletgui/FeatureColourChooser.java +++ b/src/jalview/appletgui/FeatureColourChooser.java @@ -311,7 +311,7 @@ public class FeatureColourChooser extends Panel implements ActionListener, { try { - float f = Float.valueOf(thresholdValue.getText()).floatValue(); + float f = new Float(thresholdValue.getText()).floatValue(); slider.setValue((int) (f * SCALE_FACTOR_1K)); adjustmentValueChanged(null); diff --git a/src/jalview/appletgui/FeatureSettings.java b/src/jalview/appletgui/FeatureSettings.java index 489cbb1..a60aacd 100755 --- a/src/jalview/appletgui/FeatureSettings.java +++ b/src/jalview/appletgui/FeatureSettings.java @@ -703,7 +703,7 @@ public class FeatureSettings extends Panel public void mouseClicked(MouseEvent evt) { MyCheckbox check = (MyCheckbox) evt.getSource(); - if ((evt.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0) + if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { this.popupSort(check, fr.getMinMax(), evt.getX(), evt.getY()); } diff --git a/src/jalview/appletgui/FontChooser.java b/src/jalview/appletgui/FontChooser.java index 8b74e32..443ebce 100644 --- a/src/jalview/appletgui/FontChooser.java +++ b/src/jalview/appletgui/FontChooser.java @@ -31,9 +31,9 @@ import java.awt.FlowLayout; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Frame; -import java.awt.GraphicsEnvironment; import java.awt.Label; import java.awt.Panel; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -144,9 +144,7 @@ public class FontChooser extends Panel implements ItemListener */ void init() { - // String fonts[] = Toolkit.getDefaultToolkit().getFontList(); - String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment() - .getAvailableFontFamilyNames(); + String fonts[] = Toolkit.getDefaultToolkit().getFontList(); for (int i = 0; i < fonts.length; i++) { fontName.addItem(fonts[i]); diff --git a/src/jalview/appletgui/IdPanel.java b/src/jalview/appletgui/IdPanel.java index 1d37d08..af1c47b 100755 --- a/src/jalview/appletgui/IdPanel.java +++ b/src/jalview/appletgui/IdPanel.java @@ -279,8 +279,8 @@ public class IdPanel extends Panel int seq = alignPanel.seqPanel.findSeq(e); - if ((e.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((e.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { SequenceI sq = av.getAlignment().getSequenceAt(seq); diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java index 07f5919..7f4e962 100644 --- a/src/jalview/appletgui/OverviewCanvas.java +++ b/src/jalview/appletgui/OverviewCanvas.java @@ -30,7 +30,9 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; +import java.awt.image.BufferedImage; +@SuppressWarnings("serial") public class OverviewCanvas extends Component { // This is set true if the alignment view changes whilst @@ -49,13 +51,23 @@ public class OverviewCanvas extends Component private AlignViewport av; + private boolean showSequenceFeatures; + + private boolean showAnnotation; + + private jalview.api.FeatureRenderer featureRenderer; + private jalview.renderer.seqfeatures.FeatureRenderer fr; private Frame nullFrame; - public OverviewCanvas(OverviewDimensions overviewDims, + private OverviewPanel panel; + + public OverviewCanvas(OverviewPanel panel, + OverviewDimensions overviewDims, AlignViewport alignvp) { + this.panel = panel; od = overviewDims; av = alignvp; @@ -101,46 +113,23 @@ public class OverviewCanvas extends Component } public void draw(boolean showSequenceFeatures, boolean showAnnotation, - FeatureRenderer transferRenderer) + jalview.api.FeatureRenderer featureRenderer) { - miniMe = null; + this.showSequenceFeatures = showSequenceFeatures; + this.showAnnotation = showAnnotation; + this.featureRenderer = featureRenderer; if (showSequenceFeatures) { - fr.transferSettings(transferRenderer); + fr.transferSettings(featureRenderer); } setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); - or = new OverviewRenderer(fr, od, av.getAlignment(), + or = new OverviewRenderer(panel.ap, fr, od, av.getAlignment(), av.getResidueShading(), new OverviewResColourFinder()); - miniMe = nullFrame.createImage(od.getWidth(), od.getHeight()); offscreen = nullFrame.createImage(od.getWidth(), od.getHeight()); - - miniMe = or.draw(od.getRows(av.getAlignment()), - od.getColumns(av.getAlignment())); - - Graphics mg = miniMe.getGraphics(); - - // checks for conservation annotation to make sure overview works for DNA - // too - if (showAnnotation) - { - mg.translate(0, od.getSequencesHeight()); - or.drawGraph(mg, av.getAlignmentConservationAnnotation(), - od.getGraphHeight(), od.getColumns(av.getAlignment())); - mg.translate(0, -od.getSequencesHeight()); - } - - if (restart) - { - restart = false; - draw(showSequenceFeatures, showAnnotation, transferRenderer); - } - else - { - updaterunning = false; - } + or.drawMiniMe(); } @Override @@ -152,13 +141,14 @@ public class OverviewCanvas extends Component @Override public void paint(Graphics g) { - Graphics og = offscreen.getGraphics(); if (miniMe != null) { + Graphics og = offscreen.getGraphics(); og.drawImage(miniMe, 0, 0, this); og.setColor(Color.red); od.drawBox(og); g.drawImage(offscreen, 0, 0, this); + og.dispose(); } } @@ -170,4 +160,25 @@ public class OverviewCanvas extends Component od = null; } + public void finalizeDraw(BufferedImage miniMe) + { + if (restart) + { + restart = false; + draw(showSequenceFeatures, showAnnotation, featureRenderer); + } + else + { + this.miniMe = miniMe; + // checks for conservation annotation to make sure overview works for DNA + // too + if (showAnnotation) + { + or.drawGraph(av.getAlignmentConservationAnnotation()); + } + updaterunning = false; + repaint(); + } + } + } diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 9cbdd36..328841c 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -46,16 +46,17 @@ import java.beans.PropertyChangeEvent; import javax.swing.SwingUtilities; +@SuppressWarnings("serial") public class OverviewPanel extends Panel implements Runnable, MouseMotionListener, MouseListener, ViewportListenerI { - private OverviewDimensions od; + OverviewDimensions od; - private OverviewCanvas oviewCanvas; + OverviewCanvas canvas; private AlignViewport av; - private AlignmentPanel ap; + AlignmentPanel ap; private boolean showHidden = true; @@ -73,9 +74,9 @@ public class OverviewPanel extends Panel implements Runnable, (av.isShowAnnotation() && av.getSequenceConsensusHash() != null)); - oviewCanvas = new OverviewCanvas(od, av); + canvas = new OverviewCanvas(this, od, av); setLayout(new BorderLayout()); - add(oviewCanvas, BorderLayout.CENTER); + add(canvas, BorderLayout.CENTER); setSize(new Dimension(od.getWidth(), od.getHeight())); @@ -116,8 +117,8 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mouseClicked(MouseEvent evt) { - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { showPopupMenu(evt); } @@ -142,8 +143,8 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mousePressed(MouseEvent evt) { - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { if (!Platform.isMac()) // BH was excluding JavaScript { @@ -220,7 +221,7 @@ public class OverviewPanel extends Panel implements Runnable, */ public void updateOverviewImage() { - if (oviewCanvas == null) + if (canvas == null) { /* * panel has been disposed @@ -239,7 +240,7 @@ public class OverviewPanel extends Panel implements Runnable, { if (updateRunning) { - oviewCanvas.restartDraw(); + canvas.restartDraw(); return; } @@ -254,11 +255,11 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void run() { - oviewCanvas.draw(av.isShowSequenceFeatures(), + setBoxPosition(); + canvas.draw(av.isShowSequenceFeatures(), (av.isShowAnnotation() && av.getAlignmentConservationAnnotation() != null), ap.seqPanel.seqCanvas.getFeatureRenderer()); - setBoxPosition(); } /** @@ -321,7 +322,7 @@ public class OverviewPanel extends Panel implements Runnable, (av.isShowAnnotation() && av.getAlignmentConservationAnnotation() != null)); } - oviewCanvas.resetOviewDims(od); + canvas.resetOviewDims(od); updateOverviewImage(); } @@ -339,11 +340,11 @@ public class OverviewPanel extends Panel implements Runnable, } finally { av = null; - if (oviewCanvas != null) + if (canvas != null) { - oviewCanvas.dispose(); + canvas.dispose(); } - oviewCanvas = null; + canvas = null; ap = null; od = null; } diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index d3f4a69..c91449f 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -96,8 +96,8 @@ public class ScalePanel extends Panel min = res; max = res; - if ((evt.getModifiersEx() - & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK) + if ((evt.getModifiers() + & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { rightMouseButtonPressed(evt, res); } diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index f055776..ecb0888 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -492,15 +492,17 @@ public class SeqCanvas extends Panel implements ViewportListenerI { ypos - (avcharHeight / 2), ypos - (avcharHeight / 2), ypos - (avcharHeight / 2) + 8 }, 3); } } - + // BH 2020.03.19 avoiding g.setClip at all costs + g = g.create(); if (g.getClip() == null) { - g.setClip(0, 0, cWidth * avcharWidth, canvasHeight); + g.clipRect(0, 0, cWidth * avcharWidth, canvasHeight); } drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos); - g.setClip(null); + // g.setClip(null); + g.dispose(); if (av.isShowAnnotation()) { g.translate(0, cHeight + ypos + 4); diff --git a/src/jalview/appletgui/TreePanel.java b/src/jalview/appletgui/TreePanel.java index 671fee1..b5e3342 100644 --- a/src/jalview/appletgui/TreePanel.java +++ b/src/jalview/appletgui/TreePanel.java @@ -46,7 +46,7 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; public class TreePanel extends EmbmenuFrame - implements ActionListener, ItemListener, AutoCloseable + implements ActionListener, ItemListener { SequenceI[] seq; @@ -72,11 +72,11 @@ public class TreePanel extends EmbmenuFrame } @Override - public void close() + public void finalize() throws Throwable { ap = null; av = null; - super.close(); + super.finalize(); } /** diff --git a/src/jalview/bin/AlignViewController.java b/src/jalview/bin/AlignViewController.java new file mode 100644 index 0000000..ee46a89 --- /dev/null +++ b/src/jalview/bin/AlignViewController.java @@ -0,0 +1,473 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.controller; + +import jalview.analysis.AlignmentSorter; +import jalview.api.AlignViewControllerGuiI; +import jalview.api.AlignViewControllerI; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; +import jalview.api.FeatureRenderer; +import jalview.commands.OrderCommand; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.SequenceCollectionI; +import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.FeaturesFile; +import jalview.schemes.ColourSchemeI; +import jalview.util.MessageManager; + +import java.awt.Color; +import java.util.BitSet; +import java.util.List; + +public class AlignViewController implements AlignViewControllerI +{ + AlignViewportI viewport = null; + + AlignmentViewPanel alignPanel = null; + + /** + * the GUI container that is handling interactions with the user + */ + private AlignViewControllerGuiI avcg; + + public AlignViewController(AlignViewControllerGuiI alignFrame, + AlignViewportI vp, AlignmentViewPanel ap) + { + this.avcg = alignFrame; + this.viewport = vp; + this.alignPanel = ap; + } + + @Override + public void setViewportAndAlignmentPanel(AlignViewportI vp, + AlignmentViewPanel ap) + { + this.alignPanel = ap; + this.viewport = vp; + } + + @Override + public boolean makeGroupsFromSelection() + { + SequenceGroup sg = viewport.getSelectionGroup(); + ColumnSelection cs = viewport.getColumnSelection(); + SequenceGroup[] gps = null; + if (sg != null && (cs == null || cs.isEmpty())) + { + gps = jalview.analysis.Grouping.makeGroupsFrom( + viewport.getSequenceSelection(), + viewport.getAlignmentView(true) + .getSequenceStrings(viewport.getGapCharacter()), + viewport.getAlignment().getGroups()); + } + else + { + if (cs != null) + { + gps = jalview.analysis.Grouping.makeGroupsFromCols( + (sg == null) ? viewport.getAlignment().getSequencesArray() + : sg.getSequences().toArray(new SequenceI[0]), + cs, viewport.getAlignment().getGroups()); + } + } + if (gps != null) + { + viewport.getAlignment().deleteAllGroups(); + viewport.clearSequenceColours(); + viewport.setSelectionGroup(null); + ColourSchemeI colours = viewport.getGlobalColourScheme(); + // set view properties for each group + for (int g = 0; g < gps.length; g++) + { + // gps[g].setShowunconserved(viewport.getShowUnconserved()); + gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo()); + viewport.getAlignment().addGroup(gps[g]); + if (colours != null) + { + gps[g].setColourScheme(colours.getInstance(viewport, gps[g])); + } + Color col = new Color((int) (Math.random() * 255), + (int) (Math.random() * 255), (int) (Math.random() * 255)); + gps[g].idColour = col; + viewport.setUpdateStructures(true); + viewport.addSequenceGroup(gps[g]); + } + return true; + } + return false; + } + + @Override + public boolean createGroup() + { + + SequenceGroup sg = viewport.getSelectionGroup(); + if (sg != null) + { + viewport.getAlignment().addGroup(sg); + return true; + } + return false; + } + + @Override + public boolean unGroup() + { + SequenceGroup sg = viewport.getSelectionGroup(); + if (sg != null) + { + viewport.getAlignment().deleteGroup(sg); + return true; + } + return false; + } + + @Override + public boolean deleteGroups() + { + if (viewport.getAlignment().getGroups() != null + && viewport.getAlignment().getGroups().size() > 0) + { + viewport.getAlignment().deleteAllGroups(); + viewport.clearSequenceColours(); + viewport.setSelectionGroup(null); + return true; + } + return false; + } + + @Override + public boolean markColumnsContainingFeatures(boolean invert, + boolean extendCurrent, boolean toggle, String featureType) + { + // JBPNote this routine could also mark rows, not just columns. + // need a decent query structure to allow all types of feature searches + BitSet bs = new BitSet(); + boolean searchSelection = viewport.getSelectionGroup() != null + && !extendCurrent; + SequenceCollectionI sqcol = searchSelection ? viewport + .getSelectionGroup() : viewport.getAlignment(); + + int nseq = findColumnsWithFeature(featureType, sqcol, bs); + + ColumnSelection cs = viewport.getColumnSelection(); + if (cs == null) + { + cs = new ColumnSelection(); + } + + if (bs.cardinality() > 0 || invert) + { + boolean changed = cs.markColumns(bs, sqcol.getStartRes(), + sqcol.getEndRes(), invert, extendCurrent, toggle); + if (changed) + { + viewport.setColumnSelection(cs); + alignPanel.paintAlignment(false, false); + int columnCount = invert + ? (sqcol.getEndRes() - sqcol.getStartRes() + 1) + - bs.cardinality() + : bs.cardinality(); + avcg.setStatus(MessageManager.formatMessage( + "label.view_controller_toggled_marked", new String[] + { toggle ? MessageManager.getString("label.toggled") + : MessageManager.getString("label.marked"), + String.valueOf(columnCount), + invert ? MessageManager + .getString("label.not_containing") + : MessageManager.getString("label.containing"), + featureType, Integer.valueOf(nseq).toString() })); + return true; + } + } + else + { + String key = searchSelection ? "label.no_feature_found_selection" + : "label.no_feature_of_type_found"; + avcg.setStatus(MessageManager.formatMessage(key, + new String[] { featureType })); + if (!extendCurrent) + { + cs.clear(); + alignPanel.paintAlignment(false, false); + } + } + return false; + } + + /** + * Sets a bit in the BitSet for each column (base 0) in the sequence + * collection which includes a visible feature of the specified feature type. + * Returns the number of sequences which have the feature visible in the + * selected range. + * + * @param featureType + * @param sqcol + * @param bs + * @return + */ + int findColumnsWithFeature(String featureType, + SequenceCollectionI sqcol, BitSet bs) + { + FeatureRenderer fr = alignPanel == null ? null : alignPanel + .getFeatureRenderer(); + + final int startColumn = sqcol.getStartRes() + 1; // converted to base 1 + final int endColumn = sqcol.getEndRes() + 1; + List seqs = sqcol.getSequences(); + int nseq = 0; + for (SequenceI sq : seqs) + { + if (sq != null) + { + // int ist = sq.findPosition(sqcol.getStartRes()); + List sfs = sq.findFeatures(startColumn, + endColumn, featureType); + + boolean found = false; + for (SequenceFeature sf : sfs) + { + if (fr.getColour(sf) == null) + { + continue; + } + if (!found) + { + nseq++; + } + found = true; + + int sfStartCol = sq.findIndex(sf.getBegin()); + int sfEndCol = sq.findIndex(sf.getEnd()); + + if (sf.isContactFeature()) + { + /* + * 'contact' feature - check for 'start' or 'end' + * position within the selected region + */ + if (sfStartCol >= startColumn && sfStartCol <= endColumn) + { + bs.set(sfStartCol - 1); + } + if (sfEndCol >= startColumn && sfEndCol <= endColumn) + { + bs.set(sfEndCol - 1); + } + continue; + } + + /* + * contiguous feature - select feature positions (if any) + * within the selected region + */ + if (sfStartCol < startColumn) + { + sfStartCol = startColumn; + } + // not sure what the point of this is + // if (sfStartCol < ist) + // { + // sfStartCol = ist; + // } + if (sfEndCol > endColumn) + { + sfEndCol = endColumn; + } + for (; sfStartCol <= sfEndCol; sfStartCol++) + { + bs.set(sfStartCol - 1); // convert to base 0 + } + } + } + } + return nseq; + } + + @Override + public void sortAlignmentByFeatureDensity(List typ) + { + String methodText = MessageManager.getString("label.sort_by_density"); + sortByFeatures(typ, methodText, AlignmentSorter.FEATURE_DENSITY); + } + + /** + * Sorts the alignment (or current selection) by either average score or density + * of the specified feature types, and adds to the command history. If + * {@code types} is null, all visible feature types are used for the sort. If no + * feature types apply, does nothing. + * + * @param types + * @param methodText + * - text shown in Undo/Redo command + * @param method + * - passed to + * jalview.analysis.AlignmentSorter.sortByFeatures() + */ + protected void sortByFeatures(List types, String methodText, + final String method) + { + FeatureRenderer fr = alignPanel.getFeatureRenderer(); + if (types == null && fr != null) + { + types = fr.getDisplayedFeatureTypes(); + } + if (types.isEmpty()) + { + return; // nothing to do + } + List gps = null; + if (fr != null) + { + gps = fr.getDisplayedFeatureGroups(); + } + AlignmentI al = viewport.getAlignment(); + + int start, stop; + SequenceGroup sg = viewport.getSelectionGroup(); + if (sg != null) + { + start = sg.getStartRes(); + stop = sg.getEndRes(); + } + else + { + start = 0; + stop = al.getWidth(); + } + SequenceI[] oldOrder = al.getSequencesArray(); + AlignmentSorter.sortByFeature(types, gps, start, stop, al, method); + avcg.addHistoryItem(new OrderCommand(methodText, oldOrder, + viewport.getAlignment())); + alignPanel.paintAlignment(true, false); + + } + + @Override + public void sortAlignmentByFeatureScore(List typ) + { + String methodText = MessageManager.getString("label.sort_by_score"); + sortByFeatures(typ, methodText, AlignmentSorter.FEATURE_SCORE); + } + + @Override + public boolean parseFeaturesFile(Object file, DataSourceType protocol, + boolean relaxedIdMatching) + { + boolean featuresAdded = false; + FeatureRenderer fr = alignPanel.getFeatureRenderer(); + try + { + featuresAdded = new FeaturesFile(false, file, protocol).parse( + viewport.getAlignment().getDataset(), fr.getFeatureColours(), + fr.getFeatureFilters(), false, relaxedIdMatching); + } catch (Exception ex) + { + ex.printStackTrace(); + } + + if (featuresAdded) + { + avcg.refreshFeatureUI(true); + if (fr != null) + { + // update the min/max ranges where necessary + fr.findAllFeatures(true); + } + if (avcg.getFeatureSettingsUI() != null) + { + avcg.getFeatureSettingsUI().discoverAllFeatureData(); + } + alignPanel.paintAlignment(true, true); + } + + return featuresAdded; + + } + + @Override + public boolean markHighlightedColumns(boolean invert, + boolean extendCurrent, boolean toggle) + { + if (!viewport.hasSearchResults()) + { + // do nothing if no selection exists + return false; + } + // JBPNote this routine could also mark rows, not just columns. + BitSet bs = new BitSet(); + SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null + || extendCurrent) ? viewport.getAlignment() + : viewport.getSelectionGroup(); + + // this could be a lambda... - the remains of the method is boilerplate, + // except for the different messages for reporting selection. + int nseq = viewport.getSearchResults().markColumns(sqcol, bs); + + ColumnSelection cs = viewport.getColumnSelection(); + if (cs == null) + { + cs = new ColumnSelection(); + } + + if (bs.cardinality() > 0 || invert) + { + boolean changed = cs.markColumns(bs, sqcol.getStartRes(), + sqcol.getEndRes(), invert, extendCurrent, toggle); + if (changed) + { + viewport.setColumnSelection(cs); + alignPanel.paintAlignment(false, false); + int columnCount = invert + ? (sqcol.getEndRes() - sqcol.getStartRes() + 1) + - bs.cardinality() + : bs.cardinality(); + avcg.setStatus(MessageManager.formatMessage( + "label.view_controller_toggled_marked", new String[] + { toggle ? MessageManager.getString("label.toggled") + : MessageManager.getString("label.marked"), + String.valueOf(columnCount), + invert ? MessageManager + .getString("label.not_containing") + : MessageManager.getString("label.containing"), + "Highlight", Integer.valueOf(nseq).toString() })); + return true; + } + } + else + { + avcg.setStatus(MessageManager + .formatMessage("No highlighted regions marked")); + if (!extendCurrent) + { + cs.clear(); + alignPanel.paintAlignment(false, false); + } + } + return false; + } + +} diff --git a/src/jalview/bin/AppletParams.java b/src/jalview/bin/AppletParams.java new file mode 100644 index 0000000..6a23c39 --- /dev/null +++ b/src/jalview/bin/AppletParams.java @@ -0,0 +1,447 @@ +package jalview.bin; + +import jalview.gui.Preferences; + +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +/** + * Collection of all known applet tags from JalviewLite + * + * @author hansonr + * + */ +@SuppressWarnings("serial") +public class AppletParams extends HashMap +{ + + private final static String[] params = { "alignpdbfiles", + Preferences.ANNOTATIONCOLOUR_MAX, Preferences.ANNOTATIONCOLOUR_MIN, + "annotations", + "APPLICATION_URL", "automaticScrolling", "centrecolumnlabels", + "debug", "defaultColour", "defaultColourNuc", "defaultColourProt", + "embedded", "enableSplitFrame", "externalstructureviewer", "features", + "file", "file2", "format", "heightScale", "hidefeaturegroups", + "jalviewhelpurl", "jnetfile", "jpredfile", "label", "linkLabel_", + "linkLabel_1", "linkURL_", "nojmol", "normaliseLogo", + "normaliseSequenceLogo", "oninit", "PDBFILE", "PDBSEQ", + "relaxedidmatch", "resolvetocodebase", "RGB", "scaleProteinAsCdna", + "scoreFile", "separator", "sequence", "showAnnotation", "showbutton", + "showConsensus", "showConsensusHistogram", "showConservation", + "showfeaturegroups", "showFeatureSettings", "showFullId", + "showGroupConsensus", "showGroupConservation", "showOccupancy", + "showQuality", "showSequenceLogo", "showTreeBootstraps", + "showTreeDistances", "showUnconserved", "showUnlinkedTreeNodes", + "sortBy", "sortByTree", "tree", "treeFile", "upperCase", + "userDefinedColour", "widthScale", "windowHeight", "windowWidth", + "wrap", }; + + public AppletParams(Map info) + { + for (int i = params.length; --i >= 0;) + { + put(params[i], info.get(params[i])); + } + } + + public String getParam(String param, String def) + { + String val = get(param); + return (val != null ? val : def); + } + + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + public AppletParams(String outerHTML) + { + String[] tokens = outerHTML.split(" 0;) + { + String param = tokens[i]; + String key = getAttr(param, "name"); + if (key != null) + { + String value = getAttr(param, "value"); + System.out.println("AppletParams " + key + " = \"" + value + "\""); + put(key, value); + } + } + put("_width", getAttr(outerHTML, "width")); + put("_height", getAttr(outerHTML, "height")); + put("_id", getAttr(outerHTML, "id")); + put("_name", getAttr(outerHTML, "name")); + put("_archive", getAttr(outerHTML, "archive")); + put("_code", code); + } + + public AppletParams() + { + // TODO Auto-generated constructor stub + } + + public static AppletParams getAppletParams(String[] args, + Vector vargs) + { + AppletParams appletParams = new AppletParams(); + String resourcePath = null; + for (int i = args.length; --i > 0;) // > 0 is correct, not >=0 + { + if (args[i].startsWith("name=\"Info.resourcePath\"")) + { + resourcePath = getAttr(args[i], "value"); + if (resourcePath.length() > 0 && !resourcePath.endsWith("/")) + { + resourcePath += "/"; + } + break; + } + } + for (int i = 1; i < args.length; i++) + { + String arg = args[i].trim(); + if (arg.startsWith("name=")) + { + String prefName = getAttr(arg, "name"); + String appletName = prefName.toLowerCase(); + String argName = prefName; + String value = getAttr(arg, "value"); + + // note that Application arguments ARE case-sensitive, but + // Applet.getParameter() is not. + + switch (appletName) + { + + case "file": + argName = "open"; + appletName = null; + value = resourcePath + value; + break; + case "file2": + argName = "open2"; + prefName = null; + value = resourcePath + value; + break; + case "features": + case "jnetfile": + case "jpredfile": + case "pdbfile": + case "scorefile": + case "sequence": + // setting argName to null indicates that we want + // JalviewAppLoader to take care of this. + prefName = argName = null; + value = resourcePath + value; + break; + case "tree": + case "treefile": + // setting appletName to null indicates that we want + // Jalview.doMain to taken care of this as Jalview args + argName = "tree"; + appletName = null; + value = resourcePath + value; + break; + + // non-loading preferences + + case "defaultcolour": + prefName = Preferences.DEFAULT_COLOUR; + break; + case "defaultcolournuc": + prefName = Preferences.DEFAULT_COLOUR_NUC; + break; + case "defaultcolourprot": + prefName = Preferences.DEFAULT_COLOUR_PROT; + break; + case "annotationcolour_max": + prefName = Preferences.ANNOTATIONCOLOUR_MAX; + break; + case "annotationcolour_min": + prefName = Preferences.ANNOTATIONCOLOUR_MIN; + break; + case "enablesplitframe": + prefName = Preferences.ENABLE_SPLIT_FRAME; + break; + case "centrecolumnlabels": + prefName = Preferences.CENTRE_COLUMN_LABELS; + break; + case "sortby": + prefName = Preferences.SORT_ALIGNMENT; // id, etc. + break; + case "normalisesequencelogo": + prefName = Preferences.NORMALISE_CONSENSUS_LOGO; + break; + case "relaxedidmatch": + prefName = Preferences.RELAXEDSEQIDMATCHING; + break; + case "scaleproteinascdna": + prefName = Preferences.SCALE_PROTEIN_TO_CDNA; + break; + case "userdefinedcolour": + argName = "colour"; + prefName = Preferences.USER_DEFINED_COLOURS; + break; + case "wrap": + prefName = Preferences.WRAP_ALIGNMENT; + break; + + // implemented; not tested: + + case "oninit": + prefName = null; + break; + case "annotations": + value = resourcePath + value; + argName = null; + break; + case "hidefeaturegroups": + // TODO + break; + case "pdbseq": + argName = prefName = null; + break; + case "sortbytree": + prefName = Preferences.SORT_BY_TREE; + value = checkTF(value); + appletName = null; // taken care of by Jalview + break; + case "format": + break; + case "alignpdbfiles": + argName = prefName = null; + break; + case "separator": + break; + + // TODO: probably not relevant? + + case "rgb": + prefName = null; // TODO no background for application? + break; + case "externalstructureviewer": + break; + case "application_url": + break; + case "automaticscrolling": + break; + case "heightscale": + break; + case "jalviewhelpurl": + break; + case "label": + break; + case "linklabel_": + prefName = "linkLabel_"; + break; + case "linklabel_1": + prefName = "linkLabel_1"; + break; + case "linkurl_": + prefName = "linkURL_"; + break; + + // unknown: + + case "nojmol": + case "normaliselogo": + case "resolvetocodebase": + case "uppercase": + case "widthscale": + case "windowheight": + case "windowwidth": + argName = prefName = null; + break; + + // TRUE/FALSE + + case "debug": + value = checkTF(value); + break; + case "embedded": + value = checkTF(value); + break; + case "showbutton": + value = checkTF(value); + break; + case "showannotation": + prefName = Preferences.SHOW_ANNOTATIONS; + value = checkTF(value); + break; + case "showconsensus": + prefName = Preferences.SHOW_CONSENSUS_LOGO; + value = checkTF(value); + break; + case "showconsensushistogram": + prefName = Preferences.SHOW_CONSENSUS_HISTOGRAM; + value = checkTF(value); + break; + case "showconservation": + prefName = Preferences.SHOW_CONSERVATION; + value = checkTF(value); + break; + case "showgroupconsensus": + prefName = Preferences.SHOW_GROUP_CONSENSUS; + value = checkTF(value); + break; + case "showgroupconservation": + prefName = Preferences.SHOW_GROUP_CONSERVATION; + value = checkTF(value); + break; + case "showoccupancy": + prefName = Preferences.SHOW_OCCUPANCY; + value = checkTF(value); + break; + case "showquality": + prefName = Preferences.SHOW_QUALITY; + value = checkTF(value); + break; + case "showsequencelogo": + prefName = Preferences.SHOW_CONSENSUS_LOGO; + value = checkTF(value); + break; + case "showfeaturegroups": + value = checkTF(value); + break; + case "showfeaturesettings": + value = checkTF(value); + break; + case "showfullid": + value = checkTF(value); + break; + case "showtreebootstraps": + value = checkTF(value); + break; + case "showtreedistances": + value = checkTF(value); + break; + case "showunconserved": + prefName = Preferences.SHOW_UNCONSERVED; + value = checkTF(value); + break; + case "showunlinkedtreenodes": + value = checkTF(value); + break; + default: + if (appletName.startsWith("pdbfile") + || appletName.startsWith("sequence") && Character.isDigit( + appletName.charAt(appletName.length() - 1))) + { + // could be pdbFile2, for example + prefName = argName = null; + value = resourcePath + value; + break; + } + // or one of the app preference names + break; + } + // put name and value into application args + if (value != null && argName != null) + { + vargs.add(argName); + if (value != "true") + { + vargs.add(value); + } + } + if (value == null) + { + value = "false"; + } + System.out.println("AppletParams propName=" + prefName + " argName=" + + argName + " appletName=" + + appletName + " value=" + value); + if (appletName != null) + { + appletParams.put(appletName, value); + } + if (prefName != null) + { + Cache.setPropertyNoSave(prefName, value); + } + } + } + return appletParams; + } + + /** + * Check for a single-argument option. + * + * @param value + * @return "true" or null + */ + private static String checkTF(String value) + { + return (value.toLowerCase() == "true" ? "true" : null); + } + + /** + * Crude applet innerHTML parser + * + * @param tag + * @param attr + * @return + */ + private static String getAttr(String tag, String attr) + { + int pt = tag.indexOf(attr + "=\""); + if (pt < 0) + { + System.out + .println("AppletParams did not read " + attr + " in " + tag); + return null; + } + // + int pt1 = pt + attr.length() + 2; + int pt2 = tag.indexOf("\"", pt1); + return (pt < 0 ? null : tag.substring(pt1, pt2)); + } + + public static void main(String[] args) + { + new AppletParams(" \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " "); + } + +} \ No newline at end of file diff --git a/src/jalview/bin/ArgsParser.java b/src/jalview/bin/ArgsParser.java index c927f1f..91c8838 100644 --- a/src/jalview/bin/ArgsParser.java +++ b/src/jalview/bin/ArgsParser.java @@ -34,19 +34,98 @@ import java.util.Vector; */ public class ArgsParser { - Vector vargs = null; + + // BH 2019 - new + + public static final String NOCALCULATION = "nocalculation"; + + public static final String NOMENUBAR = "nomenubar"; + + public static final String NOSTATUS = "nostatus"; + + public static final String SHOWOVERVIEW = "showoverview"; + + // + public static final String ANNOTATIONS = "annotations"; + + public static final String COLOUR = "colour"; + + public static final String FEATURES = "features"; + + public static final String GROOVY = "groovy"; + + public static final String GROUPS = "groups"; + + public static final String HEADLESS = "headless"; + + public static final String JABAWS = "jabaws"; + + public static final String NOANNOTATION = "no-annotation"; + + public static final String NOANNOTATION2 = "noannotation"; // BH 2019.05.07 + + public static final String NODISPLAY = "nodisplay"; + + public static final String NOGUI = "nogui"; + + public static final String NONEWS = "nonews"; + + public static final String NOQUESTIONNAIRE = "noquestionnaire"; + + public static final String NOSORTBYTREE = "nosortbytree"; + + public static final String NOUSAGESTATS = "nousagestats"; + + public static final String OPEN = "open"; + + public static final String OPEN2 = "open2"; // BH added -- for applet + // compatibility; not fully + // implemented + + public static final String PROPS = "props"; + + public static final String QUESTIONNAIRE = "questionnaire"; + + public static final String SETPROP = "setprop"; + + public static final String SORTBYTREE = "sortbytree"; + + public static final String TREE = "tree"; + + public static final String VDOC = "vdoc"; + + public static final String VSESS = "vsess"; + + private Vector vargs = null; + + private boolean isApplet; + + private AppletParams appletParams; + + public boolean isApplet() + { + return isApplet; + } public ArgsParser(String[] args) { - vargs = new Vector(); - for (int i = 0; i < args.length; i++) + vargs = new Vector<>(); + isApplet = (args.length > 0 && args[0].startsWith(". + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.gui; + +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.StructureFile; +import jalview.util.MessageManager; + +/** + * GUI related routines for associating PDB files with sequences. A single + * static method. + * + * @author JimP + * + */ +public class AssociatePdbFileWithSeq +{ + + private AssociatePdbFileWithSeq() + { + // inaccessible + } + + /** + * Associate the given PDB file name or URL with a sequence. Do not map + * mouse-over events. + * + * @param fileName + * or URL + * @param type + * will be DataType.FILE or DataType.URL + * @param sequence + * to associate + * @param prompt + * true if the user should be asked what to do if the specified file + * does not seem to contain PDB information (StructureChooser only) + * @return null if file is not found + */ + public static PDBEntry associatePdbWithSeq(String fileName, + DataSourceType type, SequenceI sequence, boolean prompt) + { + PDBEntry entry = new PDBEntry(); + StructureFile pdbfile = null; + pdbfile = Desktop.getStructureSelectionManager() + .setMapping(false, new SequenceI[] + { sequence }, null, fileName, type); + if (pdbfile == null) + { + // stacktrace already thrown so just return + return null; + } + String id = pdbfile.getId(); + if (id == null && (id = (prompt + ? JvOptionPane.showInternalInputDialog(Desktop.getDesktopPane(), + MessageManager + .getString("label.couldnt_find_pdb_id_in_file"), + MessageManager.getString("label.no_pdb_id_in_file"), + JvOptionPane.QUESTION_MESSAGE) + : null)) == null) + { + return null; + } + entry.setId(id); + entry.setType(PDBEntry.Type.FILE); + entry.setFile(fileName); + sequence.getDatasetSequence().addPDBId(entry); + Desktop.getInstance().getStructureSelectionManager() + .registerPDBEntry(entry); + return entry; + } +} diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index cdd8cc1..0ec9ee0 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -20,27 +20,50 @@ */ package jalview.bin; +import jalview.api.AlignCalcWorkerI; +import jalview.api.AlignFrameI; +import jalview.api.AlignViewportI; +import jalview.api.JalviewApp; +import jalview.api.StructureSelectionManagerProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; import jalview.ext.so.SequenceOntology; import jalview.gui.AlignFrame; +import jalview.gui.AlignViewport; +import jalview.gui.AlignmentPanel; +import jalview.gui.CalculationChooser; import jalview.gui.Desktop; +import jalview.gui.Preferences; import jalview.gui.PromptUserConfig; +import jalview.gui.StructureViewer; import jalview.io.AppletFormatAdapter; import jalview.io.BioJsHTMLOutput; import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.FileFormatException; import jalview.io.FileFormatI; +import jalview.io.FileFormats; import jalview.io.FileLoader; import jalview.io.HtmlSvgOutput; import jalview.io.IdentifyFile; import jalview.io.NewickFile; import jalview.io.gff.SequenceOntologyFactory; +import jalview.javascript.JSFunctionExec; +import jalview.javascript.MouseOverStructureListener; +import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.schemes.ColourSchemeI; import jalview.schemes.ColourSchemeProperty; +import jalview.structure.SelectionSource; +import jalview.structure.VamsasSource; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.jws2.Jws2Discoverer; +import java.applet.AppletContext; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; @@ -58,19 +81,17 @@ import java.security.PermissionCollection; import java.security.Permissions; import java.security.Policy; import java.util.HashMap; +import java.util.Hashtable; import java.util.Map; import java.util.Vector; -import java.util.logging.ConsoleHandler; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; import javax.swing.UIManager; -import com.threerings.getdown.util.LaunchUtil; - import groovy.lang.Binding; import groovy.util.GroovyScriptEngine; +import netscape.javascript.JSObject; /** * Main class for Jalview Application
@@ -87,20 +108,78 @@ import groovy.util.GroovyScriptEngine; * @author $author$ * @version $Revision$ */ -public class Jalview +public class Jalview implements ApplicationSingletonI, JalviewJSApi { + + public static Jalview getInstance() + { + return (Jalview) ApplicationSingletonProvider + .getInstance(Jalview.class); + } + + private Jalview() + { + } + static { Platform.getURLCommandArguments(); } - // singleton instance of this class + private boolean headless; - private static Jalview instance; + public static boolean isHeadlessMode() + { + return getInstance().headless; + } private Desktop desktop; - public static AlignFrame currentAlignFrame; + private AlignFrame currentAlignFrame; + + public boolean isJavaAppletTag; + + public String appletResourcePath; + + JalviewAppLoader appLoader; + + protected JSFunctionExec jsFunctionExec; + + private boolean noCalculation, noMenuBar, noStatus; + + private boolean noAnnotation; + + public static final String TERMINATOR_LINE = "Jalview argument parsing complete."; + + public boolean getStartCalculations() + { + return !noCalculation; + } + + public boolean getAllowMenuBar() + { + return !noMenuBar; + } + + public boolean getShowStatus() + { + return !noStatus; + } + + public boolean getShowAnnotation() + { + return !noAnnotation; + } + + public static AlignFrame getCurrentAlignFrame() + { + return getInstance().currentAlignFrame; + } + + public static void setCurrentAlignFrame(AlignFrame currentAlignFrame) + { + getInstance().currentAlignFrame = currentAlignFrame; + } static { @@ -112,21 +191,21 @@ public class Jalview */ { // grab all the rights we can for the JVM - Policy.setPolicy(new Policy() - { - @Override - public PermissionCollection getPermissions(CodeSource codesource) - { - Permissions perms = new Permissions(); - perms.add(new AllPermission()); - return (perms); - } - - @Override - public void refresh() - { - } - }); + Policy.setPolicy(new Policy() + { + @Override + public PermissionCollection getPermissions(CodeSource codesource) + { + Permissions perms = new Permissions(); + perms.add(new AllPermission()); + return (perms); + } + + @Override + public void refresh() + { + } + }); } } @@ -139,8 +218,8 @@ public class Jalview class FeatureFetcher { /* - * TODO: generalise to track all jalview events to orchestrate batch processing - * events. + * TODO: generalise to track all jalview events to orchestrate batch + * processing events. */ private int queued = 0; @@ -189,138 +268,96 @@ public class Jalview } - public static Jalview getInstance() - { - return instance; - } - /** * main class for Jalview application * * @param args - * open filename + * open filename */ public static void main(String[] args) { -// setLogging(); // BH - for event debugging in JavaScript - instance = new Jalview(); - instance.doMain(args); -} - - private static void logClass(String name) - { - // BH - for event debugging in JavaScript - ConsoleHandler consoleHandler = new ConsoleHandler(); - consoleHandler.setLevel(Level.ALL); - Logger logger = Logger.getLogger(name); - logger.setLevel(Level.ALL); - logger.addHandler(consoleHandler); - } - - @SuppressWarnings("unused") - private static void setLogging() - { - - /** - * @j2sIgnore - * - */ - { - System.out.println("not in js"); - } - - // BH - for event debugging in JavaScript (Java mode only) - if (!Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - */ - { - Logger.getLogger("").setLevel(Level.ALL); - logClass("java.awt.EventDispatchThread"); - logClass("java.awt.EventQueue"); - logClass("java.awt.Component"); - logClass("java.awt.focus.Component"); - logClass("java.awt.focus.DefaultKeyboardFocusManager"); - } - + // Platform.startJavaLogging(); + getInstance().doMain(args); } - - + @SuppressWarnings("unused") /** * @param args */ void doMain(String[] args) { - if (!Platform.isJS()) + boolean isJS = Platform.isJS(); + if (isJS) + { + Platform.setAppClass(this); + } + else { System.setSecurityManager(null); } System.out - .println("Java version: " - + System.getProperty("java.version")); - System.out.println("Java Home: " + System.getProperty("java.home")); + .println("Java version: " + System.getProperty("java.version")); System.out.println(System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version")); - String val = System.getProperty("sys.install4jVersion"); - if (val != null) { - System.out.println("Install4j version: " + val); - } - val = System.getProperty("installer_template_version"); - if (val != null) { - System.out.println("Install4j template version: " + val); - } - val = System.getProperty("launcher_version"); - if (val != null) { - System.out.println("Launcher version: " + val); - } - - // report Jalview version - Cache.loadBuildProperties(true); ArgsParser aparser = new ArgsParser(args); - boolean headless = false; - String usrPropsFile = aparser.getValue("props"); - Cache.loadProperties(usrPropsFile); // must do this before - if (usrPropsFile != null) + String usrPropsFile = aparser.getValue(ArgsParser.PROPS); + Cache.loadProperties(usrPropsFile); + + if (aparser.contains(ArgsParser.NODISPLAY) + || aparser.contains(ArgsParser.NOGUI) + || aparser.contains(ArgsParser.HEADLESS) + || "true".equals(System.getProperty("java.awt.headless"))) { - System.out.println( - "CMD [-props " + usrPropsFile + "] executed successfully!"); + headless = true; + setSynchronous(true); } - if (!Platform.isJS()) + if (isJS) + { + isJavaAppletTag = aparser.isApplet(); + if (isJavaAppletTag) + { + Preferences.setAppletDefaults(); + Cache.loadProperties(usrPropsFile); // again, because we + // might be changing defaults here? + } + System.out.println( + " found: " + aparser.getValue("Info.j2sAppletID")); + appletResourcePath = aparser.getValue("Info.resourcePath"); + } + else /** * Java only * * @j2sIgnore */ { + if (usrPropsFile != null) + { + System.out.println( + "CMD [-props " + usrPropsFile + "] executed successfully!"); + } + if (aparser.contains("help") || aparser.contains("h")) { showUsage(); System.exit(0); } - if (aparser.contains("nodisplay") || aparser.contains("nogui") - || aparser.contains("headless")) - { - System.setProperty("java.awt.headless", "true"); - headless = true; - } + // anything else! - final String jabawsUrl = aparser.getValue("jabaws"); + final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS); if (jabawsUrl != null) { try { - Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl); + Jws2Discoverer.getInstance().setPreferredUrl(jabawsUrl); System.out.println( "CMD [-jabaws " + jabawsUrl + "] executed successfully!"); } catch (MalformedURLException e) @@ -331,7 +368,8 @@ public class Jalview } } - String defs = aparser.getValue("setprop"); + // check for property setting + String defs = aparser.getValue(ArgsParser.SETPROP); while (defs != null) { int p = defs.indexOf('='); @@ -342,17 +380,12 @@ public class Jalview else { System.out.println("Executing setprop argument: " + defs); - if (Platform.isJS()) + if (isJS) { - Cache.setProperty(defs.substring(0,p), defs.substring(p+1)); + Cache.setProperty(defs.substring(0, p), defs.substring(p + 1)); } } - defs = aparser.getValue("setprop"); - } - if (System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true")) - { - headless = true; + defs = aparser.getValue(ArgsParser.SETPROP); } System.setProperty("http.agent", "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown")); @@ -371,7 +404,13 @@ public class Jalview try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + if (!isJS && Platform.isWin()) + { + UIManager.setLookAndFeel( + headless ? "javax.swing.plaf.metal.MetalLookAndFeel" + : UIManager.getSystemLookAndFeelClassName()); + // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } } catch (Exception ex) { System.err.println("Unexpected Look and Feel Exception"); @@ -416,31 +455,35 @@ public class Jalview } /* - * configure 'full' SO model if preferences say to, else use the default (full SO) - * - as JS currently doesn't have OBO parsing, it must use 'Lite' version + * configure 'full' SO model if preferences say to, + * else use the default (SO Lite) */ - boolean soDefault = !Platform.isJS(); - if (Cache.getDefault("USE_FULL_SO", soDefault)) + if (Cache.getDefault(Preferences.USE_FULL_SO, false)) { - SequenceOntologyFactory.setInstance(new SequenceOntology()); + SequenceOntologyFactory.setSequenceOntology(new SequenceOntology()); } - if (!headless) + if (headless) { - desktop = new Desktop(); - desktop.setInBatchMode(true); // indicate we are starting up + // If this is not tested, then - try + if (aparser.contains(ArgsParser.NOUSAGESTATS)) { - JalviewTaskbar.setTaskbar(this); - } catch (Throwable t) + System.err.println("CMD [-nousagestats] executed successfully!"); + } + if (aparser.contains(ArgsParser.NOQUESTIONNAIRE)) { - System.out.println("Error setting Taskbar: " + t.getMessage()); + System.err.println("CMD [-noquestionnaire] executed successfully!"); } + } + else + { + desktop = Desktop.getInstance(); + desktop.setInBatchMode(true); // indicate we are starting up desktop.setVisible(true); - if (!Platform.isJS()) + if (!isJS) /** * Java only * @@ -448,7 +491,7 @@ public class Jalview */ { desktop.startServiceDiscovery(); - if (!aparser.contains("nousagestats")) + if (!aparser.contains(ArgsParser.NOUSAGESTATS)) { startUsageStats(desktop); } @@ -457,9 +500,9 @@ public class Jalview System.err.println("CMD [-nousagestats] executed successfully!"); } - if (!aparser.contains("noquestionnaire")) + if (!aparser.contains(ArgsParser.NOQUESTIONNAIRE)) { - String url = aparser.getValue("questionnaire"); + String url = aparser.getValue(ArgsParser.QUESTIONNAIRE); if (url != null) { // Start the desktop questionnaire prompter with the specified @@ -471,7 +514,7 @@ public class Jalview } else { - if (Cache.getProperty("NOQUESTIONNAIRES") == null) + if (Cache.getProperty(Preferences.NOQUESTIONNAIRES) == null) { // Start the desktop questionnaire prompter with the specified // questionnaire @@ -491,7 +534,7 @@ public class Jalview .println("CMD [-noquestionnaire] executed successfully!"); } - if (!aparser.contains("nonews")) + if (!aparser.contains(ArgsParser.NONEWS)) { desktop.checkForNews(); } @@ -500,45 +543,85 @@ public class Jalview } } - // Move any new getdown-launcher-new.jar into place over old - // getdown-launcher.jar - String appdirString = System.getProperty("getdownappdir"); - if (appdirString != null && appdirString.length() > 0) + parseArguments(aparser, true); + System.err.println(TERMINATOR_LINE); + } + + /** + * Allow an outside entity to initiate the second half of argument parsing + * (only). + * + * @param args + * @return null is good + */ + @Override + public Object parseArguments(String[] args) + { + + try { - final File appdir = new File(appdirString); - new Thread() - { - @Override - public void run() - { - LaunchUtil.upgradeGetdown( - new File(appdir, "getdown-launcher-old.jar"), - new File(appdir, "getdown-launcher.jar"), - new File(appdir, "getdown-launcher-new.jar")); - } - }.start(); + ArgsParser aparser = new ArgsParser(args); + return parseArguments(aparser, false); + } catch (Throwable t) + { + return t; } + } - String file = null, data = null; - FileFormatI format = null; - DataSourceType protocol = null; - FileLoader fileLoader = new FileLoader(!headless); + /** + * + * @param aparser + * @param isStartup + * @return + */ + private Object parseArguments(ArgsParser aparser, boolean isStartup) + { + boolean isJS = Platform.isJS(); - String groovyscript = null; // script to execute after all loading is + Desktop desktop = (headless ? null : Desktop.getInstance()); + // script to execute after all loading is // completed one way or another // extract groovy argument and execute if necessary - groovyscript = aparser.getValue("groovy", true); - file = aparser.getValue("open", true); + String groovyscript = (isJS ? null + : aparser.getValue(ArgsParser.GROOVY, true)); + String file = aparser.getValue(ArgsParser.OPEN, true); + // BH this here to allow split frame; not working as of 5/17/2019 + String file2 = aparser.getValue(ArgsParser.OPEN2, true); + String fileFormat = (isJavaAppletTag + ? aparser.getAppletValue("format", null) + : null); + FileFormatI format = null; + DataSourceType protocol = null; if (file == null && desktop == null) { System.out.println("No files to open!"); System.exit(1); } - long progress = -1; + boolean haveImport = false;// checkStartVamas(aparser); // Finally, deal with the remaining input data. + long progress = -1; + if (file == null && isJavaAppletTag) + { + // Maybe the sequences are added as parameters + StringBuffer data = new StringBuffer("PASTE"); + int i = 1; + while ((file = aparser.getAppletValue("sequence" + i, null)) != null) + { + data.append(file.toString() + "\n"); + i++; + } + if (data.length() > 5) + { + file = data.toString(); + } + } + + String data; + if (file != null) { + if (!headless) { desktop.setProgressBar( @@ -546,14 +629,14 @@ public class Jalview .getString("status.processing_commandline_args"), progress = System.currentTimeMillis()); } - System.out.println("CMD [-open " + file + "] executed successfully!"); - if (!Platform.isJS()) - /** - * ignore in JavaScript -- can't just file existence - could load it? - * - * @j2sIgnore - */ + if (!isJS) + /** + * ignore in JavaScript -- can't just check file existence - could load + * it? + * + * @j2sIgnore + */ { if (!file.startsWith("http://") && !file.startsWith("https://")) // BH 2019 added https check for Java @@ -569,26 +652,88 @@ public class Jalview } } - protocol = AppletFormatAdapter.checkProtocol(file); + protocol = AppletFormatAdapter.checkProtocol(file); try { - format = new IdentifyFile().identify(file, protocol); + format = (isJavaAppletTag && fileFormat != null + ? FileFormats.getInstance().forName(fileFormat) + : null); + if (format == null) + { + format = new IdentifyFile().identify(file, protocol); + } } catch (FileFormatException e1) { // TODO ? } - AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol, - format); + if (aparser.contains(ArgsParser.NOMENUBAR)) + { + noMenuBar = true; + System.out.println("CMD [nomenu] executed successfully!"); + } + + if (aparser.contains(ArgsParser.NOSTATUS)) + { + noStatus = true; + System.out.println("CMD [nostatus] executed successfully!"); + } + + if (aparser.contains(ArgsParser.NOANNOTATION) + || aparser.contains(ArgsParser.NOANNOTATION2)) + { + noAnnotation = true; + System.out.println("CMD no-annotation executed successfully!"); + } + if (aparser.contains(ArgsParser.NOCALCULATION)) + { + noCalculation = true; + System.out.println("CMD [nocalculation] executed successfully!"); + } + + AlignFrame af = new FileLoader(!headless).LoadFileWaitTillLoaded(file, + protocol, format); if (af == null) { System.out.println("error"); } else { + System.out + .println("CMD [-open " + file + "] executed successfully!"); + if (file2 != null) + { + protocol = AppletFormatAdapter.checkProtocol(file2); + try + { + format = new IdentifyFile().identify(file2, protocol); + } catch (FileFormatException e1) + { + // TODO ? + } + AlignFrame af2 = new FileLoader(!headless) + .LoadFileWaitTillLoaded(file2, protocol, format); + if (af2 == null) + { + System.out.println("error"); + } + else + { + AlignViewport.openLinkedAlignmentAs(af, + af.getViewport().getAlignment(), + af2.getViewport().getAlignment(), "", + AlignViewport.SPLIT_FRAME); + System.out.println( + "CMD [-open2 " + file2 + "] executed successfully!"); + } + } + setCurrentAlignFrame(af); - data = aparser.getValue("colour", true); + + // TODO: file2 How to implement file2 for the applet spit screen? + + data = aparser.getValue(ArgsParser.COLOUR, true); if (data != null) { data.replaceAll("%20", " "); @@ -605,7 +750,7 @@ public class Jalview } // Must maintain ability to use the groups flag - data = aparser.getValue("groups", true); + data = aparser.getValue(ArgsParser.GROUPS, true); if (data != null) { af.parseFeaturesFile(data, @@ -614,7 +759,7 @@ public class Jalview System.out.println( "CMD groups[-" + data + "] executed successfully!"); } - data = aparser.getValue("features", true); + data = aparser.getValue(ArgsParser.FEATURES, true); if (data != null) { af.parseFeaturesFile(data, @@ -624,7 +769,7 @@ public class Jalview "CMD [-features " + data + "] executed successfully!"); } - data = aparser.getValue("annotations", true); + data = aparser.getValue(ArgsParser.ANNOTATIONS, true); if (data != null) { af.loadJalviewDataFile(data, null, null, null); @@ -632,8 +777,15 @@ public class Jalview System.out.println( "CMD [-annotations " + data + "] executed successfully!"); } + + if (aparser.contains(ArgsParser.SHOWOVERVIEW)) + { + af.overviewMenuItem_actionPerformed(null); + System.out.println("CMD [showoverview] executed successfully!"); + } + // set or clear the sortbytree flag. - if (aparser.contains("sortbytree")) + if (aparser.contains(ArgsParser.SORTBYTREE)) { af.getViewport().setSortByTree(true); if (af.getViewport().getSortByTree()) @@ -641,24 +793,48 @@ public class Jalview System.out.println("CMD [-sortbytree] executed successfully!"); } } - if (aparser.contains("no-annotation")) + + boolean doUpdateAnnotation = false; + + /** + * we do this earlier in JalviewJS because of a complication with + * SHOWOVERVIEW + * + * For now, just fixing this in JalviewJS. + * + * + * @j2sIgnore + * + */ { - af.getViewport().setShowAnnotation(false); - if (!af.getViewport().isShowAnnotation()) + if (aparser.contains(ArgsParser.NOANNOTATION) + || aparser.contains(ArgsParser.NOANNOTATION2)) { - System.out.println("CMD no-annotation executed successfully!"); + af.getViewport().setShowAnnotation(false); + if (!af.getViewport().isShowAnnotation()) + { + doUpdateAnnotation = true; + System.out + .println("CMD no-annotation executed successfully!"); + } } } - if (aparser.contains("nosortbytree")) + if (aparser.contains(ArgsParser.NOSORTBYTREE)) { af.getViewport().setSortByTree(false); if (!af.getViewport().getSortByTree()) { + doUpdateAnnotation = true; System.out .println("CMD [-nosortbytree] executed successfully!"); } } - data = aparser.getValue("tree", true); + if (doUpdateAnnotation) + { // BH 2019.07.24 + af.setMenusForViewport(); + af.alignPanel.updateLayout(); + } + data = aparser.getValue(ArgsParser.TREE, true); if (data != null) { try @@ -678,97 +854,30 @@ public class Jalview // TODO - load PDB structure(s) to alignment JAL-629 // (associate with identical sequence in alignment, or a specified // sequence) - if (groovyscript != null) + if (isJavaAppletTag) { - // Execute the groovy script after we've done all the rendering stuff - // and before any images or figures are generated. - System.out.println("Executing script " + groovyscript); - executeGroovyScript(groovyscript, af); - System.out.println("CMD groovy[" + groovyscript - + "] executed successfully!"); - groovyscript = null; + loadAppletParams(aparser, af); } - String imageName = "unnamed.png"; - while (aparser.getSize() > 1) + else if (!isJS) + /** + * Java only + * + * @j2sIgnore + */ { - String outputFormat = aparser.nextValue(); - file = aparser.nextValue(); - - if (outputFormat.equalsIgnoreCase("png")) - { - af.createPNG(new File(file)); - imageName = (new File(file)).getName(); - System.out.println("Creating PNG image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("svg")) - { - File imageFile = new File(file); - imageName = imageFile.getName(); - af.createSVG(imageFile); - System.out.println("Creating SVG image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("html")) - { - File imageFile = new File(file); - imageName = imageFile.getName(); - HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); - htmlSVG.exportHTML(file); - - System.out.println("Creating HTML image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("biojsmsa")) - { - if (file == null) - { - System.err.println("The output html file must not be null"); - return; - } - try - { - BioJsHTMLOutput.refreshVersionInfo( - BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); - } catch (URISyntaxException e) - { - e.printStackTrace(); - } - BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); - bjs.exportHTML(file); - System.out - .println("Creating BioJS MSA Viwer HTML file: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("imgMap")) - { - af.createImageMap(new File(file), imageName); - System.out.println("Creating image map: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("eps")) - { - File outputFile = new File(file); - System.out.println( - "Creating EPS file: " + outputFile.getAbsolutePath()); - af.createEPS(outputFile); - continue; - } - - af.saveAlignment(file, format); - if (af.isSaveAlignmentSuccessful()) - { - System.out.println("Written alignment in " + format - + " format to " + file); - } - else + if (groovyscript != null) { - System.out.println("Error writing file " + file + " in " - + format + " format!!"); + // Execute the groovy script after we've done all the rendering + // stuff + // and before any images or figures are generated. + System.out.println("Executing script " + groovyscript); + executeGroovyScript(groovyscript, af); + System.out.println("CMD groovy[" + groovyscript + + "] executed successfully!"); + groovyscript = null; } - } - + createOutputFiles(aparser, af, format); while (aparser.getSize() > 0) { System.out.println("Unknown arg: " + aparser.nextValue()); @@ -780,16 +889,16 @@ public class Jalview // And the user // //////////////////// - if (!Platform.isJS() && !headless && file == null - && Cache.getDefault("SHOW_STARTUP_FILE", true)) + if (!isJS && !headless && file == null && !haveImport + && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true)) /** * Java only * * @j2sIgnore */ { - file = Cache.getDefault("STARTUP_FILE", - Cache.getDefault("www.jalview.org", + file = jalview.bin.Cache.getDefault("STARTUP_FILE", + jalview.bin.Cache.getDefault("www.jalview.org", "http://www.jalview.org") + "/examples/exampleFile_2_7.jar"); if (file.equals( @@ -798,7 +907,7 @@ public class Jalview // hardwire upgrade of the startup file file.replace("_2_3.jar", "_2_7.jar"); // and remove the stale setting - Cache.removeProperty("STARTUP_FILE"); + jalview.bin.Cache.removeProperty("STARTUP_FILE"); } protocol = DataSourceType.FILE; @@ -823,8 +932,8 @@ public class Jalview } } - startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol, - format); + startUpAlframe = new FileLoader(!headless) + .LoadFileWaitTillLoaded(file, protocol, format); // extract groovy arguments before anything else. } @@ -852,34 +961,140 @@ public class Jalview } desktop.setInBatchMode(false); } + + return null; } - private static void showUsage() + /** + * Writes an output file for each format (if any) specified in the + * command-line arguments. Supported formats are currently + *
    + *
  • png
  • + *
  • svg
  • + *
  • html
  • + *
  • biojsmsa
  • + *
  • imgMap
  • + *
  • eps
  • + *
+ * A format parameter should be followed by a parameter specifying the output + * file name. {@code imgMap} parameters should follow those for the + * corresponding alignment image output. + * + * @param aparser + * @param af + * @param format + */ + private void createOutputFiles(ArgsParser aparser, AlignFrame af, + FileFormatI format) { - System.out.println( - "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n" - + "-nodisplay\tRun Jalview without User Interface.\n" - + "-props FILE\tUse the given Jalview properties file instead of users default.\n" - + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n" - + "-annotations FILE\tAdd precalculated annotations to the alignment.\n" - + "-tree FILE\tLoad the given newick format tree file onto the alignment\n" - + "-features FILE\tUse the given file to mark features on the alignment.\n" - + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n" - + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n" - + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n" - + "-msf FILE\tCreate alignment file FILE in MSF format.\n" - + "-pileup FILE\tCreate alignment file FILE in Pileup format\n" - + "-pir FILE\tCreate alignment file FILE in PIR format.\n" - + "-blc FILE\tCreate alignment file FILE in BLC format.\n" - + "-json FILE\tCreate alignment file FILE in JSON format.\n" - + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n" - + "-png FILE\tCreate PNG image FILE from alignment.\n" - + "-svg FILE\tCreate SVG image FILE from alignment.\n" - + "-html FILE\tCreate HTML file from alignment.\n" - + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n" - + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n" - + "-eps FILE\tCreate EPS file FILE from alignment.\n" - + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n" + String imageName = "unnamed.png"; + while (aparser.getSize() > 1) + { + String outputFormat = aparser.nextValue(); + String file = aparser.nextValue(); + // System.out.println("format " + outputFormat); + + if (outputFormat.equalsIgnoreCase("png")) + { + af.createPNG(new File(file)); + imageName = (new File(file)).getName(); + System.out.println("Creating PNG image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("svg")) + { + File imageFile = new File(file); + imageName = imageFile.getName(); + af.createSVG(imageFile); + System.out.println("Creating SVG image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("html")) + { + File imageFile = new File(file); + imageName = imageFile.getName(); + HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); + htmlSVG.exportHTML(file); + + System.out.println("Creating HTML image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("biojsmsa")) + { + if (file == null) + { + System.err.println("The output html file must not be null"); + return; + } + try + { + BioJsHTMLOutput.refreshVersionInfo( + BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); + } catch (URISyntaxException e) + { + e.printStackTrace(); + } + BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); + bjs.exportHTML(file); + System.out.println("Creating BioJS MSA Viwer HTML file: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("imgMap")) + { + af.createImageMap(new File(file), imageName); + System.out.println("Creating image map: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("eps")) + { + File outputFile = new File(file); + System.out.println( + "Creating EPS file: " + outputFile.getAbsolutePath()); + af.createEPS(outputFile); + continue; + } + + af.saveAlignment(file, format); + if (af.isSaveAlignmentSuccessful()) + { + System.out.println( + "Written alignment in " + format + " format to " + file); + } + else + { + System.out.println("Error writing file " + file + " in " + format + + " format!!"); + } + + } + } + + private static void showUsage() + { + System.out.println( + "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n" + + "-nodisplay\tRun Jalview without User Interface.\n" + + "-props FILE\tUse the given Jalview properties file instead of users default.\n" + + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n" + + "-annotations FILE\tAdd precalculated annotations to the alignment.\n" + + "-tree FILE\tLoad the given newick format tree file onto the alignment\n" + + "-features FILE\tUse the given file to mark features on the alignment.\n" + + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n" + + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n" + + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n" + + "-msf FILE\tCreate alignment file FILE in MSF format.\n" + + "-pileup FILE\tCreate alignment file FILE in Pileup format\n" + + "-pir FILE\tCreate alignment file FILE in PIR format.\n" + + "-blc FILE\tCreate alignment file FILE in BLC format.\n" + + "-json FILE\tCreate alignment file FILE in JSON format.\n" + + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n" + + "-png FILE\tCreate PNG image FILE from alignment.\n" + + "-svg FILE\tCreate SVG image FILE from alignment.\n" + + "-html FILE\tCreate HTML file from alignment.\n" + + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n" + + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n" + + "-eps FILE\tCreate EPS file FILE from alignment.\n" + + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n" + "-noquestionnaire\tTurn off questionnaire check.\n" + "-nonews\tTurn off check for Jalview news.\n" + "-nousagestats\tTurn off google analytics tracking for this session.\n" @@ -891,6 +1106,10 @@ public class Jalview // passed in correctly)" + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n" + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n" + // + + // "-vdoc vamsas-document\tImport vamsas document into new + // session or join existing session with same URN\n" + // + "-vses vamsas-session\tJoin session with given URN\n" + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n" + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n"); } @@ -900,8 +1119,9 @@ public class Jalview /** * start a User Config prompt asking if we can log usage statistics. */ - PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop, - "USAGESTATS", "Jalview Usage Statistics", + PromptUserConfig prompter = new PromptUserConfig( + Desktop.getDesktopPane(), "USAGESTATS", + "Jalview Usage Statistics", "Do you want to help make Jalview better by enabling " + "the collection of usage statistics with Google Analytics ?" + "\n\n(you can enable or disable usage tracking in the preferences)", @@ -930,10 +1150,10 @@ public class Jalview * Locate the given string as a file and pass it to the groovy interpreter. * * @param groovyscript - * the script to execute + * the script to execute * @param jalviewContext - * the Jalview Desktop object passed in to the groovy - * binding as the 'Jalview' object. + * the Jalview Desktop object passed in to the groovy binding as the + * 'Jalview' object. */ private void executeGroovyScript(String groovyscript, AlignFrame af) { @@ -1020,7 +1240,7 @@ public class Jalview } try { - Map vbinding = new HashMap<>(); + Map vbinding = new HashMap<>(); vbinding.put("Jalview", this); if (af != null) { @@ -1044,16 +1264,6 @@ public class Jalview } } - public static boolean isHeadlessMode() - { - String isheadless = System.getProperty("java.awt.headless"); - if (isheadless != null && isheadless.equalsIgnoreCase("true")) - { - return true; - } - return false; - } - public AlignFrame[] getAlignFrames() { return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() } @@ -1062,11 +1272,17 @@ public class Jalview } /** - * Quit method delegates to Desktop.quit - unless running in headless mode when - * it just ends the JVM + * Quit method delegates to Desktop.quit - unless running in headless mode + * when it just ends the JVM */ public void quit() { + if (jsFunctionExec != null) + { + jsFunctionExec.tidyUp(); + jsFunctionExec = null; + } + if (desktop != null) { desktop.quit(); @@ -1077,13 +1293,884 @@ public class Jalview } } - public static AlignFrame getCurrentAlignFrame() + /** + * Handle all JalviewLite applet parameters + * + * @param aparser + * @param af + */ + private void loadAppletParams(ArgsParser aparser, AlignFrame af) + { + JalviewApp app = new JalviewApp() + { + + // TODO BH 2019 + // + // These are methods that are in JalviewLite that various classes call + // but are not in JalviewLiteJsApi. Or, even if they are, other classes + // call + // them to JalviewLite directly. Some may not be necessary, but they have + // to + // be at least mentioned here, or the classes calling them should + // reference + // JalviewLite itself. + + private boolean alignPDBStructures; // From JalviewLite; not implemented + + private Hashtable> jsmessages; + + private Hashtable jshashes; + + @Override + public String getParameter(String name) + { + return aparser.getAppletValue(name, null); + } + + @Override + public boolean getDefaultParameter(String name, boolean def) + { + String stn; + return ((stn = getParameter(name)) == null ? def + : "true".equalsIgnoreCase(stn)); + } + + /** + * Get the applet-like document base even though this is an application. + */ + @Override + public URL getDocumentBase() + { + return Platform.getDocumentBase(); + } + + /** + * Get the applet-like code base even though this is an application. + */ + @Override + public URL getCodeBase() + { + return Platform.getCodeBase(); + } + + @Override + public AlignViewportI getViewport() + { + return af.getViewport(); + } + + /** + * features + * + */ + @Override + public boolean parseFeaturesFile(String filename, + DataSourceType protocol) + { + return af.parseFeaturesFile(filename, protocol); + } + + /** + * scorefile + * + */ + @Override + public boolean loadScoreFile(String sScoreFile) throws IOException + { + af.loadJalviewDataFile(sScoreFile, null, null, null); + return true; + } + + /** + * annotations, jpredfile, jnetfile + * + */ + @Override + public void updateForAnnotations() + { + af.updateForAnnotations(); + } + + @Override + public void loadTree(NewickFile fin, String treeFile) + throws IOException + { + // n/a -- already done by standard Jalview command line processing + } + + @Override + public void setAlignPdbStructures(boolean defaultParameter) + { + alignPDBStructures = true; + } + + @Override + public void newStructureView(PDBEntry pdb, SequenceI[] seqs, + String[] chains, DataSourceType protocol) + { + StructureViewer.launchStructureViewer(af.alignPanel, pdb, seqs); + } + + @Override + public void setFeatureGroupState(String[] groups, boolean state) + { + af.setFeatureGroupState(groups, state); + } + + @Override + public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs, + String[][] chains, String[] protocols) + { + System.err.println( + "Jalview applet interface alignedStructureView not implemented"); + } + + @Override + public void newFeatureSettings() + { + System.err.println( + "Jalview applet interface newFeatureSettings not implemented"); + } + + private Vector jsExecQueue; + + @Override + public Vector getJsExecQueue(JSFunctionExec exec) + { + jsFunctionExec = exec; + return (jsExecQueue == null ? (jsExecQueue = new Vector<>()) + : jsExecQueue); + } + + @Override + public AppletContext getAppletContext() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isJsfallbackEnabled() + { + // TODO Auto-generated method stub + return false; + } + + @Override + public JSObject getJSObject() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public StructureSelectionManagerProvider getStructureSelectionManagerProvider() + { + // TODO Q: what exactly is this? BH + return null; + } + + @Override + public void updateColoursFromMouseOver(Object source, + MouseOverStructureListener mouseOverStructureListener) + { + // TODO Auto-generated method stub + + } + + @Override + public Object[] getSelectionForListener(SequenceGroup seqsel, + ColumnSelection colsel, HiddenColumns hidden, + SelectionSource source, Object alignFrame) + { + return appLoader.getSelectionForListener(getCurrentAlignFrame(), + seqsel, colsel, hidden, source, alignFrame); + } + + @Override + public String arrayToSeparatorList(String[] array) + { + return appLoader.arrayToSeparatorList(array); + } + + @Override + public Hashtable getJSHashes() + { + return (jshashes == null ? (jshashes = new Hashtable<>()) + : jshashes); + } + + @Override + public Hashtable> getJSMessages() + { + return (jsmessages == null ? (jsmessages = new Hashtable<>()) + : jsmessages); + } + + @Override + public Object getFrameForSource(VamsasSource source) + { + if (source != null) + { + AlignFrame af; + if (source instanceof jalview.gui.AlignViewport + && source == (af = getCurrentAlignFrame()).getViewport()) + { + // should be valid if it just generated an event! + return af; + } + // TODO: ensure that if '_af' is specified along with a handler + // function, then only events from that alignFrame are sent to that + // function + } + return null; + } + + @Override + public FeatureRenderer getNewFeatureRenderer(AlignViewportI vp) + { + return new jalview.gui.FeatureRenderer((AlignmentPanel) vp); + } + + }; + + appLoader = new JalviewAppLoader(true); + appLoader.load(app); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences() + */ + @Override + public String getSelectedSequences() { - return Jalview.currentAlignFrame; + return getSelectedSequencesFrom(getCurrentAlignFrame()); } - public static void setCurrentAlignFrame(AlignFrame currentAlignFrame) + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences(java.lang.String) + */ + @Override + public String getSelectedSequences(String sep) + { + return getSelectedSequencesFrom(getCurrentAlignFrame(), sep); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui + * .AlignFrame) + */ + @Override + public String getSelectedSequencesFrom(AlignFrameI alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return getSelectedSequencesFrom(alf, null); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui + * .AlignFrame, java.lang.String) + */ + @Override + public String getSelectedSequencesFrom(AlignFrameI alf, String sep) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getSelectedSequencesFrom(alf, sep); + } + + /** + * + * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui + * .AlignFrame, java.lang.String) + */ + @Override + public void highlight(String sequenceId, String position, + String alignedPosition) + { + highlightIn(null, sequenceId, position, + alignedPosition); + } + + @Override + public void highlightIn(AlignFrameI alf, String sequenceId, + String position, String alignedPosition) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + appLoader.highlightIn(alf, sequenceId, position, alignedPosition); + } + + @Override + public void select(String sequenceIds, String columns) + { + selectIn(getCurrentAlignFrame(), sequenceIds, columns, null); + } + + @Override + public void select(String sequenceIds, String columns, String sep) + { + selectIn(null, sequenceIds, columns, sep); + } + + @Override + public void selectIn(AlignFrameI alf, String sequenceIds, String columns) + { + selectIn(alf, sequenceIds, columns, null); + } + + @Override + public void selectIn(AlignFrameI alf, String sequenceIds, String columns, + String sep) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + appLoader.selectIn(alf, sequenceIds, columns, sep); + } + + @Override + public String getSelectedSequencesAsAlignment(String format, + String suffix) + { + return getSelectedSequencesAsAlignmentFrom(null, + format, suffix); + } + + @Override + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, String sep) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getSelectedSequencesAsAlignmentFrom(alf, format, sep); + } + + @Override + public String getAlignmentOrder() + { + return getAlignmentFrom(getCurrentAlignFrame(), null); + } + + @Override + public String getAlignmentOrderFrom(AlignFrameI alf) + { + return getAlignmentFrom(alf, null); + } + + @Override + public String getAlignmentOrderFrom(AlignFrameI alf, String sep) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getAlignmentOrderFrom(alf, sep); + } + + @Override + public String orderBy(String order, String undoName) + { + return orderBy(order, undoName, null); + } + + @Override + public String orderBy(String order, String undoName, String sep) + { + return orderAlignmentBy(getCurrentAlignFrame(), order, undoName, sep); + } + + @Override + public String orderAlignmentBy(AlignFrameI alf, String order, + String undoName, String sep) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.orderAlignmentBy(alf, order, undoName, sep); + } + + @Override + public String getAlignment(String format) + { + return getAlignmentFrom(null, format, null); + } + + @Override + public String getAlignmentFrom(AlignFrameI alf, String format) + { + return getAlignmentFrom(alf, format, null); + } + + @Override + public String getAlignment(String format, String suffix) + { + return getAlignmentFrom(getCurrentAlignFrame(), format, suffix); + } + + @Override + public String getAlignmentFrom(AlignFrameI alf, String format, + String suffix) + { + return appLoader.getAlignmentFrom(alf, format, suffix); + } + + @Override + public void loadAnnotation(String annotation) + { + loadAnnotationFrom(getCurrentAlignFrame(), annotation); + } + + @Override + public void loadAnnotationFrom(AlignFrameI alf, String annotation) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + appLoader.loadAnnotationFrom(alf, annotation); + } + + @Override + public void loadFeatures(String features, boolean autoenabledisplay) + { + loadFeaturesFrom(currentAlignFrame, features, autoenabledisplay); + } + + @Override + public boolean loadFeaturesFrom(AlignFrameI alf, String features, + boolean autoenabledisplay) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.loadFeaturesFrom(alf, features, autoenabledisplay); + } + + @Override + public String getFeatures(String format) + { + return getFeaturesFrom(null, format); + } + + @Override + public String getFeaturesFrom(AlignFrameI alf, String format) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getFeaturesFrom(alf, format, true, false); + } + + @Override + public String getAnnotation() + { + return getAnnotationFrom(null); + } + + @Override + public String getAnnotationFrom(AlignFrameI alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getAnnotationFrom(alf); + } + + @Override + public AlignFrameI newView() + { + return newViewFrom(null, null); + } + + @Override + public AlignFrameI newView(String name) + { + return newViewFrom(null, name); + } + + @Override + public AlignFrameI newViewFrom(AlignFrameI alf) + { + return newViewFrom(alf, null); + } + + @Override + public AlignFrameI newViewFrom(AlignFrameI alf, String name) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.newViewFrom(alf, name); + } + + @Override + public AlignFrameI loadAlignment(String text, String title) + { + return appLoader.loadAlignment(text, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT, title); + } + + @Override + public boolean addPdbFile(AlignFrameI alFrame, String sequenceId, + String pdbEntryString, String pdbFile) + { + if (alFrame == null) + { + alFrame = getCurrentAlignFrame(); + } + return appLoader.addPdbFile(alFrame, sequenceId, pdbEntryString, + pdbFile); + } + + @Override + public void scrollViewToIn(AlignFrameI alf, String topRow, + String leftHandColumn) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + appLoader.scrollViewToIn(alf, topRow, leftHandColumn); + } + + @Override + public void scrollViewToRowIn(AlignFrameI alf, String topRow) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + appLoader.scrollViewToRowIn(alf, topRow); + } + + @Override + public void scrollViewToColumnIn(AlignFrameI alf, String leftHandColumn) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + appLoader.scrollViewToColumnIn(alf, leftHandColumn); + } + + @Override + public String getFeatureGroups() + { + return getFeatureGroupsOn(null); + } + + @Override + public String getFeatureGroupsOn(AlignFrameI alf) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getFeatureGroupsOn(alf); + } + + @Override + public String getFeatureGroupsOfState(boolean visible) + { + return getFeatureGroupsOfStateOn(null, visible); + } + + @Override + public String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getFeatureGroupsOfStateOn(alf, visible); + } + + @Override + public void setFeatureGroupState(String groups, boolean state) + { // JalviewLite API + setFeatureGroupStateOn(null, groups, state); + } + + @Override + public void setFeatureGroupStateOn(AlignFrameI alf, String groups, + boolean state) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + appLoader.setFeatureGroupStateOn(alf, groups, state); + } + + @Override + public String getSeparator() { - Jalview.currentAlignFrame = currentAlignFrame; + return appLoader.getSeparator(); } -} + + @Override + public void setSeparator(String separator) + { + appLoader.setSeparator(separator); + } + + @Override + public String getJsMessage(String messageclass, String viewId) + { + // see http://www.jalview.org/examples/jalviewLiteJs.html + return null; + } + + /** + * Open a new Tree panel on the desktop statically. Params are standard (not + * set by Groovy). No dialog is opened. + * + * @param af + * @param treeType + * @param modelName + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + @Override + public Object openTreePanel(AlignFrame af, String treeType, + String modelName) + { // JalviewJS api + if (af == null) + { + af = getCurrentAlignFrame(); + } + return CalculationChooser.openTreePanel(af, treeType, modelName, null); + } + + /** + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * + * @param af + * @param modelName + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + @Override + public Object openPcaPanel(AlignFrame af, String modelName) + { + if (af == null) + { + af = getCurrentAlignFrame(); + } + return CalculationChooser.openPcaPanel(af, modelName, null); + } + + @Override + public String getSelectedSequencesAsAlignment(String format, + boolean suffix) + { + return getSelectedSequencesAsAlignmentFrom(null, + format, suffix); + } + + @Override + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, boolean suffix) + { + if (alf == null) + { + alf = getCurrentAlignFrame(); + } + return appLoader.getSelectedSequencesAsAlignmentFrom(alf, format, + "" + suffix); + } + + @Override + public String arrayToSeparatorList(String[] array) + { + return appLoader.arrayToSeparatorList(array); + } + + @Override + public String[] separatorListToArray(String list) + { + return appLoader.separatorListToArray(list); + } + + //// probably not needed in JalviewJS -- From when Jmol and Jalview did not + //// have a direct connection? + + @Override + public void setMouseoverListener(String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void setMouseoverListener(AlignFrameI af, String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void setSelectionListener(String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void setSelectionListener(AlignFrameI af, String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void setStructureListener(String listener, String modelSet) + { + // TODO Auto-generated method stub + + } + + @Override + public void removeJavascriptListener(AlignFrameI af, String listener) + { + // TODO Auto-generated method stub + + } + + @Override + public void mouseOverStructure(String pdbResNum, String chain, + String pdbfile) + { + // TODO Auto-generated method stub + + } + + @Override + public void showOverview() + { + currentAlignFrame.overviewMenuItem_actionPerformed(null); + } + + public void notifyWorker(AlignCalcWorkerI worker, String status) + { + // System.out.println("Jalview worker " + worker.getClass().getSimpleName() + // + " " + status); + } + + /** + * flag to allow selected Runnable and Thread processes to run synchronously + * + * JAL-3563 + * + */ + private static boolean isSynchronous = false; + + /** + * Set Jalview to run selected processes synchronously in test and headless + * environments. + * + * JAL-3563 + * + * @param b + * @author Bob Hanson + */ + public static void setSynchronous(boolean b) + { + isSynchronous = b; + } + + /** + * Allows optional synchronous running of a Runnable that would otherwise use + * SwingUtilities.invokeLater. + * + * JAL-3563 + * + * @param t + * @author Bob Hanson + */ + public static boolean isSynchronous() + { + return isSynchronous; + } + + /** + * Allows optional synchronous running of a Runnable that would otherwise use + * SwingUtilities.invokeLater. + * + * JAL-3563 + * + * @param t + * @author Bob Hanson + */ + public static void execRunnable(Runnable r) + { + if (isSynchronous()) + { + r.run(); + } + else + { + SwingUtilities.invokeLater(r); + } + } + + /** + * Allows optional synchronous running of a thread that would otherwise be run + * using start(). + * + * JAL-3563 + * + * @param t + * @author Bob Hanson + */ + public static void execThread(Thread t) + { + if (isSynchronous()) + { + t.run(); + } + else + { + t.start(); + } + } + + /** + * Get the SwingJS applet ID and combine that with the frameType + * + * @param frameType + * "alignment", "desktop", etc., or null + * @return + */ + public static String getAppID(String frameType) + { + String id = Cache.getProperty("Info.j2sAppletID"); + if (id == null) + { + id = "jalview"; + } + return id + (frameType == null ? "" : "-" + frameType); + } + +} \ No newline at end of file diff --git a/src/jalview/bin/JalviewAppLoader.java b/src/jalview/bin/JalviewAppLoader.java new file mode 100644 index 0000000..834a30f --- /dev/null +++ b/src/jalview/bin/JalviewAppLoader.java @@ -0,0 +1,1484 @@ +package jalview.bin; + +import jalview.api.AlignFrameI; +import jalview.api.JalviewApp; +import jalview.api.StructureSelectionManagerProvider; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentOrder; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.AlignViewport; +import jalview.gui.Desktop; +import jalview.io.AnnotationFile; +import jalview.io.AppletFormatAdapter; +import jalview.io.DataSourceType; +import jalview.io.FeaturesFile; +import jalview.io.FileFormat; +import jalview.io.FileFormatI; +import jalview.io.FileFormats; +import jalview.io.IdentifyFile; +import jalview.io.JPredFile; +import jalview.io.JnetAnnotationMaker; +import jalview.io.NewickFile; +import jalview.structure.SelectionSource; +import jalview.structure.StructureSelectionManager; +import jalview.util.HttpUtils; +import jalview.util.MessageManager; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * A class to load parameters for either JalviewLite or Jalview + * + * @author hansonr + * + */ +public class JalviewAppLoader +{ + + private JalviewApp app; // Jalview or JalviewJS or JalviewLite + + private boolean debug; + + String separator = "\u00AC"; // JalviewLite note: the default used to + // be '|', but many sequence IDS include + // pipes. + + public String getSeparator() + { + return separator; + } + + public void setSeparator(String separator) + { + this.separator = separator; + } + + public JalviewAppLoader(boolean debug) + { + this.debug = debug; + } + + public void load(JalviewApp app) + { + + this.app = app; + + String sep = app.getParameter("separator"); + if (sep != null) + { + if (sep.length() > 0) + { + separator = sep; + } + else + { + throw new Error(MessageManager + .getString("error.invalid_separator_parameter")); + } + } + + loadTree(); + loadScoreFile(); + loadFeatures(); + loadAnnotations(); + loadJnetFile(); + loadPdbFiles(); + callInitCallback(); + } + + /** + * Load PDBFiles if any specified by parameter(s). Returns true if loaded, + * else false. + * + * @param loaderFrame + * @return + */ + protected boolean loadPdbFiles() + { + boolean result = false; + /* + * Undocumented for 2.6 - + * related to JAL-434 + */ + + boolean doAlign = app.getDefaultParameter("alignpdbfiles", false); + app.setAlignPdbStructures(doAlign); + /* + * + * + * + * + * + */ + + // Accumulate pdbs here if they are heading for the same view (if + // alignPdbStructures is true) + Vector pdbs = new Vector<>(); + // create a lazy matcher if we're asked to + jalview.analysis.SequenceIdMatcher matcher = (app + .getDefaultParameter("relaxedidmatch", false)) + ? new jalview.analysis.SequenceIdMatcher( + app.getViewport().getAlignment() + .getSequencesArray()) + : null; + + int pdbFileCount = 0; + String param; + do + { + if (pdbFileCount > 0) + { + param = app.getParameter("PDBFILE" + pdbFileCount); + } + else + { + param = app.getParameter("PDBFILE"); + } + + if (param != null) + { + PDBEntry pdb = new PDBEntry(); + + String seqstring; + SequenceI[] seqs = null; + String[] chains = null; + + StringTokenizer st = new StringTokenizer(param, " "); + + if (st.countTokens() < 2) + { + String sequence = app.getParameter("PDBSEQ"); + if (sequence != null) + { + seqs = new SequenceI[] { matcher == null + ? (Sequence) app.getViewport().getAlignment() + .findName(sequence) + : matcher.findIdMatch(sequence) }; + } + + } + else + { + param = st.nextToken(); + List tmp = new ArrayList<>(); + List tmp2 = new ArrayList<>(); + + while (st.hasMoreTokens()) + { + seqstring = st.nextToken(); + StringTokenizer st2 = new StringTokenizer(seqstring, "="); + if (st2.countTokens() > 1) + { + // This is the chain + tmp2.add(st2.nextToken()); + seqstring = st2.nextToken(); + } + tmp.add(matcher == null + ? (Sequence) app.getViewport().getAlignment() + .findName(seqstring) + : matcher.findIdMatch(seqstring)); + } + + seqs = tmp.toArray(new SequenceI[tmp.size()]); + if (tmp2.size() == tmp.size()) + { + chains = tmp2.toArray(new String[tmp2.size()]); + } + } + pdb.setId(param); + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + // TODO check JAL-357 for files in a jar (CLASSLOADER) + pdb.setFile(ret[0]); + + if (seqs != null) + { + for (int i = 0; i < seqs.length; i++) + { + if (seqs[i] != null) + { + ((Sequence) seqs[i]).addPDBId(pdb); + StructureSelectionManager + .getStructureSelectionManager( + (StructureSelectionManagerProvider) app) + .registerPDBEntry(pdb); + } + else + { + if (debug) + { + // this may not really be a problem but we give a warning + // anyway + System.err.println( + "Warning: Possible input parsing error: Null sequence for attachment of PDB (sequence " + + i + ")"); + } + } + } + + if (doAlign) + { + pdbs.addElement(new Object[] { pdb, seqs, chains, protocol }); + } + else + { + app.newStructureView(pdb, seqs, chains, protocol); + } + } + } + + pdbFileCount++; + } while (param != null || pdbFileCount < 10); + if (pdbs.size() > 0) + { + SequenceI[][] seqs = new SequenceI[pdbs.size()][]; + PDBEntry[] pdb = new PDBEntry[pdbs.size()]; + String[][] chains = new String[pdbs.size()][]; + String[] protocols = new String[pdbs.size()]; + for (int pdbsi = 0, pdbsiSize = pdbs + .size(); pdbsi < pdbsiSize; pdbsi++) + { + Object[] o = pdbs.elementAt(pdbsi); + pdb[pdbsi] = (PDBEntry) o[0]; + seqs[pdbsi] = (SequenceI[]) o[1]; + chains[pdbsi] = (String[]) o[2]; + protocols[pdbsi] = (String) o[3]; + } + app.alignedStructureView(pdb, seqs, chains, protocols); + result = true; + } + return result; + } + + /** + * Load in a Jnetfile if specified by parameter. Returns true if loaded, else + * false. + * + * @param alignFrame + * @return + */ + protected boolean loadJnetFile() + { + boolean result = false; + String param = app.getParameter("jnetfile"); + if (param == null) + { + // jnet became jpred around 2016 + param = app.getParameter("jpredfile"); + } + if (param != null) + { + try + { + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + JPredFile predictions = new JPredFile(ret[0], protocol); + JnetAnnotationMaker.add_annotation(predictions, + app.getViewport().getAlignment(), 0, false); + // false == do not add sequence profile from concise output + app.getViewport().getAlignment().setupJPredAlignment(); + app.updateForAnnotations(); + result = true; + } catch (Exception ex) + { + ex.printStackTrace(); + } + } + return result; + } + + /** + * Load annotations if specified by parameter. Returns true if loaded, else + * false. + * + * @param alignFrame + * @return + */ + protected boolean loadAnnotations() + { + boolean result = false; + String param = app.getParameter("annotations"); + if (param != null) + { + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + param = ret[0]; + if (new AnnotationFile().annotateAlignmentView(app.getViewport(), + param, protocol)) + { + app.updateForAnnotations(); + result = true; + } + else + { + System.err + .println("Annotations were not added from annotation file '" + + param + "'"); + } + } + return result; + } + + /** + * Load features file and view settings as specified by parameters. Returns + * true if features were loaded, else false. + * + * @param alignFrame + * @return + */ + protected boolean loadFeatures() + { + boolean result = false; + // /////////////////////////// + // modify display of features + // we do this before any features have been loaded, ensuring any hidden + // groups are hidden when features first displayed + // + // hide specific groups + // + String param = app.getParameter("hidefeaturegroups"); + if (param != null) + { + app.setFeatureGroupState(separatorListToArray(param, separator), + false); + // app.setFeatureGroupStateOn(newAlignFrame, param, false); + } + // show specific groups + param = app.getParameter("showfeaturegroups"); + if (param != null) + { + app.setFeatureGroupState(separatorListToArray(param, separator), + true); + // app.setFeatureGroupStateOn(newAlignFrame, param, true); + } + // and now load features + param = app.getParameter("features"); + if (param != null) + { + ret[0] = param; + DataSourceType protocol = resolveFileProtocol(app, ret); + + result = app.parseFeaturesFile(ret[0], protocol); + } + + param = app.getParameter("showFeatureSettings"); + if (param != null && param.equalsIgnoreCase("true")) + { + app.newFeatureSettings(); + } + return result; + } + + /** + * Load a score file if specified by parameter. Returns true if file was + * loaded, else false. + * + * @param loaderFrame + */ + protected boolean loadScoreFile() + { + boolean result = false; + String sScoreFile = app.getParameter("scoreFile"); + if (sScoreFile != null && !"".equals(sScoreFile)) + { + try + { + if (debug) + { + System.err.println( + "Attempting to load T-COFFEE score file from the scoreFile parameter"); + } + result = app.loadScoreFile(sScoreFile); + if (!result) + { + System.err.println( + "Failed to parse T-COFFEE parameter as a valid score file ('" + + sScoreFile + "')"); + } + } catch (Exception e) + { + System.err.printf("Cannot read score file: '%s'. Cause: %s \n", + sScoreFile, e.getMessage()); + } + } + return result; + } + + String[] ret = new String[1]; + + /** + * Load a tree for the alignment if specified by parameter. Returns true if a + * tree was loaded, else false. + * + * @param loaderFrame + * @return + */ + protected boolean loadTree() + { + boolean result = false; + String treeFile = app.getParameter("tree"); + if (treeFile == null) + { + treeFile = app.getParameter("treeFile"); + } + + if (treeFile != null) + { + try + { + ret[0] = treeFile; + NewickFile fin = new NewickFile(treeFile, + resolveFileProtocol(app, ret)); + fin.parse(); + + if (fin.getTree() != null) + { + app.loadTree(fin, ret[0]); + result = true; + if (debug) + { + System.out.println("Successfully imported tree."); + } + } + else + { + if (debug) + { + System.out.println( + "Tree parameter did not resolve to a valid tree."); + } + } + } catch (Exception ex) + { + ex.printStackTrace(); + } + } + return result; + } + + /** + * form a complete URL given a path to a resource and a reference location on + * the same server + * + * @param targetPath + * - an absolute path on the same server as localref or a document + * located relative to localref + * @param localref + * - a URL on the same server as url + * @return a complete URL for the resource located by url + */ + public static String resolveUrlForLocalOrAbsolute(String targetPath, + URL localref) + { + String resolvedPath = ""; + if (targetPath.startsWith("/")) + { + String codebase = localref.toString(); + String localfile = localref.getFile(); + resolvedPath = codebase.substring(0, + codebase.length() - localfile.length()) + targetPath; + return resolvedPath; + } + + /* + * get URL path and strip off any trailing file e.g. + * www.jalview.org/examples/index.html#applets?a=b is trimmed to + * www.jalview.org/examples/ + */ + String urlPath = localref.toString(); + String directoryPath = urlPath; + int lastSeparator = directoryPath.lastIndexOf("/"); + if (lastSeparator > 0) + { + directoryPath = directoryPath.substring(0, lastSeparator + 1); + } + + if (targetPath.startsWith("/")) + { + /* + * construct absolute URL to a file on the server - this is not allowed? + */ + // String localfile = localref.getFile(); + // resolvedPath = urlPath.substring(0, + // urlPath.length() - localfile.length()) + // + targetPath; + resolvedPath = directoryPath + targetPath.substring(1); + } + else + { + resolvedPath = directoryPath + targetPath; + } + // if (debug) + // { + // System.err.println( + // "resolveUrlForLocalOrAbsolute returning " + resolvedPath); + // } + return resolvedPath; + } + + /** + * parse the string into a list + * + * @param list + * @param separator + * @return elements separated by separator + */ + public static String[] separatorListToArray(String list, String separator) + { + // TODO use StringUtils version (slightly different...) + int seplen = separator.length(); + if (list == null || list.equals("") || list.equals(separator)) + { + return null; + } + Vector jv = new Vector<>(); + int cp = 0, pos; + while ((pos = list.indexOf(separator, cp)) > cp) + { + jv.addElement(list.substring(cp, pos)); + cp = pos + seplen; + } + if (cp < list.length()) + { + String c = list.substring(cp); + if (!c.equals(separator)) + { + jv.addElement(c); + } + } + if (jv.size() > 0) + { + String[] v = new String[jv.size()]; + for (int i = 0; i < v.length; i++) + { + v[i] = jv.elementAt(i); + } + jv.removeAllElements(); + // if (debug) + // { + // System.err.println("Array from '" + separator + // + "' separated List:\n" + v.length); + // for (int i = 0; i < v.length; i++) + // { + // System.err.println("item " + i + " '" + v[i] + "'"); + // } + // } + return v; + } + // if (debug) + // { + // System.err.println( + // "Empty Array from '" + separator + "' separated List"); + // } + return null; + } + + public static DataSourceType resolveFileProtocol(JalviewApp app, + String[] retPath) + { + String path = retPath[0]; + /* + * is it paste data? + */ + if (path.startsWith("PASTE")) + { + retPath[0] = path.substring(5); + return DataSourceType.PASTE; + } + + /* + * is it a URL? + */ + if (path.indexOf("://") >= 0) + { + return DataSourceType.URL; + } + + /* + * try relative to document root + */ + URL documentBase = app.getDocumentBase(); + String withDocBase = resolveUrlForLocalOrAbsolute(path, documentBase); + if (HttpUtils.isValidUrl(withDocBase)) + { + // if (debug) + // { + // System.err.println("Prepended document base '" + documentBase + // + "' to make: '" + withDocBase + "'"); + // } + retPath[0] = withDocBase; + return DataSourceType.URL; + } + + /* + * try relative to codebase (if different to document base) + */ + URL codeBase = app.getCodeBase(); + String withCodeBase = resolveUrlForLocalOrAbsolute(path, codeBase); + if (!withCodeBase.equals(withDocBase) + && HttpUtils.isValidUrl(withCodeBase)) + { + // if (debug) + // { + // System.err.println("Prepended codebase '" + codeBase + // + "' to make: '" + withCodeBase + "'"); + // } + retPath[0] = withCodeBase; + return DataSourceType.URL; + } + + /* + * try locating by classloader; try this last so files in the directory + * are resolved using document base + */ + if (inArchive(app.getClass(), path)) + { + return DataSourceType.CLASSLOADER; + } + return null; + } + + /** + * Discovers whether the given file is in the Applet Archive + * + * @param f + * String + * @return boolean + */ + private static boolean inArchive(Class c, String f) + { + // This might throw a security exception in certain browsers + // Netscape Communicator for instance. + try + { + boolean rtn = (c.getResourceAsStream("/" + f) != null); + // if (debug) + // { + // System.err.println("Resource '" + f + "' was " + // + (rtn ? "" : "not ") + "located by classloader."); + // } + return rtn; + } catch (Exception ex) + { + System.out.println("Exception checking resources: " + f + " " + ex); + return false; + } + } + + public void callInitCallback() + { + String initjscallback = app.getParameter("oninit"); + if (initjscallback == null) + { + return; + } + initjscallback = initjscallback.trim(); + if (initjscallback.length() > 0) + { + // TODO + } + } + + /** + * read sequence1...sequenceN as a raw alignment + * + * @param jalviewApp + * @return + */ + public String getPastedSequence(JalviewApp jalviewApp) + { + StringBuffer data = new StringBuffer("PASTE"); + int i = 1; + String file = null; + while ((file = app.getParameter("sequence" + i)) != null) + { + data.append(file.toString() + "\n"); + i++; + } + if (data.length() > 5) + { + file = data.toString(); + } + return file; + } + + /** + * concatenate the list with separator + * + * @param list + * @param separator + * @return concatenated string + */ + public static String arrayToSeparatorList(String[] list, String separator) + { + // TODO use StringUtils version + StringBuffer v = new StringBuffer(); + if (list != null && list.length > 0) + { + for (int i = 0, iSize = list.length; i < iSize; i++) + { + if (list[i] != null) + { + if (i > 0) + { + v.append(separator); + } + v.append(list[i]); + } + } + // if (debug) + // { + // System.err + // .println("Returning '" + separator + "' separated List:\n"); + // System.err.println(v); + // } + return v.toString(); + } + // if (debug) + // { + // System.err.println( + // "Returning empty '" + separator + "' separated List\n"); + // } + return "" + separator; + } + + public String arrayToSeparatorList(String[] array) + { + return arrayToSeparatorList(array, separator); + } + + public String getSelectedSequencesFrom(AlignFrameI alf, String sep) + { + StringBuffer result = new StringBuffer(""); + if (sep == null || sep.length() == 0) + { + sep = separator; // "+0x00AC; + } + AlignViewport v = ((AlignFrame) alf).getViewport(); + if (v.getSelectionGroup() != null) + { + SequenceI[] seqs = v.getSelectionGroup() + .getSequencesInOrder(v.getAlignment()); + + for (int i = 0; i < seqs.length; i++) + { + result.append(seqs[i].getName()); + result.append(sep); + } + } + + return result.toString(); + } + + public void setFeatureGroupStateOn(final AlignFrameI alf, + final String groups, boolean state) + { + Jalview.execRunnable(new Runnable() + { + @Override + public void run() + { + ((AlignFrame) alf).setFeatureGroupState( + separatorListToArray(groups, separator), state); + } + }); + } + + public String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible) + { + return arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroupsOfState(visible)); + } + + public void scrollViewToIn(final AlignFrameI alf, final String topRow, + final String leftHandColumn) + { + Jalview.execRunnable(new Runnable() + { + @Override + public void run() + { + try + { + ((AlignFrame) alf).scrollTo(new Integer(topRow).intValue(), + new Integer(leftHandColumn).intValue()); + + } catch (Exception ex) + { + System.err.println("Couldn't parse integer arguments (topRow='" + + topRow + "' and leftHandColumn='" + leftHandColumn + + "')"); + ex.printStackTrace(); + } + } + }); + } + + public void scrollViewToRowIn(final AlignFrameI alf, final String topRow) + { + + Jalview.execRunnable(new Runnable() + { + @Override + public void run() + { + try + { + ((AlignFrame) alf).scrollToRow(new Integer(topRow).intValue()); + + } catch (Exception ex) + { + System.err.println("Couldn't parse integer arguments (topRow='" + + topRow + "')"); + ex.printStackTrace(); + } + + } + }); + } + + public void scrollViewToColumnIn(final AlignFrameI alf, + final String leftHandColumn) + { + Jalview.execRunnable(new Runnable() + { + + @Override + public void run() + { + try + { + ((AlignFrame) alf) + .scrollToColumn(new Integer(leftHandColumn).intValue()); + + } catch (Exception ex) + { + System.err.println( + "Couldn't parse integer arguments (leftHandColumn='" + + leftHandColumn + "')"); + ex.printStackTrace(); + } + } + }); + + } + + public boolean addPdbFile(AlignFrameI alf, String sequenceId, + String pdbEntryString, String pdbFile) + { + AlignFrame alFrame = (AlignFrame) alf; + SequenceI toaddpdb = alFrame.getViewport().getAlignment() + .findName(sequenceId); + boolean needtoadd = false; + if (toaddpdb != null) + { + Vector pdbe = toaddpdb.getAllPDBEntries(); + PDBEntry pdbentry = null; + if (pdbe != null && pdbe.size() > 0) + { + for (int pe = 0, peSize = pdbe.size(); pe < peSize; pe++) + { + pdbentry = pdbe.elementAt(pe); + if (!pdbentry.getId().equals(pdbEntryString) + && !pdbentry.getFile().equals(pdbFile)) + { + pdbentry = null; + } + else + { + continue; + } + } + } + if (pdbentry == null) + { + pdbentry = new PDBEntry(); + pdbentry.setId(pdbEntryString); + pdbentry.setFile(pdbFile); + needtoadd = true; // add this new entry to sequence. + } + // resolve data source + // TODO: this code should be a refactored to an io package + DataSourceType protocol = AppletFormatAdapter.resolveProtocol(pdbFile, + FileFormat.PDB); + if (protocol == null) + { + return false; + } + if (needtoadd) + { + pdbentry.setProperty("protocol", protocol); + toaddpdb.addPDBId(pdbentry); + alFrame.alignPanel.getStructureSelectionManager() + .registerPDBEntry(pdbentry); + } + } + return true; + } + + public AlignFrameI loadAlignment(String text, int width, int height, + String title) + { + AlignmentI al = null; + + try + { + FileFormatI format = new IdentifyFile().identify(text, + DataSourceType.PASTE); + al = new AppletFormatAdapter().readFile(text, DataSourceType.PASTE, + format); + if (al.getHeight() > 0) + { + return new AlignFrame(al, width, height, title); + } + } catch (IOException ex) + { + ex.printStackTrace(); + } + return null; + } + + public String getFeatureGroupsOn(AlignFrameI alf) + { + return arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroups()); + } + + public void highlightIn(final AlignFrameI alf, final String sequenceId, + final String position, final String alignedPosition) + { + // TODO: could try to highlight in all alignments if alf==null + jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( + ((AlignFrame) alf).getViewport().getAlignment() + .getSequencesArray()); + final SequenceI sq = matcher.findIdMatch(sequenceId); + if (sq != null) + { + int apos = -1; + try + { + apos = new Integer(position).intValue(); + apos--; + } catch (NumberFormatException ex) + { + return; + } + final int pos = apos; + // use vamsas listener to broadcast to all listeners in scope + if (alignedPosition != null && (alignedPosition.trim().length() == 0 + || alignedPosition.toLowerCase().indexOf("false") > -1)) + { + Jalview.execRunnable(new Runnable() + { + @Override + public void run() + { + StructureSelectionManager + .getStructureSelectionManager(Desktop.getInstance()) + .mouseOverVamsasSequence(sq, sq.findIndex(pos), null); + } + }); + } + else + { + Jalview.execRunnable(new Runnable() + { + @Override + public void run() + { + StructureSelectionManager + .getStructureSelectionManager(Desktop.getInstance()) + .mouseOverVamsasSequence(sq, pos, null); + } + }); + } + } + } + + public void selectIn(final AlignFrameI alf, String sequenceIds, + String columns, String sep) + { + if (sep == null || sep.length() == 0) + { + sep = separator; + } + else + { + if (debug) + { + System.err.println("Selecting region using separator string '" + + separator + "'"); + } + } + // deparse fields + String[] ids = JalviewAppLoader.separatorListToArray(sequenceIds, sep); + String[] cols = JalviewAppLoader.separatorListToArray(columns, sep); + final SequenceGroup sel = new SequenceGroup(); + final ColumnSelection csel = new ColumnSelection(); + AlignmentI al = ((AlignFrame) alf).getViewport().getAlignment(); + jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( + ((AlignFrame) alf).getViewport().getAlignment() + .getSequencesArray()); + int start = 0, end = al.getWidth(), alw = al.getWidth(); + boolean seqsfound = true; + if (ids != null && ids.length > 0) + { + seqsfound = false; + for (int i = 0; i < ids.length; i++) + { + if (ids[i].trim().length() == 0) + { + continue; + } + SequenceI sq = matcher.findIdMatch(ids[i]); + if (sq != null) + { + seqsfound = true; + sel.addSequence(sq, false); + } + } + } + boolean inseqpos = false; + if (cols != null && cols.length > 0) + { + boolean seset = false; + for (int i = 0; i < cols.length; i++) + { + String cl = cols[i].trim(); + if (cl.length() == 0) + { + continue; + } + int p; + if ((p = cl.indexOf("-")) > -1) + { + int from = -1, to = -1; + try + { + from = new Integer(cl.substring(0, p)).intValue(); + from--; + } catch (NumberFormatException ex) + { + System.err.println( + "ERROR: Couldn't parse first integer in range element column selection string '" + + cl + "' - format is 'from-to'"); + return; + } + try + { + to = new Integer(cl.substring(p + 1)).intValue(); + to--; + } catch (NumberFormatException ex) + { + System.err.println( + "ERROR: Couldn't parse second integer in range element column selection string '" + + cl + "' - format is 'from-to'"); + return; + } + if (from >= 0 && to >= 0) + { + // valid range + if (from < to) + { + int t = to; + to = from; + to = t; + } + if (!seset) + { + start = from; + end = to; + seset = true; + } + else + { + // comment to prevent range extension + if (start > from) + { + start = from; + } + if (end < to) + { + end = to; + } + } + for (int r = from; r <= to; r++) + { + if (r >= 0 && r < alw) + { + csel.addElement(r); + } + } + if (debug) + { + System.err.println("Range '" + cl + "' deparsed as [" + from + + "," + to + "]"); + } + } + else + { + System.err.println("ERROR: Invalid Range '" + cl + + "' deparsed as [" + from + "," + to + "]"); + } + } + else + { + int r = -1; + try + { + r = new Integer(cl).intValue(); + r--; + } catch (NumberFormatException ex) + { + if (cl.toLowerCase().equals("sequence")) + { + // we are in the dataset sequence's coordinate frame. + inseqpos = true; + } + else + { + System.err.println( + "ERROR: Couldn't parse integer from point selection element of column selection string '" + + cl + "'"); + return; + } + } + if (r >= 0 && r <= alw) + { + if (!seset) + { + start = r; + end = r; + seset = true; + } + else + { + // comment to prevent range extension + if (start > r) + { + start = r; + } + if (end < r) + { + end = r; + } + } + csel.addElement(r); + if (debug) + { + System.err.println("Point selection '" + cl + + "' deparsed as [" + r + "]"); + } + } + else + { + System.err.println("ERROR: Invalid Point selection '" + cl + + "' deparsed as [" + r + "]"); + } + } + } + } + if (seqsfound) + { + // we only propagate the selection when it was the null selection, or the + // given sequences were found in the alignment. + if (inseqpos && sel.getSize() > 0) + { + // assume first sequence provides reference frame ? + SequenceI rs = sel.getSequenceAt(0); + start = rs.findIndex(start); + end = rs.findIndex(end); + List cs = new ArrayList<>(csel.getSelected()); + csel.clear(); + for (Integer selectedCol : cs) + { + csel.addElement(rs.findIndex(selectedCol)); + } + } + sel.setStartRes(start); + sel.setEndRes(end); + Jalview.execRunnable(new Runnable() + { + @Override + public void run() + { + ((AlignFrame) alf).select(sel, csel, ((AlignFrame) alf) + .getCurrentView().getAlignment().getHiddenColumns()); + } + }); + } + } + + public String getAlignmentOrderFrom(AlignFrameI alf, String sep) + { + AlignmentI alorder = ((AlignFrame) alf).getViewport().getAlignment(); + String[] order = new String[alorder.getHeight()]; + for (int i = 0; i < order.length; i++) + { + order[i] = alorder.getSequenceAt(i).getName(); + } + return arrayToSeparatorList(order, sep); + } + + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, String suffix) + { + try + { + AlignViewport vp = ((AlignFrame) alf).getViewport(); + FileFormatI theFormat = FileFormats.getInstance().forName(format); + boolean seqlimits = (suffix == null + || suffix.equalsIgnoreCase("true")); + if (vp.getSelectionGroup() != null) + { + // JBPNote: getSelectionAsNewSequence behaviour has changed - this + // method now returns a full copy of sequence data + // TODO consider using getSequenceSelection instead here + String reply = new AppletFormatAdapter().formatSequences(theFormat, + new Alignment(vp.getSelectionAsNewSequence()), + seqlimits); + return reply; + } + } catch (IllegalArgumentException ex) + { + ex.printStackTrace(); + return "Error retrieving alignment, possibly invalid format specifier: " + + format; + } + return ""; + } + + public String orderAlignmentBy(AlignFrameI alf, String order, + String undoName, String sep) + { + if (sep == null || sep.length() == 0) + { + sep = separator; + } + String[] ids = JalviewAppLoader.separatorListToArray(order, sep); + SequenceI[] sqs = null; + if (ids != null && ids.length > 0) + { + jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( + ((AlignFrame) alf).getViewport().getAlignment() + .getSequencesArray()); + int s = 0; + sqs = new SequenceI[ids.length]; + for (int i = 0; i < ids.length; i++) + { + if (ids[i].trim().length() == 0) + { + continue; + } + SequenceI sq = matcher.findIdMatch(ids[i]); + if (sq != null) + { + sqs[s++] = sq; + } + } + if (s > 0) + { + SequenceI[] sqq = new SequenceI[s]; + System.arraycopy(sqs, 0, sqq, 0, s); + sqs = sqq; + } + else + { + sqs = null; + } + } + if (sqs == null) + { + return ""; + } + final AlignmentOrder aorder = new AlignmentOrder(sqs); + + if (undoName != null && undoName.trim().length() == 0) + { + undoName = null; + } + final String _undoName = undoName; + // TODO: deal with synchronization here: cannot raise any events until after + // this has returned. + return ((AlignFrame) alf).sortBy(aorder, _undoName) ? "true" : ""; + } + + public String getAlignmentFrom(AlignFrameI alf, String format, + String suffix) + { + try + { + boolean seqlimits = (suffix == null + || suffix.equalsIgnoreCase("true")); + + FileFormatI theFormat = FileFormats.getInstance().forName(format); + String reply = new AppletFormatAdapter().formatSequences(theFormat, + ((AlignFrame) alf).getViewport().getAlignment(), seqlimits); + return reply; + } catch (IllegalArgumentException ex) + { + ex.printStackTrace(); + return "Error retrieving alignment, possibly invalid format specifier: " + + format; + } + } + + public void loadAnnotationFrom(AlignFrameI alf, String annotation) + { + if (new AnnotationFile().annotateAlignmentView( + ((AlignFrame) alf).getViewport(), annotation, + DataSourceType.PASTE)) + { + ((AlignFrame) alf).alignPanel.fontChanged(); + ((AlignFrame) alf).alignPanel.setScrollValues(0, 0); + } + else + { + ((AlignFrame) alf).parseFeaturesFile(annotation, + DataSourceType.PASTE); + } + } + + public boolean loadFeaturesFrom(AlignFrameI alf, String features, + boolean autoenabledisplay) + { + boolean ret = ((AlignFrame) alf).parseFeaturesFile(features, + DataSourceType.PASTE); + if (!ret) + { + return false; + } + if (autoenabledisplay) + { + ((AlignFrame) alf).getViewport().setShowSequenceFeatures(true); + // this next was for a checkbox in JalviewLite + // ((AlignFrame) alf).getViewport().sequenceFeatures.setState(true); + } + return true; + } + + public String getFeaturesFrom(AlignFrameI alf, String format, + boolean includeNonpositionsFeatures, boolean includeComplement) + { + AlignFrame f = ((AlignFrame) alf); + + String features; + FeaturesFile formatter = new FeaturesFile(); + if (format.equalsIgnoreCase("Jalview")) + { + features = formatter.printJalviewFormat( + f.getViewport().getAlignment().getSequencesArray(), + f.alignPanel.getFeatureRenderer(), + includeNonpositionsFeatures, includeComplement); + } + else + { + features = formatter.printGffFormat( + f.getViewport().getAlignment().getSequencesArray(), + f.alignPanel.getFeatureRenderer(), + includeNonpositionsFeatures, includeComplement); + } + + if (features == null) + { + features = ""; + } + return features; + + } + + public String getAnnotationFrom(AlignFrameI alf) + { + AlignFrame f = (AlignFrame) alf; + String annotation = new AnnotationFile() + .printAnnotationsForView(f.getViewport()); + return annotation; + } + + public AlignFrameI newViewFrom(AlignFrameI alf, String name) + { + return (AlignFrameI) ((AlignFrame) alf).newView(name, true); + } + + public String[] separatorListToArray(String list) + { + return separatorListToArray(list, separator); + } + + public Object[] getSelectionForListener(AlignFrameI currentFrame, + SequenceGroup seqsel, ColumnSelection colsel, + HiddenColumns hidden, SelectionSource source, Object alignFrame) + { + // System.err.println("Testing selection event relay to + // jsfunction:"+_listener); + String setid = ""; + AlignFrame src = (AlignFrame) alignFrame; + if (source != null) + { + if (source instanceof AlignViewport + && ((AlignFrame) currentFrame).getViewport() == source) + { + // should be valid if it just generated an event! + src = (AlignFrame) currentFrame; + + } + } + String[] seqs = new String[] {}; + String[] cols = new String[] {}; + int strt = 0, end = (src == null) ? -1 + : src.alignPanel.av.getAlignment().getWidth(); + if (seqsel != null && seqsel.getSize() > 0) + { + seqs = new String[seqsel.getSize()]; + for (int i = 0; i < seqs.length; i++) + { + seqs[i] = seqsel.getSequenceAt(i).getName(); + } + if (strt < seqsel.getStartRes()) + { + strt = seqsel.getStartRes(); + } + if (end == -1 || end > seqsel.getEndRes()) + { + end = seqsel.getEndRes(); + } + } + if (colsel != null && !colsel.isEmpty()) + { + if (end == -1) + { + end = colsel.getMax() + 1; + } + cols = new String[colsel.getSelected().size()]; + for (int i = 0; i < cols.length; i++) + { + cols[i] = "" + (1 + colsel.getSelected().get(i).intValue()); + } + } + else + { + if (seqsel != null && seqsel.getSize() > 0) + { + // send a valid range, otherwise we send the empty selection + cols = new String[2]; + cols[0] = "" + (1 + strt) + "-" + (1 + end); + } + } + return new Object[] { src, setid, arrayToSeparatorList(seqs), + arrayToSeparatorList(cols) }; + } + +} \ No newline at end of file diff --git a/src/jalview/bin/JalviewJSApi.java b/src/jalview/bin/JalviewJSApi.java new file mode 100644 index 0000000..b1fed25 --- /dev/null +++ b/src/jalview/bin/JalviewJSApi.java @@ -0,0 +1,52 @@ +package jalview.bin; + +import jalview.gui.AlignFrame; +import jalview.javascript.JalviewLiteJsApi; + +/** + * JAL-3369 JalviewJS API BH 2019.07.17 + * + * @author hansonr + * + */ +public interface JalviewJSApi extends JalviewLiteJsApi +{ + + void showOverview(); + + /** + * process commandline arguments after the JavaScript application has started + * + * @param args + * @return + */ + Object parseArguments(String[] args); + + + /** + * Open a new Tree panel on the desktop statically. Params are standard (not + * set by Groovy). No dialog is opened. + * + * @param af + * may be null + * @param treeType + * @param modelName + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + public Object openTreePanel(AlignFrame af, String treeType, + String modelName); + + /** + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * + * @param af + * may be null + * @param modelName + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + public Object openPcaPanel(AlignFrame af, String modelName); + +} diff --git a/src/jalview/bin/JalviewLite.java b/src/jalview/bin/JalviewLite.java index e7f2a53..75b0add 100644 --- a/src/jalview/bin/JalviewLite.java +++ b/src/jalview/bin/JalviewLite.java @@ -21,6 +21,9 @@ package jalview.bin; import jalview.analysis.AlignmentUtils; +import jalview.api.AlignFrameI; +import jalview.api.AlignViewportI; +import jalview.api.JalviewApp; import jalview.api.StructureSelectionManagerProvider; import jalview.appletgui.AlignFrame; import jalview.appletgui.AlignViewport; @@ -31,8 +34,8 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; -import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.io.AnnotationFile; @@ -42,18 +45,19 @@ import jalview.io.FileFormatI; import jalview.io.FileFormats; import jalview.io.FileParse; import jalview.io.IdentifyFile; -import jalview.io.JPredFile; -import jalview.io.JnetAnnotationMaker; import jalview.io.NewickFile; import jalview.javascript.JSFunctionExec; import jalview.javascript.JalviewLiteJsApi; import jalview.javascript.JsCallBack; import jalview.javascript.MouseOverStructureListener; +import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.structure.SelectionListener; +import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; +import jalview.structure.VamsasSource; import jalview.util.ColorUtils; -import jalview.util.HttpUtils; import jalview.util.MessageManager; +import jalview.viewmodel.AlignmentViewport; import java.applet.Applet; import java.awt.Button; @@ -73,7 +77,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; -import java.util.StringTokenizer; import java.util.Vector; import netscape.javascript.JSObject; @@ -84,10 +87,16 @@ import netscape.javascript.JSObject; * @author $author$ * @version $Revision: 1.92 $ */ +@SuppressWarnings("serial") public class JalviewLite extends Applet - implements StructureSelectionManagerProvider, JalviewLiteJsApi + implements StructureSelectionManagerProvider, JalviewLiteJsApi, + JalviewApp { + public JalviewLite() + { + appLoader = new JalviewAppLoader(debug); + } private static final String TRUE = "true"; private static final String FALSE = "false"; @@ -97,6 +106,12 @@ public class JalviewLite extends Applet return StructureSelectionManager.getStructureSelectionManager(this); } + @Override + public StructureSelectionManagerProvider getStructureSelectionManagerProvider() + { + return this; + } + // ///////////////////////////////////////// // The following public methods may be called // externally, eg via javascript in HTML page @@ -130,7 +145,7 @@ public class JalviewLite extends Applet * .AlignFrame) */ @Override - public String getSelectedSequencesFrom(AlignFrame alf) + public String getSelectedSequencesFrom(AlignFrameI alf) { return getSelectedSequencesFrom(alf, separator); // ""+0x00AC); } @@ -143,17 +158,18 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public String getSelectedSequencesFrom(AlignFrame alf, String sep) + public String getSelectedSequencesFrom(AlignFrameI alf, String sep) { StringBuffer result = new StringBuffer(""); if (sep == null || sep.length() == 0) { sep = separator; // "+0x00AC; } - if (alf.viewport.getSelectionGroup() != null) + if (((AlignFrame) alf).viewport.getSelectionGroup() != null) { - SequenceI[] seqs = alf.viewport.getSelectionGroup() - .getSequencesInOrder(alf.viewport.getAlignment()); + SequenceI[] seqs = ((AlignFrame) alf).viewport.getSelectionGroup() + .getSequencesInOrder( + ((AlignFrame) alf).viewport.getAlignment()); for (int i = 0; i < seqs.length; i++) { @@ -186,19 +202,19 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public void highlightIn(final AlignFrame alf, final String sequenceId, + public void highlightIn(final AlignFrameI alf, final String sequenceId, final String position, final String alignedPosition) { // TODO: could try to highlight in all alignments if alf==null jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( - alf.viewport.getAlignment().getSequencesArray()); + ((AlignFrame) alf).viewport.getAlignment().getSequencesArray()); final SequenceI sq = matcher.findIdMatch(sequenceId); if (sq != null) { int apos = -1; try { - apos = Integer.valueOf(position).intValue(); + apos = new Integer(position).intValue(); apos--; } catch (NumberFormatException ex) { @@ -266,7 +282,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String) */ @Override - public void selectIn(AlignFrame alf, String sequenceIds, String columns) + public void selectIn(AlignFrameI alf, String sequenceIds, String columns) { selectIn(alf, sequenceIds, columns, separator); } @@ -278,7 +294,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public void selectIn(final AlignFrame alf, String sequenceIds, + public void selectIn(final AlignFrameI alf, String sequenceIds, String columns, String sep) { if (sep == null || sep.length() == 0) @@ -294,13 +310,13 @@ public class JalviewLite extends Applet } } // deparse fields - String[] ids = separatorListToArray(sequenceIds, sep); - String[] cols = separatorListToArray(columns, sep); + String[] ids = JalviewAppLoader.separatorListToArray(sequenceIds, sep); + String[] cols = JalviewAppLoader.separatorListToArray(columns, sep); final SequenceGroup sel = new SequenceGroup(); final ColumnSelection csel = new ColumnSelection(); - AlignmentI al = alf.viewport.getAlignment(); + AlignmentI al = ((AlignFrame) alf).viewport.getAlignment(); jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( - alf.viewport.getAlignment().getSequencesArray()); + ((AlignFrame) alf).viewport.getAlignment().getSequencesArray()); int start = 0, end = al.getWidth(), alw = al.getWidth(); boolean seqsfound = true; if (ids != null && ids.length > 0) @@ -337,7 +353,7 @@ public class JalviewLite extends Applet int from = -1, to = -1; try { - from = Integer.valueOf(cl.substring(0, p)).intValue(); + from = new Integer(cl.substring(0, p)).intValue(); from--; } catch (NumberFormatException ex) { @@ -348,7 +364,7 @@ public class JalviewLite extends Applet } try { - to = Integer.valueOf(cl.substring(p + 1)).intValue(); + to = new Integer(cl.substring(p + 1)).intValue(); to--; } catch (NumberFormatException ex) { @@ -408,7 +424,7 @@ public class JalviewLite extends Applet int r = -1; try { - r = Integer.valueOf(cl).intValue(); + r = new Integer(cl).intValue(); r--; } catch (NumberFormatException ex) { @@ -484,8 +500,8 @@ public class JalviewLite extends Applet @Override public void run() { - alf.select(sel, csel, - alf.getAlignViewport().getAlignment().getHiddenColumns()); + ((AlignFrame) alf).select(sel, csel, ((AlignFrame) alf) + .getAlignViewport().getAlignment().getHiddenColumns()); } }); } @@ -514,20 +530,21 @@ public class JalviewLite extends Applet * .appletgui.AlignFrame, java.lang.String, java.lang.String) */ @Override - public String getSelectedSequencesAsAlignmentFrom(AlignFrame alf, + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, String format, String suffix) { try { FileFormatI theFormat = FileFormats.getInstance().forName(format); boolean seqlimits = suffix.equalsIgnoreCase(TRUE); - if (alf.viewport.getSelectionGroup() != null) + if (((AlignFrame) alf).viewport.getSelectionGroup() != null) { // JBPNote: getSelectionAsNewSequence behaviour has changed - this // method now returns a full copy of sequence data // TODO consider using getSequenceSelection instead here String reply = new AppletFormatAdapter().formatSequences(theFormat, - new Alignment(alf.viewport.getSelectionAsNewSequence()), + new Alignment(((AlignFrame) alf).viewport + .getSelectionAsNewSequence()), seqlimits); return reply; } @@ -559,7 +576,7 @@ public class JalviewLite extends Applet * ) */ @Override - public String getAlignmentOrderFrom(AlignFrame alf) + public String getAlignmentOrderFrom(AlignFrameI alf) { return getAlignmentOrderFrom(alf, separator); } @@ -572,9 +589,10 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public String getAlignmentOrderFrom(AlignFrame alf, String sep) + public String getAlignmentOrderFrom(AlignFrameI alf, String sep) { - AlignmentI alorder = alf.getAlignViewport().getAlignment(); + AlignmentI alorder = ((AlignFrame) alf).getAlignViewport() + .getAlignment(); String[] order = new String[alorder.getHeight()]; for (int i = 0; i < order.length; i++) { @@ -615,15 +633,16 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public String orderAlignmentBy(AlignFrame alf, String order, + public String orderAlignmentBy(AlignFrameI alf, String order, String undoName, String sep) { - String[] ids = separatorListToArray(order, sep); + String[] ids = JalviewAppLoader.separatorListToArray(order, sep); SequenceI[] sqs = null; if (ids != null && ids.length > 0) { jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher( - alf.viewport.getAlignment().getSequencesArray()); + ((AlignFrame) alf).viewport.getAlignment() + .getSequencesArray()); int s = 0; sqs = new SequenceI[ids.length]; for (int i = 0; i < ids.length; i++) @@ -663,7 +682,7 @@ public class JalviewLite extends Applet final String _undoName = undoName; // TODO: deal with synchronization here: cannot raise any events until after // this has returned. - return alf.sortBy(aorder, _undoName) ? TRUE : ""; + return ((AlignFrame) alf).sortBy(aorder, _undoName) ? TRUE : ""; } /* @@ -685,7 +704,7 @@ public class JalviewLite extends Applet * java.lang.String) */ @Override - public String getAlignmentFrom(AlignFrame alf, String format) + public String getAlignmentFrom(AlignFrameI alf, String format) { return getAlignmentFrom(alf, format, TRUE); } @@ -710,7 +729,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String) */ @Override - public String getAlignmentFrom(AlignFrame alf, String format, + public String getAlignmentFrom(AlignFrameI alf, String format, String suffix) { try @@ -719,7 +738,7 @@ public class JalviewLite extends Applet FileFormatI theFormat = FileFormats.getInstance().forName(format); String reply = new AppletFormatAdapter().formatSequences(theFormat, - alf.viewport.getAlignment(), seqlimits); + ((AlignFrame) alf).viewport.getAlignment(), seqlimits); return reply; } catch (IllegalArgumentException ex) { @@ -748,17 +767,19 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public void loadAnnotationFrom(AlignFrame alf, String annotation) + public void loadAnnotationFrom(AlignFrameI alf, String annotation) { - if (new AnnotationFile().annotateAlignmentView(alf.getAlignViewport(), + if (new AnnotationFile().annotateAlignmentView( + ((AlignFrame) alf).getAlignViewport(), annotation, DataSourceType.PASTE)) { - alf.alignPanel.fontChanged(); - alf.alignPanel.setScrollValues(0, 0); + ((AlignFrame) alf).alignPanel.fontChanged(); + ((AlignFrame) alf).alignPanel.setScrollValues(0, 0); } else { - alf.parseFeaturesFile(annotation, DataSourceType.PASTE); + ((AlignFrame) alf).parseFeaturesFile(annotation, + DataSourceType.PASTE); } } @@ -781,10 +802,11 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public boolean loadFeaturesFrom(AlignFrame alf, String features, + public boolean loadFeaturesFrom(AlignFrameI alf, String features, boolean autoenabledisplay) { - return alf.parseFeaturesFile(features, DataSourceType.PASTE, + return ((AlignFrame) alf).parseFeaturesFile(features, + DataSourceType.PASTE, autoenabledisplay); } @@ -807,9 +829,9 @@ public class JalviewLite extends Applet * java.lang.String) */ @Override - public String getFeaturesFrom(AlignFrame alf, String format) + public String getFeaturesFrom(AlignFrameI alf, String format) { - return alf.outputFeatures(false, format); + return ((AlignFrame) alf).outputFeatures(false, format); } /* @@ -831,9 +853,9 @@ public class JalviewLite extends Applet * ) */ @Override - public String getAnnotationFrom(AlignFrame alf) + public String getAnnotationFrom(AlignFrameI alf) { - return alf.outputAnnotations(false); + return ((AlignFrame) alf).outputAnnotations(false); } /* @@ -864,9 +886,9 @@ public class JalviewLite extends Applet * @see jalview.bin.JalviewLiteJsApi#newViewFrom(jalview.appletgui.AlignFrame) */ @Override - public AlignFrame newViewFrom(AlignFrame alf) + public AlignFrame newViewFrom(AlignFrameI alf) { - return alf.newView(null); + return ((AlignFrame) alf).newView(null); } /* @@ -876,9 +898,9 @@ public class JalviewLite extends Applet * java.lang.String) */ @Override - public AlignFrame newViewFrom(AlignFrame alf, String name) + public AlignFrame newViewFrom(AlignFrameI alf, String name) { - return alf.newView(name); + return ((AlignFrame) alf).newView(name); } /* @@ -930,7 +952,7 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public void setMouseoverListener(AlignFrame af, String listener) + public void setMouseoverListener(AlignFrameI af, String listener) { if (listener != null) { @@ -943,7 +965,7 @@ public class JalviewLite extends Applet } } jalview.javascript.MouseOverListener mol = new jalview.javascript.MouseOverListener( - this, af, listener); + this, (AlignFrame) af, listener, debug); javascriptListeners.addElement(mol); StructureSelectionManager.getStructureSelectionManager(this) .addStructureViewerListener(mol); @@ -952,7 +974,8 @@ public class JalviewLite extends Applet System.err.println("Added a mouseover listener for " + ((af == null) ? "All frames" : "Just views for " - + af.getAlignViewport().getSequenceSetId())); + + ((AlignFrame) af).getAlignViewport() + .getSequenceSetId())); System.err.println("There are now " + javascriptListeners.size() + " listeners in total."); } @@ -977,7 +1000,7 @@ public class JalviewLite extends Applet * , java.lang.String) */ @Override - public void setSelectionListener(AlignFrame af, String listener) + public void setSelectionListener(AlignFrameI af, String listener) { if (listener != null) { @@ -990,7 +1013,7 @@ public class JalviewLite extends Applet } } jalview.javascript.JsSelectionSender mol = new jalview.javascript.JsSelectionSender( - this, af, listener); + this, (AlignFrame) af, listener, debug); javascriptListeners.addElement(mol); StructureSelectionManager.getStructureSelectionManager(this) .addSelectionListener(mol); @@ -999,7 +1022,8 @@ public class JalviewLite extends Applet System.err.println("Added a selection listener for " + ((af == null) ? "All frames" : "Just views for " - + af.getAlignViewport().getSequenceSetId())); + + ((AlignFrame) af).getAlignViewport() + .getSequenceSetId())); System.err.println("There are now " + javascriptListeners.size() + " listeners in total."); } @@ -1030,7 +1054,7 @@ public class JalviewLite extends Applet } } MouseOverStructureListener mol = new MouseOverStructureListener(this, - listener, separatorListToArray(modelSet)); + listener, separatorListToArray(modelSet), debug); javascriptListeners.addElement(mol); StructureSelectionManager.getStructureSelectionManager(this) .addStructureViewerListener(mol); @@ -1051,7 +1075,7 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public void removeJavascriptListener(AlignFrame af, String listener) + public void removeJavascriptListener(AlignFrameI af, String listener) { if (listener != null) { @@ -1146,11 +1170,10 @@ public class JalviewLite extends Applet } if (jsFunctionExec != null) { - jsFunctionExec.stopQueue(); - jsFunctionExec.jvlite = null; + jsFunctionExec.tidyUp(); + jsFunctionExec = null; } initialAlignFrame = null; - jsFunctionExec = null; javascriptListeners = null; StructureSelectionManager.release(this); } @@ -1176,7 +1199,7 @@ public class JalviewLite extends Applet try { StructureSelectionManager.getStructureSelectionManager(me) - .mouseOverStructure(Integer.valueOf(pdbResNum).intValue(), + .mouseOverStructure(new Integer(pdbResNum).intValue(), chain, pdbfile); if (debug) { @@ -1202,7 +1225,7 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String) */ @Override - public void scrollViewToIn(final AlignFrame alf, final String topRow, + public void scrollViewToIn(final AlignFrameI alf, final String topRow, final String leftHandColumn) { java.awt.EventQueue.invokeLater(new Runnable() @@ -1212,8 +1235,8 @@ public class JalviewLite extends Applet { try { - alf.scrollTo(Integer.valueOf(topRow).intValue(), - Integer.valueOf(leftHandColumn).intValue()); + ((AlignFrame) alf).scrollTo(new Integer(topRow).intValue(), + new Integer(leftHandColumn).intValue()); } catch (Exception ex) { @@ -1234,7 +1257,7 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public void scrollViewToRowIn(final AlignFrame alf, final String topRow) + public void scrollViewToRowIn(final AlignFrameI alf, final String topRow) { java.awt.EventQueue.invokeLater(new Runnable() @@ -1244,7 +1267,7 @@ public class JalviewLite extends Applet { try { - alf.scrollToRow(Integer.valueOf(topRow).intValue()); + ((AlignFrame) alf).scrollToRow(new Integer(topRow).intValue()); } catch (Exception ex) { @@ -1265,7 +1288,7 @@ public class JalviewLite extends Applet * .AlignFrame, java.lang.String) */ @Override - public void scrollViewToColumnIn(final AlignFrame alf, + public void scrollViewToColumnIn(final AlignFrameI alf, final String leftHandColumn) { java.awt.EventQueue.invokeLater(new Runnable() @@ -1276,7 +1299,8 @@ public class JalviewLite extends Applet { try { - alf.scrollToColumn(Integer.valueOf(leftHandColumn).intValue()); + ((AlignFrame) alf) + .scrollToColumn(new Integer(leftHandColumn).intValue()); } catch (Exception ex) { @@ -1322,9 +1346,9 @@ public class JalviewLite extends Applet boolean embedded = false; - private boolean checkForJmol = true; + boolean checkForJmol = true; - private boolean checkedForJmol = false; // ensure we don't check for jmol + boolean checkedForJmol = false; // ensure we don't check for jmol // every time the app is re-inited @@ -1338,6 +1362,10 @@ public class JalviewLite extends Applet */ public boolean useXtrnalSviewer = false; + public JalviewAppLoader appLoader; + + public AlignFrame loaderFrame; + public static boolean debug = false; static String builddate = null, version = null, installation = null; @@ -1470,6 +1498,9 @@ public class JalviewLite extends Applet .getString("error.invalid_separator_parameter")); } } + + // Background color + int r = 255; int g = 255; int b = 255; @@ -1489,68 +1520,33 @@ public class JalviewLite extends Applet b = 255; } } + setBackground(new Color(r, g, b)); + param = getParameter("label"); if (param != null) { launcher.setLabel(param); } - setBackground(new Color(r, g, b)); - file = getParameter("file"); if (file == null) { - // Maybe the sequences are added as parameters - StringBuffer data = new StringBuffer("PASTE"); - int i = 1; - while ((file = getParameter("sequence" + i)) != null) - { - data.append(file.toString() + "\n"); - i++; - } - if (data.length() > 5) - { - file = data.toString(); - } + file = appLoader.getPastedSequence(this); } if (getDefaultParameter("enableSplitFrame", true)) { file2 = getParameter("file2"); } - embedded = TRUE.equalsIgnoreCase(getParameter("embedded")); + embedded = (TRUE.equalsIgnoreCase(getParameter("embedded")) + || file != null + && FALSE.equalsIgnoreCase(getParameter("showbutton"))); if (embedded) { - LoadingThread loader = new LoadingThread(file, file2, this); - loader.start(); - } - else if (file != null) - { - /* - * Start the applet immediately or show a button to start it - */ - if (FALSE.equalsIgnoreCase(getParameter("showbutton"))) - { - LoadingThread loader = new LoadingThread(file, file2, this); - loader.start(); - } - else - { - add(launcher); - launcher.addActionListener(new java.awt.event.ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - LoadingThread loader = new LoadingThread(file, file2, - JalviewLite.this); - loader.start(); - } - }); - } + startLoading(); } - else + else if (file == null) { // jalview initialisation with no alignment. loadAlignment() method can // still be called to open new alignments. @@ -1558,6 +1554,24 @@ public class JalviewLite extends Applet fileFound = false; callInitCallback(); } + else + { + add(launcher); + launcher.addActionListener(new java.awt.event.ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + startLoading(); + } + }); + } + } + + protected void startLoading() + { + LoadingThread loader = new LoadingThread(file, file2, this); + loader.start(); } private void initLiveConnect() @@ -1597,7 +1611,7 @@ public class JalviewLite extends Applet } } - private void callInitCallback() + void callInitCallback() { String initjscallback = getParameter("oninit"); if (initjscallback == null) @@ -1623,7 +1637,7 @@ public class JalviewLite extends Applet try { // do onInit with the JS executor thread - new JSFunctionExec(this).executeJavascriptFunction(true, + new JSFunctionExec(this, debug).executeJavascriptFunction(true, initjscallback, null, "Calling oninit callback '" + initjscallback + "'."); } catch (Exception e) @@ -1836,7 +1850,7 @@ public class JalviewLite extends Applet JalviewLite applet; - private void dbgMsg(String msg) + public void dbgMsg(String msg) { if (JalviewLite.debug) { @@ -1853,67 +1867,10 @@ public class JalviewLite extends Applet */ public String resolveFileProtocol(String path) { - /* - * is it paste data? - */ - if (path.startsWith("PASTE")) - { - protocol = DataSourceType.PASTE; - return path.substring(5); - } - /* - * is it a URL? - */ - if (path.indexOf("://") != -1) - { - protocol = DataSourceType.URL; - return path; - } - - /* - * try relative to document root - */ - URL documentBase = getDocumentBase(); - String withDocBase = resolveUrlForLocalOrAbsolute(path, documentBase); - if (HttpUtils.isValidUrl(withDocBase)) - { - if (debug) - { - System.err.println("Prepended document base '" + documentBase - + "' to make: '" + withDocBase + "'"); - } - protocol = DataSourceType.URL; - return withDocBase; - } - - /* - * try relative to codebase (if different to document base) - */ - URL codeBase = getCodeBase(); - String withCodeBase = applet.resolveUrlForLocalOrAbsolute(path, - codeBase); - if (!withCodeBase.equals(withDocBase) - && HttpUtils.isValidUrl(withCodeBase)) - { - protocol = DataSourceType.URL; - if (debug) - { - System.err.println("Prepended codebase '" + codeBase - + "' to make: '" + withCodeBase + "'"); - } - return withCodeBase; - } - - /* - * try locating by classloader; try this last so files in the directory - * are resolved using document base - */ - if (inArchive(path)) - { - protocol = DataSourceType.CLASSLOADER; - } - return path; + String[] ret = new String[] { path }; + protocol = JalviewAppLoader.resolveFileProtocol(applet, ret); + return ret[0]; } public LoadingThread(String file, String file2, JalviewLite _applet) @@ -1958,25 +1915,16 @@ public class JalviewLite extends Applet if (newAlignFrame != null) { addToDisplay(newAlignFrame, newAlignFrame2); - loadTree(newAlignFrame); - - loadScoreFile(newAlignFrame); - - loadFeatures(newAlignFrame); - - loadAnnotations(newAlignFrame); - - loadJnetFile(newAlignFrame); - - loadPdbFiles(newAlignFrame); + applet.loaderFrame = newAlignFrame; + appLoader.load(applet); } else { fileFound = false; applet.remove(launcher); applet.repaint(); + callInitCallback(); } - callInitCallback(); } /** @@ -2089,392 +2037,6 @@ public class JalviewLite extends Applet return null; } - /** - * Load PDBFiles if any specified by parameter(s). Returns true if loaded, - * else false. - * - * @param alignFrame - * @return - */ - protected boolean loadPdbFiles(AlignFrame alignFrame) - { - boolean result = false; - /* - * Undocumented for 2.6 - - * related to JAL-434 - */ - - applet.setAlignPdbStructures( - getDefaultParameter("alignpdbfiles", false)); - /* - * - * - * - * - * - */ - - int pdbFileCount = 0; - // Accumulate pdbs here if they are heading for the same view (if - // alignPdbStructures is true) - Vector pdbs = new Vector(); - // create a lazy matcher if we're asked to - jalview.analysis.SequenceIdMatcher matcher = (applet - .getDefaultParameter("relaxedidmatch", false)) - ? new jalview.analysis.SequenceIdMatcher( - alignFrame.getAlignViewport().getAlignment() - .getSequencesArray()) - : null; - - String param; - do - { - if (pdbFileCount > 0) - { - param = applet.getParameter("PDBFILE" + pdbFileCount); - } - else - { - param = applet.getParameter("PDBFILE"); - } - - if (param != null) - { - PDBEntry pdb = new PDBEntry(); - - String seqstring; - SequenceI[] seqs = null; - String[] chains = null; - - StringTokenizer st = new StringTokenizer(param, " "); - - if (st.countTokens() < 2) - { - String sequence = applet.getParameter("PDBSEQ"); - if (sequence != null) - { - seqs = new SequenceI[] { matcher == null - ? (Sequence) alignFrame.getAlignViewport() - .getAlignment().findName(sequence) - : matcher.findIdMatch(sequence) }; - } - - } - else - { - param = st.nextToken(); - List tmp = new ArrayList<>(); - List tmp2 = new ArrayList<>(); - - while (st.hasMoreTokens()) - { - seqstring = st.nextToken(); - StringTokenizer st2 = new StringTokenizer(seqstring, "="); - if (st2.countTokens() > 1) - { - // This is the chain - tmp2.add(st2.nextToken()); - seqstring = st2.nextToken(); - } - tmp.add(matcher == null - ? (Sequence) alignFrame.getAlignViewport() - .getAlignment().findName(seqstring) - : matcher.findIdMatch(seqstring)); - } - - seqs = tmp.toArray(new SequenceI[tmp.size()]); - if (tmp2.size() == tmp.size()) - { - chains = tmp2.toArray(new String[tmp2.size()]); - } - } - param = resolveFileProtocol(param); - // TODO check JAL-357 for files in a jar (CLASSLOADER) - pdb.setFile(param); - - if (seqs != null) - { - for (int i = 0; i < seqs.length; i++) - { - if (seqs[i] != null) - { - ((Sequence) seqs[i]).addPDBId(pdb); - StructureSelectionManager - .getStructureSelectionManager(applet) - .registerPDBEntry(pdb); - } - else - { - if (JalviewLite.debug) - { - // this may not really be a problem but we give a warning - // anyway - System.err.println( - "Warning: Possible input parsing error: Null sequence for attachment of PDB (sequence " - + i + ")"); - } - } - } - - if (!alignPdbStructures) - { - alignFrame.newStructureView(applet, pdb, seqs, chains, - protocol); - } - else - { - pdbs.addElement(new Object[] { pdb, seqs, chains, protocol }); - } - } - } - - pdbFileCount++; - } while (param != null || pdbFileCount < 10); - if (pdbs.size() > 0) - { - SequenceI[][] seqs = new SequenceI[pdbs.size()][]; - PDBEntry[] pdb = new PDBEntry[pdbs.size()]; - String[][] chains = new String[pdbs.size()][]; - String[] protocols = new String[pdbs.size()]; - for (int pdbsi = 0, pdbsiSize = pdbs - .size(); pdbsi < pdbsiSize; pdbsi++) - { - Object[] o = (Object[]) pdbs.elementAt(pdbsi); - pdb[pdbsi] = (PDBEntry) o[0]; - seqs[pdbsi] = (SequenceI[]) o[1]; - chains[pdbsi] = (String[]) o[2]; - protocols[pdbsi] = (String) o[3]; - } - alignFrame.alignedStructureView(applet, pdb, seqs, chains, - protocols); - result = true; - } - return result; - } - - /** - * Load in a Jnetfile if specified by parameter. Returns true if loaded, - * else false. - * - * @param alignFrame - * @return - */ - protected boolean loadJnetFile(AlignFrame alignFrame) - { - boolean result = false; - String param = applet.getParameter("jnetfile"); - if (param == null) - { - // jnet became jpred around 2016 - param = applet.getParameter("jpredfile"); - } - if (param != null) - { - try - { - param = resolveFileProtocol(param); - JPredFile predictions = new JPredFile(param, protocol); - JnetAnnotationMaker.add_annotation(predictions, - alignFrame.viewport.getAlignment(), 0, false); - // false == do not add sequence profile from concise output - - alignFrame.viewport.getAlignment().setupJPredAlignment(); - - alignFrame.alignPanel.fontChanged(); - alignFrame.alignPanel.setScrollValues(0, 0); - result = true; - } catch (Exception ex) - { - ex.printStackTrace(); - } - } - return result; - } - - /** - * Load annotations if specified by parameter. Returns true if loaded, else - * false. - * - * @param alignFrame - * @return - */ - protected boolean loadAnnotations(AlignFrame alignFrame) - { - boolean result = false; - String param = applet.getParameter("annotations"); - if (param != null) - { - param = resolveFileProtocol(param); - - if (new AnnotationFile().annotateAlignmentView(alignFrame.viewport, - param, protocol)) - { - alignFrame.alignPanel.fontChanged(); - alignFrame.alignPanel.setScrollValues(0, 0); - result = true; - } - else - { - System.err.println( - "Annotations were not added from annotation file '" - + param + "'"); - } - } - return result; - } - - /** - * Load features file and view settings as specified by parameters. Returns - * true if features were loaded, else false. - * - * @param alignFrame - * @return - */ - protected boolean loadFeatures(AlignFrame alignFrame) - { - boolean result = false; - // /////////////////////////// - // modify display of features - // we do this before any features have been loaded, ensuring any hidden - // groups are hidden when features first displayed - // - // hide specific groups - // - String param = applet.getParameter("hidefeaturegroups"); - if (param != null) - { - alignFrame.setFeatureGroupState(separatorListToArray(param), false); - // applet.setFeatureGroupStateOn(newAlignFrame, param, false); - } - // show specific groups - param = applet.getParameter("showfeaturegroups"); - if (param != null) - { - alignFrame.setFeatureGroupState(separatorListToArray(param), true); - // applet.setFeatureGroupStateOn(newAlignFrame, param, true); - } - // and now load features - param = applet.getParameter("features"); - if (param != null) - { - param = resolveFileProtocol(param); - - result = alignFrame.parseFeaturesFile(param, protocol); - } - - param = applet.getParameter("showFeatureSettings"); - if (param != null && param.equalsIgnoreCase(TRUE)) - { - alignFrame.viewport.setShowSequenceFeatures(true); - new FeatureSettings(alignFrame.alignPanel); - } - return result; - } - - /** - * Load a score file if specified by parameter. Returns true if file was - * loaded, else false. - * - * @param alignFrame - */ - protected boolean loadScoreFile(AlignFrame alignFrame) - { - boolean result = false; - String sScoreFile = applet.getParameter("scoreFile"); - if (sScoreFile != null && !"".equals(sScoreFile)) - { - try - { - if (debug) - { - System.err.println( - "Attempting to load T-COFFEE score file from the scoreFile parameter"); - } - result = alignFrame.loadScoreFile(sScoreFile); - if (!result) - { - System.err.println( - "Failed to parse T-COFFEE parameter as a valid score file ('" - + sScoreFile + "')"); - } - } catch (Exception e) - { - System.err.printf("Cannot read score file: '%s'. Cause: %s \n", - sScoreFile, e.getMessage()); - } - } - return result; - } - - /** - * Load a tree for the alignment if specified by parameter. Returns true if - * a tree was loaded, else false. - * - * @param alignFrame - * @return - */ - protected boolean loadTree(AlignFrame alignFrame) - { - boolean result = false; - String treeFile = applet.getParameter("tree"); - if (treeFile == null) - { - treeFile = applet.getParameter("treeFile"); - } - - if (treeFile != null) - { - try - { - treeFile = resolveFileProtocol(treeFile); - NewickFile fin = new NewickFile(treeFile, protocol); - fin.parse(); - - if (fin.getTree() != null) - { - alignFrame.loadTree(fin, treeFile); - result = true; - dbgMsg("Successfully imported tree."); - } - else - { - dbgMsg("Tree parameter did not resolve to a valid tree."); - } - } catch (Exception ex) - { - ex.printStackTrace(); - } - } - return result; - } - - /** - * Discovers whether the given file is in the Applet Archive - * - * @param f - * String - * @return boolean - */ - boolean inArchive(String f) - { - // This might throw a security exception in certain browsers - // Netscape Communicator for instance. - try - { - boolean rtn = (getClass().getResourceAsStream("/" + f) != null); - if (debug) - { - System.err.println("Resource '" + f + "' was " - + (rtn ? "" : "not ") + "located by classloader."); - } - return rtn; - } catch (Exception ex) - { - System.out.println("Exception checking resources: " + f + " " + ex); - return false; - } - } } /** @@ -2507,7 +2069,7 @@ public class JalviewLite extends Applet /** * set to enable the URL based javascript execution mechanism */ - public boolean jsfallbackEnabled = false; + private boolean jsfallbackEnabled = false; /** * parse the string into a list @@ -2515,66 +2077,10 @@ public class JalviewLite extends Applet * @param list * @return elements separated by separator */ + @Override public String[] separatorListToArray(String list) { - return separatorListToArray(list, separator); - } - - /** - * parse the string into a list - * - * @param list - * @param separator - * @return elements separated by separator - */ - public static String[] separatorListToArray(String list, String separator) - { - // TODO use StringUtils version (slightly different...) - int seplen = separator.length(); - if (list == null || list.equals("") || list.equals(separator)) - { - return null; - } - java.util.Vector jv = new Vector(); - int cp = 0, pos; - while ((pos = list.indexOf(separator, cp)) > cp) - { - jv.addElement(list.substring(cp, pos)); - cp = pos + seplen; - } - if (cp < list.length()) - { - String c = list.substring(cp); - if (!c.equals(separator)) - { - jv.addElement(c); - } - } - if (jv.size() > 0) - { - String[] v = new String[jv.size()]; - for (int i = 0; i < v.length; i++) - { - v[i] = (String) jv.elementAt(i); - } - jv.removeAllElements(); - if (debug) - { - System.err.println("Array from '" + separator - + "' separated List:\n" + v.length); - for (int i = 0; i < v.length; i++) - { - System.err.println("item " + i + " '" + v[i] + "'"); - } - } - return v; - } - if (debug) - { - System.err.println( - "Empty Array from '" + separator + "' separated List"); - } - return null; + return JalviewAppLoader.separatorListToArray(list, separator); } /** @@ -2583,49 +2089,10 @@ public class JalviewLite extends Applet * @param list * @return concatenated string */ + @Override public String arrayToSeparatorList(String[] list) { - return arrayToSeparatorList(list, separator); - } - - /** - * concatenate the list with separator - * - * @param list - * @param separator - * @return concatenated string - */ - public static String arrayToSeparatorList(String[] list, String separator) - { - // TODO use StringUtils version - StringBuffer v = new StringBuffer(); - if (list != null && list.length > 0) - { - for (int i = 0, iSize = list.length; i < iSize; i++) - { - if (list[i] != null) - { - if (i > 0) - { - v.append(separator); - } - v.append(list[i]); - } - } - if (debug) - { - System.err - .println("Returning '" + separator + "' separated List:\n"); - System.err.println(v); - } - return v.toString(); - } - if (debug) - { - System.err.println( - "Returning empty '" + separator + "' separated List\n"); - } - return "" + separator; + return JalviewAppLoader.arrayToSeparatorList(list, separator); } /* @@ -2649,9 +2116,10 @@ public class JalviewLite extends Applet * ) */ @Override - public String getFeatureGroupsOn(AlignFrame alf) + public String getFeatureGroupsOn(AlignFrameI alf) { - String lst = arrayToSeparatorList(alf.getFeatureGroups()); + String lst = arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroups()); return lst; } @@ -2675,9 +2143,10 @@ public class JalviewLite extends Applet * .AlignFrame, boolean) */ @Override - public String getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible) + public String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible) { - return arrayToSeparatorList(alf.getFeatureGroupsOfState(visible)); + return arrayToSeparatorList( + ((AlignFrame) alf).getFeatureGroupsOfState(visible)); } /* @@ -2687,7 +2156,7 @@ public class JalviewLite extends Applet * AlignFrame, java.lang.String, boolean) */ @Override - public void setFeatureGroupStateOn(final AlignFrame alf, + public void setFeatureGroupStateOn(final AlignFrameI alf, final String groups, boolean state) { final boolean st = state;// !(state==null || state.equals("") || @@ -2697,7 +2166,8 @@ public class JalviewLite extends Applet @Override public void run() { - alf.setFeatureGroupState(separatorListToArray(groups), st); + ((AlignFrame) alf) + .setFeatureGroupState(separatorListToArray(groups), st); } }); } @@ -2755,6 +2225,7 @@ public class JalviewLite extends Applet * the value to return otherwise * @return true or false */ + @Override public boolean getDefaultParameter(String name, boolean def) { String stn; @@ -2776,13 +2247,15 @@ public class JalviewLite extends Applet * java.lang.String, java.lang.String, java.lang.String) */ @Override - public boolean addPdbFile(AlignFrame alFrame, String sequenceId, + public boolean addPdbFile(AlignFrameI alFrame, String sequenceId, String pdbEntryString, String pdbFile) { - return alFrame.addPdbFile(sequenceId, pdbEntryString, pdbFile); + return ((AlignFrame) alFrame).addPdbFile(sequenceId, pdbEntryString, + pdbFile); } - protected void setAlignPdbStructures(boolean alignPdbStructures) + @Override + public void setAlignPdbStructures(boolean alignPdbStructures) { this.alignPdbStructures = alignPdbStructures; } @@ -2798,86 +2271,36 @@ public class JalviewLite extends Applet // callInitCallback(); } - private Hashtable jshashes = new Hashtable<>(); + private Hashtable jshashes = new Hashtable<>(); private Hashtable> jsmessages = new Hashtable<>(); - public void setJsMessageSet(String messageclass, String viewId, - String[] colcommands) - { - Hashtable msgset = jsmessages.get(messageclass); - if (msgset == null) - { - msgset = new Hashtable<>(); - jsmessages.put(messageclass, msgset); - } - msgset.put(viewId, colcommands); - long[] l = new long[colcommands.length]; - for (int i = 0; i < colcommands.length; i++) - { - l[i] = colcommands[i].hashCode(); - } - jshashes.put(messageclass + "|" + viewId, l); - } - /* - * (non-Javadoc) - * - * @see jalview.bin.JalviewLiteJsApi#getJsMessage(java.lang.String, - * java.lang.String) - */ @Override - public String getJsMessage(String messageclass, String viewId) + public Hashtable getJSHashes() { - Hashtable msgset = jsmessages.get(messageclass); - if (msgset != null) - { - String[] msgs = msgset.get(viewId); - if (msgs != null) - { - for (int i = 0; i < msgs.length; i++) - { - if (msgs[i] != null) - { - String m = msgs[i]; - msgs[i] = null; - return m; - } - } - } - } - return ""; + return jshashes; } - public boolean isJsMessageSetChanged(String string, String string2, - String[] colcommands) + @Override + public Hashtable> getJSMessages() { - long[] l = jshashes.get(string + "|" + string2); - if (l == null && colcommands != null) - { - return true; - } - for (int i = 0; i < colcommands.length; i++) - { - if (l[i] != colcommands[i].hashCode()) - { - return true; - } - } - return false; + return jsmessages; } - private Vector jsExecQueue = new Vector(); + private Vector jsExecQueue = new Vector<>(); - public Vector getJsExecQueue() + @Override + public Vector getJsExecQueue(JSFunctionExec exec) { + jsFunctionExec = exec; return jsExecQueue; } - public void setExecutor(JSFunctionExec jsFunctionExec2) - { - jsFunctionExec = jsFunctionExec2; - } + // public void setExecutor(JSFunctionExec jsFunctionExec2) + // { + // jsFunctionExec = jsFunctionExec2; + // } /** * return the given colour value parameter or the given default if parameter @@ -2914,66 +2337,6 @@ public class JalviewLite extends Applet } /** - * form a complete URL given a path to a resource and a reference location on - * the same server - * - * @param targetPath - * - an absolute path on the same server as localref or a document - * located relative to localref - * @param localref - * - a URL on the same server as url - * @return a complete URL for the resource located by url - */ - private String resolveUrlForLocalOrAbsolute(String targetPath, - URL localref) - { - String resolvedPath = ""; - if (targetPath.startsWith("/")) - { - String codebase = localref.toString(); - String localfile = localref.getFile(); - resolvedPath = codebase.substring(0, - codebase.length() - localfile.length()) + targetPath; - return resolvedPath; - } - - /* - * get URL path and strip off any trailing file e.g. - * www.jalview.org/examples/index.html#applets?a=b is trimmed to - * www.jalview.org/examples/ - */ - String urlPath = localref.toString(); - String directoryPath = urlPath; - int lastSeparator = directoryPath.lastIndexOf("/"); - if (lastSeparator > 0) - { - directoryPath = directoryPath.substring(0, lastSeparator + 1); - } - - if (targetPath.startsWith("/")) - { - /* - * construct absolute URL to a file on the server - this is not allowed? - */ - // String localfile = localref.getFile(); - // resolvedPath = urlPath.substring(0, - // urlPath.length() - localfile.length()) - // + targetPath; - resolvedPath = directoryPath + targetPath.substring(1); - } - else - { - resolvedPath = directoryPath + targetPath; - } - if (debug) - { - System.err.println( - "resolveUrlForLocalOrAbsolute returning " + resolvedPath); - } - return resolvedPath; - } - - /** * open a URL in the browser - resolving it according to relative refs and * coping with javascript: protocol if necessary. * @@ -2990,7 +2353,7 @@ public class JalviewLite extends Applet // form valid URL // Should really use docbase, not codebase. URL prepend; - url = resolveUrlForLocalOrAbsolute(url, + url = JalviewAppLoader.resolveUrlForLocalOrAbsolute(url, prepend = getDefaultParameter("resolvetocodebase", false) ? getCodeBase() : getDocumentBase()); @@ -3023,21 +2386,209 @@ public class JalviewLite extends Applet } } - /** - * bind structures in a viewer to any matching sequences in an alignFrame (use - * sequenceIds to limit scope of search to specific sequences) - * - * @param alFrame - * @param viewer - * @param sequenceIds - * @return TODO: consider making an exception structure for indicating when - * binding fails public SequenceStructureBinding - * addStructureViewInstance( AlignFrame alFrame, Object viewer, String - * sequenceIds) { - * - * if (sequenceIds != null && sequenceIds.length() > 0) { return - * alFrame.addStructureViewInstance(viewer, - * separatorListToArray(sequenceIds)); } else { return - * alFrame.addStructureViewInstance(viewer, null); } // return null; } - */ + @Override + public AlignViewportI getViewport() + { + return loaderFrame.getAlignViewport(); + } + + @Override + public void newStructureView(PDBEntry pdb, SequenceI[] seqs, + String[] chains, DataSourceType protocol) + { + loaderFrame.newStructureView(this, pdb, seqs, chains, + protocol); + } + + @Override + public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs, + String[][] chains, String[] protocols) + { + loaderFrame.alignedStructureView(this, pdb, seqs, chains, protocols); + } + + @Override + public void updateForAnnotations() + { + loaderFrame.alignPanel.fontChanged(); + loaderFrame.alignPanel.setScrollValues(0, 0); + } + + @Override + public void setFeatureGroupState(String[] groups, boolean state) + { + loaderFrame.setFeatureGroupState(groups, state); + } + + @Override + public boolean parseFeaturesFile(String param, DataSourceType protocol) + { + return loaderFrame.parseFeaturesFile(param, protocol); + } + + @Override + public void newFeatureSettings() + { + getViewport().setShowSequenceFeatures(true); + new FeatureSettings(loaderFrame.alignPanel); + } + + @Override + public boolean loadScoreFile(String sScoreFile) throws IOException + { + return loaderFrame.loadScoreFile(sScoreFile); + } + + @Override + public void loadTree(NewickFile tree, String treeFile) throws IOException + { + loaderFrame.loadTree(tree, treeFile); + } + + @Override + public boolean isJsfallbackEnabled() + { + return jsfallbackEnabled; + } + + @Override + public JSObject getJSObject() + { + return JSObject.getWindow(this); + } + + @Override + public void updateColoursFromMouseOver(Object source, + MouseOverStructureListener listener) + { + } + + @Override + public Object[] getSelectionForListener(SequenceGroup seqsel, ColumnSelection colsel, + HiddenColumns hidden, SelectionSource source, Object alignFrame) + { + // System.err.println("Testing selection event relay to + // jsfunction:"+_listener); + String setid = ""; + AlignFrame src = (AlignFrame) alignFrame; + if (source != null) + { + if (source instanceof jalview.appletgui.AlignViewport + && ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame.viewport == source) + { + // should be valid if it just generated an event! + src = ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame; + + } + } + String[] seqs = new String[] {}; + String[] cols = new String[] {}; + int strt = 0, end = (src == null) ? -1 + : src.alignPanel.av.getAlignment().getWidth(); + if (seqsel != null && seqsel.getSize() > 0) + { + seqs = new String[seqsel.getSize()]; + for (int i = 0; i < seqs.length; i++) + { + seqs[i] = seqsel.getSequenceAt(i).getName(); + } + if (strt < seqsel.getStartRes()) + { + strt = seqsel.getStartRes(); + } + if (end == -1 || end > seqsel.getEndRes()) + { + end = seqsel.getEndRes(); + } + } + if (colsel != null && !colsel.isEmpty()) + { + if (end == -1) + { + end = colsel.getMax() + 1; + } + cols = new String[colsel.getSelected().size()]; + for (int i = 0; i < cols.length; i++) + { + cols[i] = "" + (1 + colsel.getSelected().get(i).intValue()); + } + } + else + { + if (seqsel != null && seqsel.getSize() > 0) + { + // send a valid range, otherwise we send the empty selection + cols = new String[2]; + cols[0] = "" + (1 + strt) + "-" + (1 + end); + } + } + return new Object[] + { src, setid, arrayToSeparatorList(seqs), arrayToSeparatorList(cols) }; + } + + @Override + public String getJsMessage(String messageclass, String viewId) + { + return JSFunctionExec.getJsMessage(messageclass, viewId, this); + } + + @Override + public Object getFrameForSource(VamsasSource source) + { + if (source != null) + { + if (source instanceof jalview.appletgui.AlignViewport + && ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame.viewport == source) + { + // should be valid if it just generated an event! + return ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame; + + } + // TODO: ensure that if '_af' is specified along with a handler + // function, then only events from that alignFrame are sent to that + // function + } + return null; + } + + @Override + public FeatureRenderer getNewFeatureRenderer(AlignViewportI vp) + { + return new jalview.appletgui.FeatureRenderer((AlignmentViewport) vp); + } + + @Override + public String getSelectedSequencesAsAlignment(String format, + boolean suffix) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, boolean suffix) + { + // TODO Auto-generated method stub + return null; + } + + // /** + // * bind structures in a viewer to any matching sequences in an alignFrame + // (use + // * sequenceIds to limit scope of search to specific sequences) + // * + // * @param alFrame + // * @param viewer + // * @param sequenceIds + // * @return TODO: consider making an exception structure for indicating when + // * binding fails public SequenceStructureBinding + // * addStructureViewInstance( AlignFrame alFrame, Object viewer, String + // * sequenceIds) { + // * + // * if (sequenceIds != null && sequenceIds.length() > 0) { return + // * alFrame.addStructureViewInstance(viewer, + // * separatorListToArray(sequenceIds)); } else { return + // * alFrame.addStructureViewInstance(viewer, null); } // return null; } + // */ } diff --git a/src/jalview/datamodel/features/FeatureStore.java b/src/jalview/datamodel/features/FeatureStore.java index 54c0d59..653d389 100644 --- a/src/jalview/datamodel/features/FeatureStore.java +++ b/src/jalview/datamodel/features/FeatureStore.java @@ -23,6 +23,7 @@ package jalview.datamodel.features; import jalview.datamodel.SequenceFeature; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -30,18 +31,35 @@ import java.util.Set; import intervalstore.api.IntervalStoreI; import intervalstore.impl.BinarySearcher; -import intervalstore.impl.IntervalStore; +import intervalstore.impl.BinarySearcher.Compare; -/** - * A data store for a set of sequence features that supports efficient lookup of - * features overlapping a given range. Intended for (but not limited to) storage - * of features for one sequence and feature type. - * - * @author gmcarstairs - * - */ public class FeatureStore { + public enum IntervalStoreType + { + /** + * original NCList-based IntervalStore + */ + INTERVAL_STORE_NCLIST, + + /** + * linked-list IntervalStore + */ + INTERVAL_STORE_LINKED_LIST, + + /** + * NCList as array buffer IntervalStore + */ + INTERVAL_STORE_NCARRAY + } + + /* + * track largest start for quick insertion of ordered features + */ + protected int maxStart = -1; + + protected int maxContactStart = -1; + /* * Non-positional features have no (zero) start/end position. * Kept as a separate list in case this criterion changes in future. @@ -91,165 +109,149 @@ public class FeatureStore float nonPositionalMaxScore; /** - * Constructor + * Answers the 'length' of the feature, counting 0 for non-positional features + * and 1 for contact features + * + * @param feature + * @return */ - public FeatureStore() + protected static int getFeatureLength(SequenceFeature feature) { - features = new IntervalStore<>(); - positionalFeatureGroups = new HashSet<>(); - nonPositionalFeatureGroups = new HashSet<>(); - positionalMinScore = Float.NaN; - positionalMaxScore = Float.NaN; - nonPositionalMinScore = Float.NaN; - nonPositionalMaxScore = Float.NaN; - - // we only construct nonPositionalFeatures, contactFeatures if we need to + if (feature.isNonPositional()) + { + return 0; + } + if (feature.isContactFeature()) + { + return 1; + } + return 1 + feature.getEnd() - feature.getBegin(); } /** - * Adds one sequence feature to the store, and returns true, unless the - * feature is already contained in the store, in which case this method - * returns false. Containment is determined by SequenceFeature.equals() - * comparison. + * Answers true if the list contains the feature, else false. This method is + * optimised for the condition that the list is sorted on feature start + * position ascending, and will give unreliable results if this does not hold. * + * @param list * @param feature + * @return */ - public boolean addFeature(SequenceFeature feature) + public static boolean listContains(List list, + SequenceFeature feature) { - if (contains(feature)) + if (list == null || feature == null) { return false; } /* - * keep a record of feature groups - */ - if (!feature.isNonPositional()) - { - positionalFeatureGroups.add(feature.getFeatureGroup()); - } - - if (feature.isContactFeature()) - { - addContactFeature(feature); - } - else if (feature.isNonPositional()) - { - addNonPositionalFeature(feature); - } - else - { - addNestedFeature(feature); - } - - /* - * record the total extent of positional features, to make - * getTotalFeatureLength possible; we count the length of a - * contact feature as 1 - */ - totalExtent += getFeatureLength(feature); - - /* - * record the minimum and maximum score for positional - * and non-positional features + * locate the first entry in the list which does not precede the feature */ - float score = feature.getScore(); - if (!Float.isNaN(score)) + int begin = feature.begin; + int pos = BinarySearcher.findFirst(list, true, Compare.GE, begin); + int len = list.size(); + while (pos < len) { - if (feature.isNonPositional()) + SequenceFeature sf = list.get(pos); + if (sf.begin > begin) { - nonPositionalMinScore = min(nonPositionalMinScore, score); - nonPositionalMaxScore = max(nonPositionalMaxScore, score); + return false; // no match found } - else + if (sf.equals(feature)) { - positionalMinScore = min(positionalMinScore, score); - positionalMaxScore = max(positionalMaxScore, score); + return true; } + pos++; } - - return true; + return false; } /** - * Answers true if this store contains the given feature (testing by - * SequenceFeature.equals), else false + * A helper method to return the maximum of two floats, where a non-NaN value + * is treated as 'greater than' a NaN value (unlike Math.max which does the + * opposite) * - * @param feature - * @return + * @param f1 + * @param f2 */ - public boolean contains(SequenceFeature feature) + protected static float max(float f1, float f2) { - if (feature.isNonPositional()) + if (Float.isNaN(f1)) { - return nonPositionalFeatures == null ? false : nonPositionalFeatures - .contains(feature); + return Float.isNaN(f2) ? f1 : f2; } - - if (feature.isContactFeature()) + else { - return contactFeatureStarts == null ? false : listContains( - contactFeatureStarts, feature); + return Float.isNaN(f2) ? f1 : Math.max(f1, f2); } - - return features == null ? false : features - .contains(feature); } /** - * Answers the 'length' of the feature, counting 0 for non-positional features - * and 1 for contact features + * A helper method to return the minimum of two floats, where a non-NaN value + * is treated as 'less than' a NaN value (unlike Math.min which does the + * opposite) * - * @param feature - * @return + * @param f1 + * @param f2 */ - protected static int getFeatureLength(SequenceFeature feature) + protected static float min(float f1, float f2) { - if (feature.isNonPositional()) + if (Float.isNaN(f1)) { - return 0; + return Float.isNaN(f2) ? f1 : f2; } - if (feature.isContactFeature()) + else { - return 1; + return Float.isNaN(f2) ? f1 : Math.min(f1, f2); } - return 1 + feature.getEnd() - feature.getBegin(); } /** - * Adds the feature to the list of non-positional features (with lazy - * instantiation of the list if it is null), and returns true. The feature - * group is added to the set of distinct feature groups for non-positional - * features. This method allows duplicate features, so test before calling to - * prevent this. - * - * @param feature + * Constructor that defaults to using NCList IntervalStore */ - protected boolean addNonPositionalFeature(SequenceFeature feature) + public FeatureStore() { - if (nonPositionalFeatures == null) - { - nonPositionalFeatures = new ArrayList<>(); - } - - nonPositionalFeatures.add(feature); + this(IntervalStoreType.INTERVAL_STORE_NCLIST); + } - nonPositionalFeatureGroups.add(feature.getFeatureGroup()); + /** + * Constructor that allows an alternative IntervalStore implementation to be + * chosen + */ + public FeatureStore(IntervalStoreType intervalStoreType) + { + features = getIntervalStore(intervalStoreType); + positionalFeatureGroups = new HashSet<>(); + nonPositionalFeatureGroups = new HashSet<>(); + positionalMinScore = Float.NaN; + positionalMaxScore = Float.NaN; + nonPositionalMinScore = Float.NaN; + nonPositionalMaxScore = Float.NaN; - return true; + // only construct nonPositionalFeatures or contactFeatures if needed } /** - * Adds one feature to the IntervalStore that can manage nested features - * (creating the IntervalStore if necessary) + * Returns a new instance of IntervalStoreI of implementation as selected by + * the type parameter + * + * @param type + * @return */ - protected synchronized void addNestedFeature(SequenceFeature feature) + private IntervalStoreI getIntervalStore( + IntervalStoreType type) { - if (features == null) + switch (type) { - features = new IntervalStore<>(); + default: + case INTERVAL_STORE_NCLIST: + return new intervalstore.impl.IntervalStore<>(); + case INTERVAL_STORE_NCARRAY: + return new intervalstore.nonc.IntervalStore<>(); + case INTERVAL_STORE_LINKED_LIST: + return new intervalstore.nonc.IntervalStore0<>(); } - features.add(feature); } /** @@ -266,9 +268,6 @@ public class FeatureStore if (contactFeatureStarts == null) { contactFeatureStarts = new ArrayList<>(); - } - if (contactFeatureEnds == null) - { contactFeatureEnds = new ArrayList<>(); } @@ -276,264 +275,194 @@ public class FeatureStore * insert into list sorted by start (first contact position): * binary search the sorted list to find the insertion point */ - int insertPosition = BinarySearcher.findFirst(contactFeatureStarts, - f -> f.getBegin() >= feature.getBegin()); - contactFeatureStarts.add(insertPosition, feature); - - + int insertAt = BinarySearcher.findFirst(contactFeatureStarts, true, + Compare.GE, feature.begin); + contactFeatureStarts.add(insertAt, feature); /* * insert into list sorted by end (second contact position): * binary search the sorted list to find the insertion point */ - insertPosition = BinarySearcher.findFirst(contactFeatureEnds, - f -> f.getEnd() >= feature.getEnd()); - contactFeatureEnds.add(insertPosition, feature); + contactFeatureEnds.add(findFirstEnd(contactFeatureEnds, feature.end), + feature); return true; } /** - * Answers true if the list contains the feature, else false. This method is - * optimised for the condition that the list is sorted on feature start - * position ascending, and will give unreliable results if this does not hold. + * Adds one sequence feature to the store, and returns true, unless the + * feature is already contained in the store, in which case this method + * returns false. Containment is determined by SequenceFeature.equals() + * comparison. * - * @param features * @param feature - * @return */ - protected static boolean listContains(List features, - SequenceFeature feature) + public boolean addFeature(SequenceFeature feature) { - if (features == null || feature == null) + if (feature.isContactFeature()) { - return false; + if (containsContactFeature(feature)) + { + return false; + } + positionalFeatureGroups.add(feature.getFeatureGroup()); + if (feature.begin > maxContactStart) + { + maxContactStart = feature.begin; + } + addContactFeature(feature); } + else if (feature.isNonPositional()) + { + if (containsNonPositionalFeature(feature)) + { + return false; + } - /* - * locate the first entry in the list which does not precede the feature - */ - // int pos = binarySearch(features, - // SearchCriterion.byFeature(feature, RangeComparator.BY_START_POSITION)); - int pos = BinarySearcher.findFirst(features, - val -> val.getBegin() >= feature.getBegin()); - int len = features.size(); - while (pos < len) + addNonPositionalFeature(feature); + } + else { - SequenceFeature sf = features.get(pos); - if (sf.getBegin() > feature.getBegin()) + if (!features.add(feature, false)) { - return false; // no match found + return false; } - if (sf.equals(feature)) + positionalFeatureGroups.add(feature.getFeatureGroup()); + if (feature.begin > maxStart) { - return true; + maxStart = feature.begin; } - pos++; } - return false; - } - - /** - * Returns a (possibly empty) list of features whose extent overlaps the given - * range. The returned list is not ordered. Contact features are included if - * either of the contact points lies within the range. - * - * @param start - * start position of overlap range (inclusive) - * @param end - * end position of overlap range (inclusive) - * @return - */ - public List findOverlappingFeatures(long start, long end) - { - List result = new ArrayList<>(); - findContactFeatures(start, end, result); + /* + * record the total extent of positional features, to make + * getTotalFeatureLength possible; we count the length of a + * contact feature as 1 + */ + totalExtent += getFeatureLength(feature); - if (features != null) + /* + * record the minimum and maximum score for positional + * and non-positional features + */ + float score = feature.getScore(); + if (!Float.isNaN(score)) { - result.addAll(features.findOverlaps(start, end)); + if (feature.isNonPositional()) + { + nonPositionalMinScore = min(nonPositionalMinScore, score); + nonPositionalMaxScore = max(nonPositionalMaxScore, score); + } + else + { + positionalMinScore = min(positionalMinScore, score); + positionalMaxScore = max(positionalMaxScore, score); + } } - return result; + return true; } /** - * Adds contact features to the result list where either the second or the - * first contact position lies within the target range + * A helper method that adds to the result list any features from the + * collection provided whose feature group matches the specified group * - * @param from - * @param to + * @param group + * @param sfs * @param result */ - protected void findContactFeatures(long from, long to, - List result) + private void addFeaturesForGroup(String group, + Collection sfs, List result) { - if (contactFeatureStarts != null) + if (sfs == null) { - findContactStartOverlaps(from, to, result); + return; } - if (contactFeatureEnds != null) + for (SequenceFeature sf : sfs) { - findContactEndOverlaps(from, to, result); + String featureGroup = sf.getFeatureGroup(); + if (group == null && featureGroup == null + || group != null && group.equals(featureGroup)) + { + result.add(sf); + } } } /** - * Adds to the result list any contact features whose end (second contact - * point), but not start (first contact point), lies in the query from-to - * range + * Adds the feature to the list of non-positional features (with lazy + * instantiation of the list if it is null), and returns true. The feature + * group is added to the set of distinct feature groups for non-positional + * features. This method allows duplicate features, so test before calling to + * prevent this. * - * @param from - * @param to - * @param result + * @param feature */ - protected void findContactEndOverlaps(long from, long to, - List result) + protected boolean addNonPositionalFeature(SequenceFeature feature) { - /* - * find the first contact feature (if any) - * whose end point is not before the target range - */ - int index = BinarySearcher.findFirst(contactFeatureEnds, - f -> f.getEnd() >= from); - - while (index < contactFeatureEnds.size()) + if (nonPositionalFeatures == null) { - SequenceFeature sf = contactFeatureEnds.get(index); - if (!sf.isContactFeature()) - { - System.err.println("Error! non-contact feature type " - + sf.getType() + " in contact features list"); - index++; - continue; - } - - int begin = sf.getBegin(); - if (begin >= from && begin <= to) - { - /* - * this feature's first contact position lies in the search range - * so we don't include it in results a second time - */ - index++; - continue; - } - - if (sf.getEnd() > to) - { - /* - * this feature (and all following) has end point after the target range - */ - break; - } - - /* - * feature has end >= from and end <= to - * i.e. contact end point lies within overlap search range - */ - result.add(sf); - index++; + nonPositionalFeatures = new ArrayList<>(); } - } - /** - * Adds contact features whose start position lies in the from-to range to the - * result list - * - * @param from - * @param to - * @param result - */ - protected void findContactStartOverlaps(long from, long to, - List result) - { - int index = BinarySearcher.findFirst(contactFeatureStarts, - f -> f.getBegin() >= from); + nonPositionalFeatures.add(feature); - while (index < contactFeatureStarts.size()) - { - SequenceFeature sf = contactFeatureStarts.get(index); - if (!sf.isContactFeature()) - { - System.err.println("Error! non-contact feature " + sf.toString() - + " in contact features list"); - index++; - continue; - } - if (sf.getBegin() > to) - { - /* - * this feature's start (and all following) follows the target range - */ - break; - } + nonPositionalFeatureGroups.add(feature.getFeatureGroup()); - /* - * feature has begin >= from and begin <= to - * i.e. contact start point lies within overlap search range - */ - result.add(sf); - index++; - } + return true; } /** - * Answers a list of all positional features stored, in no guaranteed order + * Answers true if this store contains the given feature (testing by + * SequenceFeature.equals), else false * + * @param feature * @return */ - public List getPositionalFeatures() + public boolean contains(SequenceFeature feature) { - List result = new ArrayList<>(); - - /* - * add any contact features - from the list by start position - */ - if (contactFeatureStarts != null) + if (feature.isNonPositional()) { - result.addAll(contactFeatureStarts); + return containsNonPositionalFeature(feature); } - /* - * add any nested features - */ - if (features != null) + if (feature.isContactFeature()) { - result.addAll(features); + return containsContactFeature(feature); } - return result; + return containsPositionalFeature(feature); + } + + private boolean containsPositionalFeature(SequenceFeature feature) + { + return features == null || feature.begin > maxStart ? false + : features.contains(feature); } /** - * Answers a list of all contact features. If there are none, returns an - * immutable empty list. + * Answers true if this store already contains a contact feature equal to the + * given feature (by {@code SequenceFeature.equals()} test), else false * + * @param feature * @return */ - public List getContactFeatures() + private boolean containsContactFeature(SequenceFeature feature) { - if (contactFeatureStarts == null) - { - return Collections.emptyList(); - } - return new ArrayList<>(contactFeatureStarts); + return contactFeatureStarts != null && feature.begin <= maxContactStart + && listContains(contactFeatureStarts, feature); } /** - * Answers a list of all non-positional features. If there are none, returns - * an immutable empty list. + * Answers true if this store already contains a non-positional feature equal + * to the given feature (by {@code SequenceFeature.equals()} test), else false * + * @param feature * @return */ - public List getNonPositionalFeatures() + private boolean containsNonPositionalFeature(SequenceFeature feature) { - if (nonPositionalFeatures == null) - { - return Collections.emptyList(); - } - return new ArrayList<>(nonPositionalFeatures); + return nonPositionalFeatures == null ? false + : nonPositionalFeatures.contains(feature); } /** @@ -561,15 +490,12 @@ public class FeatureStore } } - boolean removedNonPositional = false; - /* * if not found, try non-positional features */ if (!removed && nonPositionalFeatures != null) { - removedNonPositional = nonPositionalFeatures.remove(sf); - removed = removedNonPositional; + removed = nonPositionalFeatures.remove(sf); } /* @@ -588,100 +514,92 @@ public class FeatureStore return removed; } + public List findFeatures(long start, long end) + { + return findFeatures(start, end, null); + } + /** - * Rescan all features to recompute any cached values after an entry has been - * deleted. This is expected to be an infrequent event, so performance here is - * not critical. + * Returns a (possibly empty) list of features whose extent overlaps the given + * range. The returned list is not ordered. Contact features are included if + * either of the contact points lies within the range. If the {@code result} + * parameter is not null, new entries are added to this list and the (possibly + * extended) list returned. + * + * @param start + * start position of overlap range (inclusive) + * @param end + * end position of overlap range (inclusive) + * @param result + * @return */ - protected synchronized void rescanAfterDelete() + public List findFeatures(long start, long end, + List result) { - positionalFeatureGroups.clear(); - nonPositionalFeatureGroups.clear(); - totalExtent = 0; - positionalMinScore = Float.NaN; - positionalMaxScore = Float.NaN; - nonPositionalMinScore = Float.NaN; - nonPositionalMaxScore = Float.NaN; - - /* - * scan non-positional features for groups and scores - */ - for (SequenceFeature sf : getNonPositionalFeatures()) + if (result == null) { - nonPositionalFeatureGroups.add(sf.getFeatureGroup()); - float score = sf.getScore(); - nonPositionalMinScore = min(nonPositionalMinScore, score); - nonPositionalMaxScore = max(nonPositionalMaxScore, score); + result = new ArrayList<>(); } - /* - * scan positional features for groups, scores and extents - */ - for (SequenceFeature sf : getPositionalFeatures()) - { - positionalFeatureGroups.add(sf.getFeatureGroup()); - float score = sf.getScore(); - positionalMinScore = min(positionalMinScore, score); - positionalMaxScore = max(positionalMaxScore, score); - totalExtent += getFeatureLength(sf); - } + findContactFeatures(start, end, result); + features.findOverlaps(start, end, result); + + return result; } /** - * A helper method to return the minimum of two floats, where a non-NaN value - * is treated as 'less than' a NaN value (unlike Math.min which does the - * opposite) + * Returns a (possibly empty) list of stored contact features * - * @param f1 - * @param f2 + * @return */ - protected static float min(float f1, float f2) + public List getContactFeatures() { - if (Float.isNaN(f1)) - { - return Float.isNaN(f2) ? f1 : f2; - } - else - { - return Float.isNaN(f2) ? f1 : Math.min(f1, f2); - } + List result = new ArrayList<>(); + getContactFeatures(result); + return result; } /** - * A helper method to return the maximum of two floats, where a non-NaN value - * is treated as 'greater than' a NaN value (unlike Math.max which does the - * opposite) + * Adds any stored contact features to the result list * - * @param f1 - * @param f2 + * @return */ - protected static float max(float f1, float f2) + public void getContactFeatures(List result) { - if (Float.isNaN(f1)) - { - return Float.isNaN(f2) ? f1 : f2; - } - else + if (contactFeatureStarts != null) { - return Float.isNaN(f2) ? f1 : Math.max(f1, f2); + result.addAll(contactFeatureStarts); } } /** - * Answers true if this store has no features, else false + * Answers the number of positional (or non-positional) features stored. + * Contact features count as 1. * + * @param positional * @return */ - public boolean isEmpty() + public int getFeatureCount(boolean positional) { - boolean hasFeatures = (contactFeatureStarts != null - && !contactFeatureStarts - .isEmpty()) - || (nonPositionalFeatures != null && !nonPositionalFeatures - .isEmpty()) - || (features != null && features.size() > 0); + if (!positional) + { + return nonPositionalFeatures == null ? 0 + : nonPositionalFeatures.size(); + } - return !hasFeatures; + int size = 0; + + if (contactFeatureStarts != null) + { + // note a contact feature (start/end) counts as one + size += contactFeatureStarts.size(); + } + + if (features != null) + { + size += features.size(); + } + return size; } /** @@ -700,52 +618,58 @@ public class FeatureStore } else { - return nonPositionalFeatureGroups == null ? Collections - . emptySet() : Collections - .unmodifiableSet(nonPositionalFeatureGroups); + return nonPositionalFeatureGroups == null + ? Collections. emptySet() + : Collections.unmodifiableSet(nonPositionalFeatureGroups); } } /** - * Answers the number of positional (or non-positional) features stored. - * Contact features count as 1. + * Answers a list of all either positional or non-positional features whose + * feature group matches the given group (which may be null) * * @param positional + * @param group * @return */ - public int getFeatureCount(boolean positional) + public List getFeaturesForGroup(boolean positional, + String group) { - if (!positional) + List result = new ArrayList<>(); + + /* + * if we know features don't include the target group, no need + * to inspect them for matches + */ + if (positional && !positionalFeatureGroups.contains(group) + || !positional && !nonPositionalFeatureGroups.contains(group)) { - return nonPositionalFeatures == null ? 0 : nonPositionalFeatures - .size(); + return result; } - int size = 0; - - if (contactFeatureStarts != null) + if (positional) { - // note a contact feature (start/end) counts as one - size += contactFeatureStarts.size(); + addFeaturesForGroup(group, contactFeatureStarts, result); + addFeaturesForGroup(group, features, result); } - - if (features != null) + else { - size += features.size(); + addFeaturesForGroup(group, nonPositionalFeatures, result); } - - return size; + return result; } /** - * Answers the total length of positional features (or zero if there are - * none). Contact features contribute a value of 1 to the total. + * Answers the maximum score held for positional or non-positional features. + * This may be Float.NaN if there are no features, are none has a non-NaN + * score. * + * @param positional * @return */ - public int getTotalFeatureLength() + public float getMaximumScore(boolean positional) { - return totalExtent; + return positional ? positionalMaxScore : nonPositionalMaxScore; } /** @@ -762,53 +686,147 @@ public class FeatureStore } /** - * Answers the maximum score held for positional or non-positional features. - * This may be Float.NaN if there are no features, are none has a non-NaN - * score. + * Answers a (possibly empty) list of all non-positional features * - * @param positional * @return */ - public float getMaximumScore(boolean positional) + public List getNonPositionalFeatures() { - return positional ? positionalMaxScore : nonPositionalMaxScore; + List result = new ArrayList<>(); + getNonPositionalFeatures(result); + return result; } /** - * Answers a list of all either positional or non-positional features whose - * feature group matches the given group (which may be null) + * Adds any stored non-positional features to the result list * - * @param positional - * @param group * @return */ - public List getFeaturesForGroup(boolean positional, - String group) + public void getNonPositionalFeatures(List result) + { + if (nonPositionalFeatures != null) + { + result.addAll(nonPositionalFeatures); + } + } + + /** + * Returns a (possibly empty) list of all positional features stored + * + * @return + */ + public List getPositionalFeatures() { List result = new ArrayList<>(); + getPositionalFeatures(result); + + return result; + } + /** + * Adds all positional features stored to the result list, in no guaranteed + * order, and with no check for duplicates + */ + public void getPositionalFeatures(List result) + { /* - * if we know features don't include the target group, no need - * to inspect them for matches + * add any contact features - from the list by start position */ - if (positional && !positionalFeatureGroups.contains(group) - || !positional && !nonPositionalFeatureGroups.contains(group)) + if (contactFeatureStarts != null) { - return result; + result.addAll(contactFeatureStarts); } - List sfs = positional ? getPositionalFeatures() - : getNonPositionalFeatures(); - for (SequenceFeature sf : sfs) + /* + * add any nested features + */ + if (features != null) { - String featureGroup = sf.getFeatureGroup(); - if (group == null && featureGroup == null || group != null - && group.equals(featureGroup)) + result.addAll(features); + } + } + + /** + * Answers the total length of positional features (or zero if there are + * none). Contact features contribute a value of 1 to the total. + * + * @return + */ + public int getTotalFeatureLength() + { + return totalExtent; + } + + /** + * Answers true if this store has no features, else false + * + * @return + */ + public boolean isEmpty() + { + boolean hasFeatures = (contactFeatureStarts != null + && !contactFeatureStarts.isEmpty()) + || (nonPositionalFeatures != null + && !nonPositionalFeatures.isEmpty()) + || (features != null && features.size() > 0); + + return !hasFeatures; + } + + /** + * Rescan all features to recompute any cached values after an entry has been + * deleted. This is expected to be an infrequent event, so performance here is + * not critical. + */ + protected synchronized void rescanAfterDelete() + { + positionalFeatureGroups.clear(); + nonPositionalFeatureGroups.clear(); + totalExtent = 0; + positionalMinScore = Float.NaN; + positionalMaxScore = Float.NaN; + nonPositionalMinScore = Float.NaN; + nonPositionalMaxScore = Float.NaN; + /* + * scan non-positional features for groups and scores + */ + if (nonPositionalFeatures != null) + { + for (int i = 0, n = nonPositionalFeatures.size(); i < n; i++) { - result.add(sf); + SequenceFeature sf = nonPositionalFeatures.get(i); + nonPositionalFeatureGroups.add(sf.getFeatureGroup()); + float score = sf.getScore(); + nonPositionalMinScore = min(nonPositionalMinScore, score); + nonPositionalMaxScore = max(nonPositionalMaxScore, score); } } - return result; + + rescanPositional(contactFeatureStarts); + rescanPositional(features); + } + + /** + * Scans the given features and updates cached feature groups, minimum and + * maximum feature score, and total feature extent (length) for positional + * features + * + * @param sfs + */ + private void rescanPositional(Collection sfs) + { + if (sfs == null) + { + return; + } + for (SequenceFeature sf : sfs) + { + positionalFeatureGroups.add(sf.getFeatureGroup()); + float score = sf.getScore(); + positionalMinScore = min(positionalMinScore, score); + positionalMaxScore = max(positionalMaxScore, score); + totalExtent += getFeatureLength(sf); + } } /** @@ -828,8 +846,10 @@ public class FeatureStore * (Although a simple shift of all values would preserve data integrity!) */ boolean modified = false; - for (SequenceFeature sf : getPositionalFeatures()) + List list = getPositionalFeatures(); + for (int i = 0, n = list.size(); i < n; i++) { + SequenceFeature sf = list.get(i); if (sf.getBegin() >= fromPosition) { modified = true; @@ -851,4 +871,136 @@ public class FeatureStore } return modified; } + + /** + * Answers the position (0, 1...) in the list of the first entry whose end + * position is not less than {@ pos}. If no such entry is found, answers the + * length of the list. + * + * @param list + * @param pos + * @return + */ + protected int findFirstEnd(List list, long pos) + { + return BinarySearcher.findFirst(list, false, Compare.GE, (int) pos); + } + + /** + * Adds contact features to the result list where either the second or the + * first contact position lies within the target range + * + * @param from + * @param to + * @param result + */ + protected void findContactFeatures(long from, long to, + List result) + { + if (contactFeatureStarts != null) + { + findContactStartOverlaps(from, to, result); + findContactEndOverlaps(from, to, result); + } + } + + /** + * Adds to the result list any contact features whose end (second contact + * point), but not start (first contact point), lies in the query from-to + * range + * + * @param from + * @param to + * @param result + */ + private void findContactEndOverlaps(long from, long to, + List result) + { + /* + * find the first contact feature (if any) + * whose end point is not before the target range + */ + int index = findFirstEnd(contactFeatureEnds, from); + + int n = contactFeatureEnds.size(); + while (index < n) + { + SequenceFeature sf = contactFeatureEnds.get(index); + if (!sf.isContactFeature()) + { + System.err.println("Error! non-contact feature type " + sf.getType() + + " in contact features list"); + index++; + continue; + } + + int begin = sf.getBegin(); + if (begin >= from && begin <= to) + { + /* + * this feature's first contact position lies in the search range + * so we don't include it in results a second time + */ + index++; + continue; + } + + if (sf.getEnd() > to) + { + /* + * this feature (and all following) has end point after the target range + */ + break; + } + + /* + * feature has end >= from and end <= to + * i.e. contact end point lies within overlap search range + */ + result.add(sf); + index++; + } + } + + /** + * Adds contact features whose start position lies in the from-to range to the + * result list + * + * @param from + * @param to + * @param result + */ + private void findContactStartOverlaps(long from, long to, + List result) + { + int index = BinarySearcher.findFirst(contactFeatureStarts, true, + Compare.GE, (int) from); + + while (index < contactFeatureStarts.size()) + { + SequenceFeature sf = contactFeatureStarts.get(index); + if (!sf.isContactFeature()) + { + System.err.println("Error! non-contact feature " + sf.toString() + + " in contact features list"); + index++; + continue; + } + if (sf.getBegin() > to) + { + /* + * this feature's start (and all following) follows the target range + */ + break; + } + + /* + * feature has begin >= from and begin <= to + * i.e. contact start point lies within overlap search range + */ + result.add(sf); + index++; + } + } + } diff --git a/src/jalview/datamodel/features/SequenceFeatures.java b/src/jalview/datamodel/features/SequenceFeatures.java index db2f0e1..bc38942 100644 --- a/src/jalview/datamodel/features/SequenceFeatures.java +++ b/src/jalview/datamodel/features/SequenceFeatures.java @@ -23,8 +23,11 @@ package jalview.datamodel.features; import jalview.datamodel.SequenceFeature; import jalview.io.gff.SequenceOntologyFactory; import jalview.io.gff.SequenceOntologyI; +import jalview.util.Platform; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -44,7 +47,6 @@ import intervalstore.api.IntervalI; */ public class SequenceFeatures implements SequenceFeaturesI { - /* * map from feature type to structured store of features for that type * null types are permitted (but not a good idea!) @@ -108,12 +110,11 @@ public class SequenceFeatures implements SequenceFeaturesI String... type) { List result = new ArrayList<>(); - for (FeatureStore featureSet : varargToTypes(type)) { - result.addAll(featureSet.findOverlappingFeatures(from, to)); + // BH MUCH more efficient to pass the list + featureSet.findFeatures(from, to, result); } - return result; } @@ -196,7 +197,7 @@ public class SequenceFeatures implements SequenceFeaturesI for (FeatureStore featureSet : varargToTypes(type)) { - result.addAll(featureSet.getPositionalFeatures()); + featureSet.getPositionalFeatures(result); } return result; } @@ -241,7 +242,7 @@ public class SequenceFeatures implements SequenceFeaturesI for (FeatureStore featureSet : varargToTypes(type)) { - result.addAll(featureSet.getContactFeatures()); + featureSet.getContactFeatures(result); } return result; } @@ -256,7 +257,7 @@ public class SequenceFeatures implements SequenceFeaturesI for (FeatureStore featureSet : varargToTypes(type)) { - result.addAll(featureSet.getNonPositionalFeatures()); + featureSet.getNonPositionalFeatures(result); } return result; } @@ -300,7 +301,11 @@ public class SequenceFeatures implements SequenceFeaturesI public Set getFeatureGroups(boolean positionalFeatures, String... type) { - Set groups = new HashSet<>(); + // BH 2020.03.21 This is the set that orders the list of groups + // at the top of the FeatureSettings panel. + // In order to keep the same order as a Java HashSet, we must + // request that specifically. See Platform. + Set groups = Platform.getJavaOrderedHashSet(); for (FeatureStore featureSet : varargToTypes(type)) { @@ -317,7 +322,10 @@ public class SequenceFeatures implements SequenceFeaturesI public Set getFeatureTypesForGroups(boolean positionalFeatures, String... groups) { - Set result = new HashSet<>(); + // BH 2020.03.21 This set is the one that sets the initial ordering for + // feature rendering. We set it to new HashSet<>(16,0.75) to force it to + // be backed by a Java hash-ordered HashMap instead of a JavaScript Map. + Set result = Platform.getJavaOrderedHashSet(); for (Entry featureType : featureStore.entrySet()) { @@ -345,7 +353,7 @@ public class SequenceFeatures implements SequenceFeaturesI @Override public Set getFeatureTypes(String... soTerm) { - Set types = new HashSet<>(); + Set types = Platform.getJavaOrderedHashSet(); for (Entry entry : featureStore.entrySet()) { String type = entry.getKey(); @@ -373,7 +381,7 @@ public class SequenceFeatures implements SequenceFeaturesI { return true; } - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); for (String term : soTerm) { if (type.equals(term) || so.isA(type, term)) @@ -465,4 +473,24 @@ public class SequenceFeatures implements SequenceFeaturesI { featureStore.clear(); } + + @Override + public List findFeatures(int pos, String type, + List list) + { + FeatureStore fs = featureStore.get(type); + if (fs == null) + { + return list == null ? new ArrayList<>() : list; + } + return fs.findFeatures(pos, pos, list); + } + + @Override + public boolean hasFeatures(String type) + { + return featureStore.containsKey(type) + && !featureStore.get(type).isEmpty(); + } + } diff --git a/src/jalview/datamodel/features/SequenceFeaturesI.java b/src/jalview/datamodel/features/SequenceFeaturesI.java index 7213cba..fe5e927 100644 --- a/src/jalview/datamodel/features/SequenceFeaturesI.java +++ b/src/jalview/datamodel/features/SequenceFeaturesI.java @@ -42,8 +42,7 @@ public interface SequenceFeaturesI /** * Returns a (possibly empty) list of features, optionally restricted to * specified types, which overlap the given (inclusive) sequence position - * range. If types are specified, features are returned in the order of the - * types given. + * range * * @param from * @param to @@ -229,4 +228,22 @@ public interface SequenceFeaturesI * Deletes all positional and non-positional features */ void deleteAll(); + + /** + * Answers a (possibly empty) list of features of the specified type that + * overlap the specified column position. If parameter {@code result} is not + * null, features are appended to it and the (possibly extended) list is + * returned. + * + * @param pos + * @param type + * @param result + * @return + */ + List findFeatures(int pos, String type, List result); + + /** + * Answers true if there are any features of the given type, else false + */ + boolean hasFeatures(String type); } diff --git a/src/jalview/ext/ensembl/EnsemblCds.java b/src/jalview/ext/ensembl/EnsemblCds.java index 8f13d99..bf37265 100644 --- a/src/jalview/ext/ensembl/EnsemblCds.java +++ b/src/jalview/ext/ensembl/EnsemblCds.java @@ -93,7 +93,7 @@ public class EnsemblCds extends EnsemblSeqProxy @Override protected boolean retainFeature(SequenceFeature sf, String accessionId) { - if (SequenceOntologyFactory.getInstance().isA(sf.getType(), + if (SequenceOntologyFactory.getSequenceOntology().isA(sf.getType(), SequenceOntologyI.CDS)) { return false; diff --git a/src/jalview/ext/ensembl/EnsemblGene.java b/src/jalview/ext/ensembl/EnsemblGene.java index 0e3d84b..a65f2ed 100644 --- a/src/jalview/ext/ensembl/EnsemblGene.java +++ b/src/jalview/ext/ensembl/EnsemblGene.java @@ -578,7 +578,7 @@ public class EnsemblGene extends EnsemblSeqProxy @Override protected boolean retainFeature(SequenceFeature sf, String accessionId) { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); String type = sf.getType(); if (so.isA(type, SequenceOntologyI.GENE)) { @@ -625,7 +625,7 @@ public class EnsemblGene extends EnsemblSeqProxy { return new FeatureSettingsAdapter() { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); @Override public boolean isFeatureDisplayed(String type) diff --git a/src/jalview/ext/ensembl/EnsemblSeqProxy.java b/src/jalview/ext/ensembl/EnsemblSeqProxy.java index fd8800f..11f8b7b 100644 --- a/src/jalview/ext/ensembl/EnsemblSeqProxy.java +++ b/src/jalview/ext/ensembl/EnsemblSeqProxy.java @@ -732,7 +732,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient * for sequence_variant on reverse strand, have to convert the allele * values to their complements */ - if (!forwardStrand && SequenceOntologyFactory.getInstance() + if (!forwardStrand && SequenceOntologyFactory.getSequenceOntology() .isA(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT)) { reverseComplementAlleles(copy); @@ -966,7 +966,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient public static boolean isTranscript(String featureType) { return SequenceOntologyI.NMD_TRANSCRIPT_VARIANT.equals(featureType) - || SequenceOntologyFactory.getInstance().isA(featureType, + || SequenceOntologyFactory.getSequenceOntology().isA(featureType, SequenceOntologyI.TRANSCRIPT); } } diff --git a/src/jalview/gui/APQHandlers.java b/src/jalview/gui/APQHandlers.java index c5a1b66..75c06ed 100644 --- a/src/jalview/gui/APQHandlers.java +++ b/src/jalview/gui/APQHandlers.java @@ -22,7 +22,7 @@ public class APQHandlers public APQHandlers() { } - protected static boolean setAPQHandlers(jalview.gui.Desktop jalviewDesktop) + protected boolean setAPQHandlers(jalview.gui.Desktop jalviewDesktop) { // flagging this test to avoid unnecessary reflection if (!setAPQHandlers) diff --git a/src/jalview/gui/AlignExportOptions.java b/src/jalview/gui/AlignExportOptions.java index 70601c9..3a8fb7c 100644 --- a/src/jalview/gui/AlignExportOptions.java +++ b/src/jalview/gui/AlignExportOptions.java @@ -96,7 +96,7 @@ public class AlignExportOptions extends JPanel this.settings = defaults; this.isComplexAlignFile = format.isComplexAlignFile(); init(viewport.hasHiddenRows(), viewport.hasHiddenColumns()); - dialog = JvOptionPane.newOptionDialog(Desktop.desktop); + dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()); } /** diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index b7ba75a..a12f772 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -23,6 +23,7 @@ package jalview.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; +import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; @@ -46,6 +47,7 @@ import java.awt.event.MouseEvent; import java.awt.print.PageFormat; import java.awt.print.PrinterJob; import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; @@ -80,6 +82,7 @@ import jalview.analysis.GeneticCodeI; import jalview.analysis.ParseProperties; import jalview.analysis.SequenceIdMatcher; import jalview.api.AlignExportSettingsI; +import jalview.api.AlignFrameI; import jalview.api.AlignViewControllerGuiI; import jalview.api.AlignViewControllerI; import jalview.api.AlignViewportI; @@ -162,7 +165,8 @@ import jalview.ws.seqfetcher.DbSourceProxy; * @version $Revision$ */ @SuppressWarnings("serial") -public class AlignFrame extends GAlignFrame implements DropTargetListener, +public class AlignFrame extends GAlignFrame + implements AlignFrameI, DropTargetListener, IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener { @@ -189,9 +193,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, /** * Current filename for this alignment */ - String fileName = null; + private String fileName = null; - File fileObject; + private File fileObject; /** * Creates a new AlignFrame object with specific width and height. @@ -295,10 +299,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId); + // BH! new alignPanel must come later + // alignPanel = new AlignmentPanel(this, viewport); + // addAlignmentPanel(alignPanel, true); - alignPanel = new AlignmentPanel(this, viewport); - - addAlignmentPanel(alignPanel, true); init(); } @@ -318,9 +322,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { viewport.hideSequence(hiddenSeqs); } - alignPanel = new AlignmentPanel(this, viewport); - addAlignmentPanel(alignPanel, true); - init(); + // BH! new alignPanel must come later + //alignPanel = new AlignmentPanel(this, viewport); + //addAlignmentPanel(alignPanel, true); +init(); } /** @@ -335,7 +340,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { viewport = ap.av; alignPanel = ap; - addAlignmentPanel(ap, false); + // BH! adding must come later + // addAlignmentPanel(ap, false); init(); } @@ -345,11 +351,36 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ void init() { -// setBackground(Color.white); // BH 2019 - + // BH! Here is where we create the panel; note the sequence + boolean newPanel = (alignPanel == null); + viewport.setShowAutocalculatedAbove(isShowAutoCalculatedAbove()); + if (newPanel) + { + if (Platform.isJS()) + { + // need to set this up front if NOANNOTATION is + // used in conjunction with SHOWOVERVIEW. + + // I have not determined if this is appropriate for + // Jalview/Java, as it means we are setting this flag + // for all subsequent AlignFrames. For now, at least, + // I am setting it to be JalviewJS-only. + + boolean showAnnotation = Jalview.getInstance().getShowAnnotation(); + viewport.setShowAnnotation(showAnnotation); + } + alignPanel = new AlignmentPanel(this, viewport); + } + addAlignmentPanel(alignPanel, newPanel); + + // setBackground(Color.white); // BH 2019 + + // BH meaning "without display, one way or another" if (!Jalview.isHeadlessMode()) { progressBar = new ProgressBar(this.statusPanel, this.statusBar); + statusPanel.setVisible(Jalview.getInstance().getShowStatus()); + alignFrameMenuBar.setVisible(Jalview.getInstance().getAllowMenuBar()); } avc = new jalview.controller.AlignViewController(this, viewport, @@ -364,7 +395,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // modifyPID.setEnabled(false); } - String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT", + String sortby = Cache.getDefault(Preferences.SORT_ALIGNMENT, "No sort"); if (sortby.equals("Id")) @@ -376,7 +407,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, sortPairwiseMenuItem_actionPerformed(null); } - this.alignPanel.av + alignPanel.av .setShowAutocalculatedAbove(isShowAutoCalculatedAbove()); setMenusFromViewport(viewport); @@ -392,7 +423,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, }); buildColourMenu(); - if (Desktop.desktop != null) + if (Desktop.getDesktopPane() != null) { this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); if (!Platform.isJS()) @@ -407,7 +438,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, wrapMenuItem_actionPerformed(null); } - if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false)) + if (jalview.bin.Cache.getDefault(Preferences.SHOW_OVERVIEW, false)) { this.overviewMenuItem_actionPerformed(null); } @@ -551,7 +582,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, switch (evt.getKeyCode()) { - case 27: // escape key + case KeyEvent.VK_ESCAPE: // escape key deselectAllSequenceMenuItem_actionPerformed(null); break; @@ -790,9 +821,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { ap.av.getAlignment().padGaps(); } - ap.av.updateConservation(ap); - ap.av.updateConsensus(ap); - ap.av.updateStrucConsensus(ap); + // BH! important option for JalviewJS + if (Jalview.getInstance().getStartCalculations()) + { + ap.av.updateConservation(ap); + ap.av.updateConsensus(ap); + ap.av.updateStrucConsensus(ap); + } } } @@ -814,31 +849,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, /* 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() - { + PropertyChangeListener thisListener; + Desktop.getInstance().addJalviewPropertyChangeListener("services", + thisListener = new PropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent evt) + { + { + SwingUtilities.invokeLater(new Runnable() + { - @Override - public void run() - { + @Override + public void run() + { System.err.println( "Rebuild WS Menu for service change"); - BuildWebServiceMenu(); - } - - }); - } - } - }); + BuildWebServiceMenu(); + } + }); + } + } + }); addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() { @Override @@ -846,7 +878,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, javax.swing.event.InternalFrameEvent evt) { // System.out.println("deregistering discoverer listener"); - Desktop.instance.removeJalviewPropertyChangeListener("services", + Desktop.getInstance().removeJalviewPropertyChangeListener("services", thisListener); closeMenuItem_actionPerformed(true); } @@ -920,13 +952,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, scaleLeft.setVisible(av.getWrapAlignment()); scaleRight.setVisible(av.getWrapAlignment()); annotationPanelMenuItem.setState(av.isShowAnnotation()); - /* - * Show/hide annotations only enabled if annotation panel is shown - */ - showAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState()); - hideAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState()); - showAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState()); - hideAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState()); + // Show/hide annotations only enabled if annotation panel is shown + + syncAnnotationMenuItems(); + viewBoxesMenuItem.setSelected(av.getShowBoxes()); viewTextMenuItem.setSelected(av.getShowText()); showNonconservedMenuItem.setSelected(av.getShowUnconserved()); @@ -944,7 +973,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, applyToAllGroups.setState(av.getColourAppliesToAllGroups()); showNpFeatsMenuitem.setSelected(av.isShowNPFeats()); showDbRefsMenuitem.setSelected(av.isShowDBRefs()); - autoCalculate.setSelected(av.autoCalculateConsensus); + autoCalculate.setSelected(av.getAutoCalculateConsensusAndConservation()); sortByTree.setSelected(av.sortByTree); listenToViewSelections.setSelected(av.followSelection); @@ -1027,103 +1056,107 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void addFromFile_actionPerformed(ActionEvent e) { - Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport); + Desktop.getInstance().inputLocalFileMenuItem_actionPerformed(viewport); } @Override public void reload_actionPerformed(ActionEvent e) { - if (fileName != null) + if (fileName == null) + { + return; + } + // TODO: JAL-1108 - ensure all associated frames are closed regardless of + // originating file's format + // TODO: work out how to recover feature settings for correct view(s) when + // file is reloaded. + if (FileFormat.Jalview.equals(currentFileFormat)) { - // TODO: JAL-1108 - ensure all associated frames are closed regardless of - // originating file's format - // TODO: work out how to recover feature settings for correct view(s) when - // file is reloaded. - if (FileFormat.Jalview.equals(currentFileFormat)) + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); + for (int i = 0; i < frames.length; i++) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); - for (int i = 0; i < frames.length; i++) + if (frames[i] instanceof AlignFrame && frames[i] != this + && ((AlignFrame) frames[i]).fileName != null + && ((AlignFrame) frames[i]).fileName.equals(fileName)) { - if (frames[i] instanceof AlignFrame && frames[i] != this - && ((AlignFrame) frames[i]).fileName != null - && ((AlignFrame) frames[i]).fileName.equals(fileName)) + try + { + frames[i].setSelected(true); + Desktop.getInstance().closeAssociatedWindows(); + } catch (java.beans.PropertyVetoException ex) { - try - { - frames[i].setSelected(true); - Desktop.instance.closeAssociatedWindows(); - } catch (java.beans.PropertyVetoException ex) - { - } } - } - Desktop.instance.closeAssociatedWindows(); - FileLoader loader = new FileLoader(); - DataSourceType protocol = fileName.startsWith("http:") - ? DataSourceType.URL - : DataSourceType.FILE; - loader.LoadFile(viewport, fileName, protocol, currentFileFormat); } + Desktop.getInstance().closeAssociatedWindows(); + + FileLoader loader = new FileLoader(); + DataSourceType protocol = fileName.startsWith("http:") + ? DataSourceType.URL + : DataSourceType.FILE; + if (fileObject == null) + loader.LoadFile(fileName, protocol, currentFileFormat); else - { - Rectangle bounds = this.getBounds(); - - FileLoader loader = new FileLoader(); + loader.loadFile(null, (File) fileObject, protocol, currentFileFormat); + } + else + { + Rectangle bounds = this.getBounds(); - AlignFrame newframe = null; + FileLoader loader = new FileLoader(); - if (fileObject == null) - { + AlignFrame newframe = null; - DataSourceType protocol = (fileName.startsWith("http:") - ? DataSourceType.URL - : DataSourceType.FILE); - newframe = loader.LoadFileWaitTillLoaded(fileName, protocol, - currentFileFormat); - } - else - { - newframe = loader.LoadFileWaitTillLoaded(fileObject, - DataSourceType.FILE, currentFileFormat); - } + if (fileObject == null) + { +// BH! Q: What about https? + DataSourceType protocol = (fileName.startsWith("http:") + ? DataSourceType.URL + : DataSourceType.FILE); + newframe = loader.LoadFileWaitTillLoaded(fileName, protocol, + currentFileFormat); + } + else + { + newframe = loader.loadFileWaitTillLoaded((File) fileObject, + DataSourceType.FILE, currentFileFormat); + } - newframe.setBounds(bounds); - if (featureSettings != null && featureSettings.isShowing()) + newframe.setBounds(bounds); + if (featureSettings != null && featureSettings.isShowing()) + { + final Rectangle fspos = featureSettings.frame.getBounds(); + // TODO: need a 'show feature settings' function that takes bounds - + // need to refactor Desktop.addFrame + newframe.featureSettings_actionPerformed(null); + final FeatureSettings nfs = newframe.featureSettings; + Jalview.execRunnable(new Runnable() { - final Rectangle fspos = featureSettings.frame.getBounds(); - // TODO: need a 'show feature settings' function that takes bounds - - // need to refactor Desktop.addFrame - newframe.featureSettings_actionPerformed(null); - final FeatureSettings nfs = newframe.featureSettings; - SwingUtilities.invokeLater(new Runnable() + @Override + public void run() { - @Override - public void run() - { - nfs.frame.setBounds(fspos); - } - }); - this.featureSettings.close(); - this.featureSettings = null; - } - this.closeMenuItem_actionPerformed(true); + nfs.frame.setBounds(fspos); + } + }); + this.featureSettings.close(); + this.featureSettings = null; } + this.closeMenuItem_actionPerformed(true); } } @Override public void addFromText_actionPerformed(ActionEvent e) { - Desktop.instance + Desktop.getInstance() .inputTextboxMenuItem_actionPerformed(viewport.getAlignPanel()); } @Override public void addFromURL_actionPerformed(ActionEvent e) { - Desktop.instance.inputURLMenuItem_actionPerformed(viewport); + Desktop.getInstance().inputURLMenuItem_actionPerformed(viewport); } @Override @@ -1167,7 +1200,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // todo is this (2005) test now obsolete - value is never null? while (currentFileFormat == null) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.select_file_format_before_saving"), MessageManager.getString("label.file_format_not_specified"), @@ -1287,7 +1320,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, try { String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file; - PrintWriter out = new PrintWriter( + PrintWriter out = new PrintWriter( new FileWriter(tempFilePath)); out.print(output); @@ -1543,6 +1576,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, closeView(alignPanel); } } + if (closeAllTabs) { if (featureSettings != null && featureSettings.isOpen()) @@ -1934,16 +1968,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, StringSelection ss = new StringSelection(output); + Desktop d = Desktop.getInstance(); try { - jalview.gui.Desktop.internalCopy = true; + d.internalCopy = true; // Its really worth setting the clipboard contents // to empty before setting the large StringSelection!! Toolkit.getDefaultToolkit().getSystemClipboard() .setContents(new StringSelection(""), null); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, - Desktop.instance); + Desktop.getInstance()); } catch (OutOfMemoryError er) { new OOMWarning("copying region", er); @@ -1963,7 +1998,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, hiddenCutoff, hiddenOffset); } - Desktop.jalviewClipboard = new Object[] { seqs, + d.jalviewClipboard = new Object[] { seqs, viewport.getAlignment().getDataset(), hiddenColumns }; setStatus(MessageManager.formatMessage( "label.copied_sequences_to_clipboard", new Object[] @@ -2035,12 +2070,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, boolean annotationAdded = false; AlignmentI alignment = null; - if (Desktop.jalviewClipboard != null) + Desktop d = Desktop.getInstance(); + + if (d.jalviewClipboard != null) { // The clipboard was filled from within Jalview, we must use the // sequences // And dataset from the copied alignment - SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0]; + SequenceI[] newseq = (SequenceI[]) d.jalviewClipboard[0]; // be doubly sure that we create *new* sequence objects. sequences = new SequenceI[newseq.length]; for (int i = 0; i < newseq.length; i++) @@ -2065,10 +2102,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (newAlignment) { - if (Desktop.jalviewClipboard != null) + if (d.jalviewClipboard != null) { // dataset is inherited - alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]); + alignment.setDataset((Alignment) d.jalviewClipboard[1]); } else { @@ -2084,8 +2121,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, alignment = viewport.getAlignment(); alwidth = alignment.getWidth() + 1; // decide if we need to import sequences from an existing dataset - boolean importDs = Desktop.jalviewClipboard != null - && Desktop.jalviewClipboard[1] != alignment.getDataset(); + boolean importDs = d.jalviewClipboard != null + && d.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 @@ -2287,10 +2324,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, DEFAULT_HEIGHT); String newtitle = new String("Copied sequences"); - if (Desktop.jalviewClipboard != null - && Desktop.jalviewClipboard[2] != null) + if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null) { - HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2]; + HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2]; af.viewport.setHiddenColumns(hc); } @@ -2343,10 +2379,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, DEFAULT_HEIGHT); String newtitle = new String("Flanking alignment"); - if (Desktop.jalviewClipboard != null - && Desktop.jalviewClipboard[2] != null) + Desktop d = Desktop.getInstance(); + + if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null) { - HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2]; + HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2]; af.viewport.setHiddenColumns(hc); } @@ -2407,33 +2444,33 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, Runnable okAction = new Runnable() { - @Override - public void run() - { - 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) - { - try - { - AlignFrame.this.setClosed(true); - } catch (Exception ex) - { - } - } - }}; + @Override + public void run() + { + 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) + { + try + { + AlignFrame.this.setClosed(true); + } catch (Exception ex) + { + } + } + }}; /* * If the cut affects all sequences, prompt for confirmation @@ -2441,20 +2478,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, 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 - { - okAction.run(); - } + if (wholeHeight && wholeWidth) + { + JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()); + 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 + { + okAction.run(); + } } /** @@ -2917,7 +2954,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void gatherViews_actionPerformed(ActionEvent e) { - Desktop.instance.gatherViews(this); + Desktop.getInstance().gatherViews(this); } /** @@ -3302,13 +3339,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { final boolean setVisible = annotationPanelMenuItem.isSelected(); viewport.setShowAnnotation(setVisible); - this.showAllSeqAnnotations.setEnabled(setVisible); - this.hideAllSeqAnnotations.setEnabled(setVisible); - this.showAllAlAnnotations.setEnabled(setVisible); - this.hideAllAlAnnotations.setEnabled(setVisible); + syncAnnotationMenuItems(); alignPanel.updateLayout(); } + private void syncAnnotationMenuItems() + { + final boolean setVisible = annotationPanelMenuItem.isSelected(); + showAllSeqAnnotations.setEnabled(setVisible); + hideAllSeqAnnotations.setEnabled(setVisible); + showAllAlAnnotations.setEnabled(setVisible); + hideAllAlAnnotations.setEnabled(setVisible); + } + + @Override public void alignmentProperties() { @@ -3369,12 +3413,36 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } JInternalFrame frame = new JInternalFrame(); - final OverviewPanel overview = new OverviewPanel(alignPanel); + + // BH 2019.07.26 we allow for an embedded + // undecorated overview with defined size + frame.setName(Jalview.getAppID("overview")); + // + Dimension dim = Platform.getDimIfEmbedded(frame, -1, -1); + if (dim != null && dim.width == 0) + { + dim = null; // hidden, not embedded + } + OverviewPanel overview = new OverviewPanel(alignPanel, dim); + frame.setContentPane(overview); + if (dim == null) + { + dim = new Dimension(); + // was frame.getSize(), but that is 0,0 at this point; + } + else + { + // we are imbedding, and so we have an undecorated frame + // and we can set the the frame dimensions accordingly. + } + // allowing for unresizable option using, style="resize:none" + boolean resizable = (Platform.getEmbeddedAttribute(frame, + "resize") != "none"); Desktop.addInternalFrame(frame, MessageManager .formatMessage("label.overview_params", new Object[] - { this.getTitle() }), true, frame.getWidth(), frame.getHeight(), - true, true); + { this.getTitle() }), true, dim.width, dim.height, resizable, + true); frame.pack(); frame.setLayer(JLayeredPane.PALETTE_LAYER); frame.addInternalFrameListener( @@ -3654,8 +3722,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void autoCalculate_actionPerformed(ActionEvent e) { - viewport.autoCalculateConsensus = autoCalculate.isSelected(); - if (viewport.autoCalculateConsensus) + viewport.setAutoCalculateConsensusAndConservation(autoCalculate.isSelected()); + if (viewport.getAutoCalculateConsensusAndConservation()) { viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences()); @@ -3701,7 +3769,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { if (_s.getLength() < sg.getEndRes()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.getString( "label.selected_region_to_tree_may_only_contain_residues_or_gaps"), MessageManager.getString( @@ -3733,7 +3801,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, frameTitle += this.title; - Desktop.addInternalFrame(tp, frameTitle, 600, 500); + Dimension dim = Platform.getDimIfEmbedded(tp, 600, 500); + Desktop.addInternalFrame(tp, frameTitle, dim.width, dim.height); } /** @@ -4023,7 +4092,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, viewport.setCurrentTree(showNewickTree(fin, filePath).getTree()); } catch (Exception ex) { - JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(), + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), ex.getMessage(), MessageManager .getString("label.problem_reading_tree_file"), JvOptionPane.WARNING_MESSAGE); @@ -4031,7 +4100,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (fin != null && fin.hasWarningMessage()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), fin.getWarningMessage(), MessageManager.getString( "label.possible_problem_with_tree_file"), @@ -4085,15 +4154,24 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (nf.getTree() != null) { tp = new TreePanel(alignPanel, nf, treeTitle, input); - - tp.setSize(w, h); + Dimension dim = Platform.getDimIfEmbedded(tp, -1, -1); + if (dim == null) + { + dim = new Dimension(w, h); + } + else + { + // no offset, either + x = 0; + } + tp.setSize(dim.width, dim.height); if (x > 0 && y > 0) { tp.setLocation(x, y); } - Desktop.addInternalFrame(tp, treeTitle, w, h); + Desktop.addInternalFrame(tp, treeTitle, dim.width, dim.height); } } catch (Exception ex) { @@ -4111,6 +4189,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ public void BuildWebServiceMenu() { + if (Jalview.isSynchronous()) + { + return; + } while (buildingMenu) { try @@ -4159,9 +4241,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, final JMenu dismenu = new JMenu("Protein Disorder"); // JAL-940 - only show secondary structure prediction services from // the legacy server + Hashtable> services = Discoverer + .getInstance().getServices(); if (// Cache.getDefault("SHOW_JWS1_SERVICES", true) - // && - Discoverer.services != null && (Discoverer.services.size() > 0)) + // && + services != null && (services.size() > 0)) { // TODO: refactor to allow list of AbstractName/Handler bindings to // be @@ -4169,8 +4253,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // No MSAWS used any more: // Vector msaws = null; // (Vector) // Discoverer.services.get("MsaWS"); - Vector secstrpr = Discoverer.services - .get("SecStrPred"); + Vector secstrpr = services.get("SecStrPred"); if (secstrpr != null) { // Add any secondary structure prediction services @@ -4221,10 +4304,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, webService.add(me.webServiceNoServices); } // TODO: move into separate menu builder class. - boolean new_sspred = false; + // boolean new_sspred = false; if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer(); + Jws2Discoverer jws2servs = Jws2Discoverer.getInstance(); if (jws2servs != null) { if (jws2servs.hasServices()) @@ -4411,7 +4494,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, final String errorTitle = MessageManager .getString("label.implementation_error") + MessageManager.getString("label.translation_failed"); - JvOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, errorTitle, JvOptionPane.ERROR_MESSAGE); return; } @@ -4421,7 +4504,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, "label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"); final String errorTitle = MessageManager .getString("label.translation_failed"); - JvOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msg, errorTitle, JvOptionPane.WARNING_MESSAGE); } else @@ -4435,7 +4518,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true)) { final SequenceI[] seqs = viewport.getSelectionAsNewSequence(); - viewport.openSplitFrame(af, new Alignment(seqs)); + AlignViewport.openSplitFrame(this, af, new Alignment(seqs)); } else { @@ -4468,7 +4551,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { // BH 2018 return avc.parseFeaturesFile(file, sourceType, - Cache.getDefault("RELAXEDSEQIDMATCHING", false)); + Cache.getDefault(Preferences.RELAXEDSEQIDMATCHING, false)); } @@ -4611,7 +4694,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (filesmatched.size() > 0) { boolean autoAssociate = Cache - .getDefault("AUTOASSOCIATE_PDBANDSEQS", false); + .getDefault(Preferences.AUTOASSOCIATE_PDBANDSEQS, false); if (!autoAssociate) { String msg = MessageManager.formatMessage( @@ -4634,10 +4717,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // associating PDB files which have no IDs. for (SequenceI toassoc : (SequenceI[]) fm[2]) { - PDBEntry pe = new AssociatePdbFileWithSeq() + // BH! check + PDBEntry pe = AssociatePdbFileWithSeq .associatePdbWithSeq(fm[0].toString(), - (DataSourceType) fm[1], toassoc, false, - Desktop.instance); + (DataSourceType) fm[1], toassoc, false); if (pe != null) { System.err.println("Associated file : " @@ -4748,7 +4831,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { // some problem - if no warning its probable that the ID matching // process didn't work - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), tcf.getWarningMessage() == null ? MessageManager.getString( "label.check_file_matches_sequence_ids_alignment") @@ -4809,23 +4892,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } else { - alignPanel.paintAlignment(true, true); - } + alignPanel.paintAlignment(true, true); } } + } else { - new FileLoader().LoadFile(viewport, file, sourceType, format); + if (file instanceof File) { + new FileLoader().loadFile(viewport, (File) file, sourceType, format); + } else { + new FileLoader().LoadFile(viewport, (String) file, sourceType, format); + } } } } if (isAnnotation) { - - alignPanel.adjustAnnotationHeight(); - viewport.updateSequenceIdColours(); - buildSortByAnnotationScoresMenu(); - alignPanel.paintAlignment(true, true); + updateForAnnotations(); } } catch (Exception ex) { @@ -4849,11 +4932,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, + (format != null ? "(parsing as '" + format + "' file)" : ""), - oom, Desktop.desktop); + oom, Desktop.getDesktopPane()); } } /** + * Do all updates necessary after an annotation file such as jnet. Also called + * from Jalview.loadAppletParams for "annotations", "jnetFile" + */ + public void updateForAnnotations() + { + alignPanel.adjustAnnotationHeight(); + viewport.updateSequenceIdColours(); + buildSortByAnnotationScoresMenu(); + alignPanel.paintAlignment(true, true); + } + + /** * Method invoked by the ChangeListener on the tabbed pane, in other words * when a different tabbed pane is selected by the user or programmatically. */ @@ -4873,7 +4968,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { // refresh the featureSettings to reflect UI change showFeatureSettingsUI(); - } + } else { // close feature settings for this view. @@ -4951,6 +5046,32 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } /** + * Change the display state for the given feature groups -- Added by BH from + * JalviewLite + * + * @param groups + * list of group strings + * @param state + * visible or invisible + */ + public void setFeatureGroupState(String[] groups, boolean state) + { + jalview.api.FeatureRenderer fr = null; + viewport.setShowSequenceFeatures(true); + if (alignPanel != null + && (fr = alignPanel.getFeatureRenderer()) != null) + { + + fr.setGroupVisibility(Arrays.asList(groups), state); + alignPanel.getSeqPanel().seqCanvas.repaint(); + if (alignPanel.overviewPanel != null) + { + alignPanel.overviewPanel.updateOverviewImage(); + } + } + } + + /** * Open the dialog for regex description parsing. */ @Override @@ -5096,19 +5217,18 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, }); rfetch.add(fetchr); - new Thread(new Runnable() + Jalview.execThread(new Thread(new Runnable() { @Override public void run() { - final jalview.ws.SequenceFetcher sf = jalview.gui.SequenceFetcher - .getSequenceFetcherSingleton(); - javax.swing.SwingUtilities.invokeLater(new Runnable() + Jalview.execRunnable(new Runnable() { @Override public void run() { - String[] dbclasses = sf.getNonAlignmentSources(); + String[] dbclasses = jalview.ws.SequenceFetcher.getInstance() + .getNonAlignmentSources(); List otherdb; JMenu dfetch = new JMenu(); JMenu ifetch = new JMenu(); @@ -5118,7 +5238,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, int dbi = 0; for (String dbclass : dbclasses) { - otherdb = sf.getSourceProxy(dbclass); + otherdb = jalview.ws.SequenceFetcher.getInstance() + .getSourceProxy(dbclass); // add a single entry for this class, or submenu allowing 'fetch // all' or pick one if (otherdb == null || otherdb.size() < 1) @@ -5131,9 +5252,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (otherdb.size() == 1) { - final DbSourceProxy[] dassource = otherdb - .toArray(new DbSourceProxy[0]); + // BH cleaner code DbSourceProxy src = otherdb.get(0); + DbSourceProxy[] dassource = new DbSourceProxy[] { + src }; fetchr = new JMenuItem(src.getDbSource()); fetchr.addActionListener(new ActionListener() { @@ -5324,7 +5446,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } }); } - }).start(); + })); } @@ -5684,7 +5806,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } catch (Exception ex) { System.err.println((ex.toString())); - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.couldnt_run_groovy_script"), MessageManager.getString("label.groovy_support_failed"), JvOptionPane.ERROR_MESSAGE); @@ -5795,6 +5917,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } + private Rectangle lastFeatureSettingsBounds = null; @Override public void setFeatureSettingsGeometry(Rectangle bounds) @@ -5807,6 +5930,68 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { return lastFeatureSettingsBounds; } + + /** + * BH 2019 from JalviewLite + * + * get sequence feature groups that are hidden or shown + * + * @param visible + * true is visible + * @return list + */ + public String[] getFeatureGroupsOfState(boolean visible) + { + jalview.api.FeatureRenderer fr = null; + if (alignPanel != null + && (fr = alignPanel + .getFeatureRenderer()) != null) + { + List gps = fr.getGroups(visible); + String[] _gps = gps.toArray(new String[gps.size()]); + return _gps; + } + return null; + } + + public void scrollTo(int row, int column) + { + alignPanel.getSeqPanel().scrollTo(row, column); + } + + public void scrollToRow(int row) + { + alignPanel.getSeqPanel().scrollToRow(row); + } + + public void scrollToColumn(int column) + { + alignPanel.getSeqPanel().scrollToColumn(column); + } + + /** + * + * @return list of feature groups on the view + */ + public String[] getFeatureGroups() + { + jalview.api.FeatureRenderer fr = null; + if (alignPanel != null + && (fr = alignPanel.getFeatureRenderer()) != null) + { + List gps = fr.getFeatureGroups(); + String[] _gps = gps.toArray(new String[gps.size()]); + return _gps; + } + return null; + } + + public void select(SequenceGroup sel, ColumnSelection csel, + HiddenColumns hidden) + { + alignPanel.getSeqPanel().selection(sel, csel, hidden, null); + } + } class PrintThread extends Thread @@ -5845,4 +6030,5 @@ class PrintThread extends Thread } } } + } diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 140f77e..954cfcc 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -208,24 +208,29 @@ public class AlignViewport extends AlignmentViewport */ private void applyViewProperties() { - antiAlias = Cache.getDefault("ANTI_ALIAS", true); - - viewStyle.setShowJVSuffix(Cache.getDefault("SHOW_JVSUFFIX", true)); - setShowAnnotation(Cache.getDefault("SHOW_ANNOTATIONS", true)); - - setRightAlignIds(Cache.getDefault("RIGHT_ALIGN_IDS", false)); - setCentreColumnLabels(Cache.getDefault("CENTRE_COLUMN_LABELS", false)); - autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true); - - setPadGaps(Cache.getDefault("PAD_GAPS", true)); - setShowNPFeats(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true)); - setShowDBRefs(Cache.getDefault("SHOW_DBREFS_TOOLTIP", true)); - viewStyle.setSeqNameItalics(Cache.getDefault("ID_ITALICS", true)); - viewStyle.setWrapAlignment(Cache.getDefault("WRAP_ALIGNMENT", false)); + // BH! using final static strings here because we also use these in + // JS version startup api + // BH was false + antiAlias = Cache.getDefault(Preferences.ANTI_ALIAS, true); + + viewStyle.setShowJVSuffix( + Cache.getDefault(Preferences.SHOW_JVSUFFIX, true)); + setShowAnnotation(Cache.getDefault(Preferences.SHOW_ANNOTATIONS, true)); + + setRightAlignIds(Cache.getDefault(Preferences.RIGHT_ALIGN_IDS, false)); + setCentreColumnLabels(Cache.getDefault(Preferences.CENTRE_COLUMN_LABELS, false)); + autoCalculateConsensusAndConservation = Cache.getDefault(Preferences.AUTO_CALC_CONSENSUS, true); + + setPadGaps(Cache.getDefault(Preferences.PAD_GAPS, true)); + setShowNPFeats(Cache.getDefault(Preferences.SHOW_NPFEATS_TOOLTIP, true)); + setShowDBRefs(Cache.getDefault(Preferences.SHOW_DBREFS_TOOLTIP, true)); + viewStyle.setSeqNameItalics(Cache.getDefault(Preferences.ID_ITALICS, true)); + viewStyle.setWrapAlignment( + Cache.getDefault(Preferences.WRAP_ALIGNMENT, false)); viewStyle.setShowUnconserved( - Cache.getDefault("SHOW_UNCONSERVED", false)); - sortByTree = Cache.getDefault("SORT_BY_TREE", false); - followSelection = Cache.getDefault("FOLLOW_SELECTIONS", true); + Cache.getDefault(Preferences.SHOW_UNCONSERVED, false)); + sortByTree = Cache.getDefault(Preferences.SORT_BY_TREE, false); + followSelection = Cache.getDefault(Preferences.FOLLOW_SELECTIONS, true); sortAnnotationsBy = SequenceAnnotationOrder .valueOf(Cache.getDefault(Preferences.SORT_ANNOTATIONS, SequenceAnnotationOrder.NONE.name())); @@ -239,9 +244,10 @@ public class AlignViewport extends AlignmentViewport { applyViewProperties(); - String fontName = Cache.getDefault("FONT_NAME", "SansSerif"); - String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + ""); - String fontSize = Cache.getDefault("FONT_SIZE", "10"); + String fontName = Cache.getDefault(Preferences.FONT_NAME, "SansSerif"); + String fontStyle = Cache.getDefault(Preferences.FONT_STYLE, + Font.PLAIN + ""); + String fontSize = Cache.getDefault(Preferences.FONT_SIZE, "10"); int style = 0; @@ -257,7 +263,8 @@ public class AlignViewport extends AlignmentViewport setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true); alignment - .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0)); + .setGapCharacter(Cache.getDefault(Preferences.GAP_SYMBOL, "-") + .charAt(0)); // We must set conservation and consensus before setting colour, // as Blosum and Clustal require this to be done @@ -265,18 +272,22 @@ public class AlignViewport extends AlignmentViewport { if (!alignment.isNucleotide()) { - showConservation = Cache.getDefault("SHOW_CONSERVATION", true); - showQuality = Cache.getDefault("SHOW_QUALITY", true); - showGroupConservation = Cache.getDefault("SHOW_GROUP_CONSERVATION", - false); + showConservation = Cache.getDefault(Preferences.SHOW_CONSERVATION, + true); + showQuality = Cache.getDefault(Preferences.SHOW_QUALITY, true); + showGroupConservation = Cache + .getDefault(Preferences.SHOW_GROUP_CONSERVATION, false); } - showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", - true); - showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false); - normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO", + showConsensusHistogram = Cache + .getDefault(Preferences.SHOW_CONSENSUS_HISTOGRAM, true); + showSequenceLogo = Cache.getDefault(Preferences.SHOW_CONSENSUS_LOGO, false); - showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false); - showConsensus = Cache.getDefault("SHOW_IDENTITY", true); + + normaliseSequenceLogo = Cache + .getDefault(Preferences.NORMALISE_CONSENSUS_LOGO, false); + showGroupConsensus = Cache + .getDefault(Preferences.SHOW_GROUP_CONSENSUS, false); + showConsensus = Cache.getDefault(Preferences.SHOW_IDENTITY, true); showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true); } @@ -385,9 +396,8 @@ public class AlignViewport extends AlignmentViewport */ if (align != null) { - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - ssm.registerMappings(align.getCodonFrames()); + Desktop.getStructureSelectionManager() + .registerMappings(align.getCodonFrames()); } /* @@ -407,8 +417,8 @@ public class AlignViewport extends AlignmentViewport List mappings = al.getCodonFrames(); if (mappings != null) { - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); for (AlignedCodonFrame acf : mappings) { if (noReferencesTo(acf)) @@ -533,12 +543,10 @@ public class AlignViewport extends AlignmentViewport @Override public void sendSelection() { - jalview.structure.StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) - .sendSelection(new SequenceGroup(getSelectionGroup()), - new ColumnSelection(getColumnSelection()), - new HiddenColumns(getAlignment().getHiddenColumns()), - this); + Desktop.getStructureSelectionManager().sendSelection( + new SequenceGroup(getSelectionGroup()), + new ColumnSelection(getColumnSelection()), + new HiddenColumns(getAlignment().getHiddenColumns()), this); } /** @@ -579,8 +587,7 @@ public class AlignViewport extends AlignmentViewport @Override public StructureSelectionManager getStructureSelectionManager() { - return StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + return Desktop.getStructureSelectionManager(); } @Override @@ -749,6 +756,12 @@ public class AlignViewport extends AlignmentViewport firePropertyChange("alignment", null, getAlignment().getSequences()); } + public final static int NO_SPLIT = 0; + + public final static int SPLIT_FRAME = 1; + + public final static int NEW_WINDOW = 2; + /** * Show a dialog with the option to open and link (cDNA <-> protein) as a new * alignment, either as a standalone alignment or in a split frame. Returns @@ -765,54 +778,62 @@ public class AlignViewport extends AlignmentViewport MessageManager.getString("label.new_window"), }; final String question = JvSwingUtils.wrapTooltip(true, MessageManager.getString("label.open_split_window?")); - final AlignViewport us = this; - + /* * options No, Split Window, New Window correspond to * dialog responses 0, 1, 2 (even though JOptionPane shows them * in reverse order) */ - JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop) - .setResponseHandler(0, new Runnable() + JvOptionPane dialog = JvOptionPane + .newOptionDialog(Desktop.getDesktopPane()) + .setResponseHandler(NO_SPLIT, new Runnable() { @Override public void run() { - addDataToAlignment(al); + addDataToAlignment(al); } - }).setResponseHandler(1, new Runnable() + }).setResponseHandler(SPLIT_FRAME, new Runnable() { @Override public void run() { - us.openLinkedAlignmentAs(al, title, true); + openLinkedAlignmentAs(getAlignPanel().alignFrame, + new Alignment(getAlignment()), al, title, + SPLIT_FRAME); } - }).setResponseHandler(2, new Runnable() + }).setResponseHandler(NEW_WINDOW, new Runnable() { @Override public void run() { - us.openLinkedAlignmentAs(al, title, false); + openLinkedAlignmentAs(null, getAlignment(), al, title, + NEW_WINDOW); } }); - dialog.showDialog(question, + dialog.showDialog(question, MessageManager.getString("label.open_split_window"), JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options, options[0]); } - protected void openLinkedAlignmentAs(AlignmentI al, String title, - boolean newWindowOrSplitPane) - { - /* - * Identify protein and dna alignments. Make a copy of this one if opening - * in a new split pane. - */ - AlignmentI thisAlignment = newWindowOrSplitPane - ? new Alignment(getAlignment()) - : getAlignment(); + /** + * Open a split frame or a new window + * + * @param al + * @param title + * @param mode + * SPLIT_FRAME or NEW_WINDOW + */ + public static void openLinkedAlignmentAs(AlignFrame thisFrame, + AlignmentI thisAlignment, AlignmentI al, String title, int mode) + { + // BH: thisAlignment is already a copy if mode == SPLIT_FRAME + // Identify protein and dna alignments. Make a copy of this one if opening + // in a new split pane. + AlignmentI protein = al.isNucleotide() ? thisAlignment : al; - final AlignmentI cdna = al.isNucleotide() ? al : thisAlignment; + AlignmentI cdna = al.isNucleotide() ? al : thisAlignment; /* * Map sequences. At least one should get mapped as we have already passed @@ -841,7 +862,7 @@ public class AlignViewport extends AlignmentViewport // alignFrame.setFileName(file, format); // } - if (!newWindowOrSplitPane) + if (mode == NEW_WINDOW) { Desktop.addInternalFrame(newAlignFrame, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); @@ -849,16 +870,15 @@ public class AlignViewport extends AlignmentViewport try { - newAlignFrame.setMaximum( - jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false)); + newAlignFrame.setMaximum(Cache.getDefault(Preferences.SHOW_FULLSCREEN, false)); } catch (java.beans.PropertyVetoException ex) { } - if (newWindowOrSplitPane) + if (mode == SPLIT_FRAME) { al.alignAs(thisAlignment); - protein = openSplitFrame(newAlignFrame, thisAlignment); + openSplitFrame(thisFrame, newAlignFrame, thisAlignment); } } @@ -872,8 +892,8 @@ public class AlignViewport extends AlignmentViewport * cdna/protein complement alignment to show in the other split half * @return the protein alignment in the split frame */ - protected AlignmentI openSplitFrame(AlignFrame newAlignFrame, - AlignmentI complement) + static protected AlignmentI openSplitFrame(AlignFrame thisFrame, + AlignFrame newAlignFrame, AlignmentI complement) { /* * Make a new frame with a copy of the alignment we are adding to. If this @@ -882,7 +902,7 @@ public class AlignViewport extends AlignmentViewport */ AlignFrame copyMe = new AlignFrame(complement, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - copyMe.setTitle(getAlignPanel().alignFrame.getTitle()); + copyMe.setTitle(thisFrame.getTitle()); AlignmentI al = newAlignFrame.viewport.getAlignment(); final AlignFrame proteinFrame = al.isNucleotide() ? copyMe @@ -1045,11 +1065,11 @@ public class AlignViewport extends AlignmentViewport { return; } - + FeatureRenderer fr = getAlignPanel().getSeqPanel().seqCanvas .getFeatureRenderer(); - List origRenderOrder = new ArrayList(), - origGroups = new ArrayList(); + List origRenderOrder = new ArrayList<>(), + origGroups = new ArrayList<>(); // preserve original render order - allows differentiation between user configured colours and autogenerated ones origRenderOrder.addAll(fr.getRenderOrder()); origGroups.addAll(fr.getFeatureGroups()); @@ -1059,8 +1079,8 @@ public class AlignViewport extends AlignmentViewport FeaturesDisplayedI displayed = fr.getFeaturesDisplayed(); if (!mergeOnly) { - // only clear displayed features if we are mergeing - displayed.clear(); + // only clear displayed features if we are merging + displayed.clear(); } // TODO this clears displayed.featuresRegistered - do we care? // @@ -1084,15 +1104,15 @@ public class AlignViewport extends AlignmentViewport { // if we are merging, only update if there wasn't already a colour defined for // this type - if (preferredColour != null) - { - fr.setColour(type, preferredColour); - } - if (featureSettings.isFeatureDisplayed(type)) - { - displayed.setVisible(type); - } + if (preferredColour != null) + { + fr.setColour(type, preferredColour); } + if (featureSettings.isFeatureDisplayed(type)) + { + displayed.setVisible(type); + } + } } /* diff --git a/src/jalview/gui/AnnotationColourChooser.java b/src/jalview/gui/AnnotationColourChooser.java index e89c1c2..bd05be1 100644 --- a/src/jalview/gui/AnnotationColourChooser.java +++ b/src/jalview/gui/AnnotationColourChooser.java @@ -301,7 +301,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter updateView(); } }; - JalviewColourChooser.showColourChooser(Desktop.getDesktop(), ttl, + JalviewColourChooser.showColourChooser(Desktop.getDesktopPane(), ttl, colourPanel.getBackground(), listener); } diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index 5a681f1..27dcebf 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -971,7 +971,7 @@ public class AnnotationLabels extends JPanel seqs, omitHidden, alignmentStartEnd); Toolkit.getDefaultToolkit().getSystemClipboard() - .setContents(new StringSelection(output), Desktop.instance); + .setContents(new StringSelection(output), Desktop.getInstance()); HiddenColumns hiddenColumns = null; diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index e13df4a..afb727f 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -546,7 +546,7 @@ public class AppJmol extends StructureViewerBase } if (errormsgs.length() > 0) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.pdb_entries_couldnt_be_retrieved", new String[] { errormsgs.toString() }), diff --git a/src/jalview/gui/AssociatePdbFileWithSeq.java b/src/jalview/gui/AssociatePdbFileWithSeq.java index fe0aedf..1f540da 100644 --- a/src/jalview/gui/AssociatePdbFileWithSeq.java +++ b/src/jalview/gui/AssociatePdbFileWithSeq.java @@ -20,18 +20,15 @@ */ package jalview.gui; -import jalview.api.StructureSelectionManagerProvider; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; import jalview.io.StructureFile; -import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; -import javax.swing.JOptionPane; - /** - * GUI related routines for associating PDB files with sequences + * GUI related routines for associating PDB files with sequences. A single + * static method. * * @author JimP * @@ -39,58 +36,56 @@ import javax.swing.JOptionPane; public class AssociatePdbFileWithSeq { + private AssociatePdbFileWithSeq() + { + // inaccessible + } + /** - * assocate the given PDB file with + * Associate the given PDB file name or URL with a sequence. Do not map + * mouse-over events. * - * @param choice + * @param fileName + * or URL + * @param type + * will be DataType.FILE or DataType.URL * @param sequence + * to associate + * @param prompt + * true if the user should be asked what to do if the specified file + * does not seem to contain PDB information (StructureChooser only) + * @return null if file is not found */ - public PDBEntry associatePdbWithSeq(String choice, DataSourceType file, - SequenceI sequence, boolean prompt, - StructureSelectionManagerProvider ssmp) + public static PDBEntry associatePdbWithSeq(String fileName, + DataSourceType type, SequenceI sequence, boolean prompt) { PDBEntry entry = new PDBEntry(); StructureFile pdbfile = null; - pdbfile = StructureSelectionManager.getStructureSelectionManager(ssmp) + pdbfile = Desktop.getStructureSelectionManager() .setMapping(false, new SequenceI[] - { sequence }, null, choice, file); + { sequence }, null, fileName, type); if (pdbfile == null) { // stacktrace already thrown so just return return null; } - if (pdbfile.getId() == null) - { - String reply = null; - - if (prompt) - { - reply = JvOptionPane.showInternalInputDialog(Desktop.desktop, - MessageManager - .getString("label.couldnt_find_pdb_id_in_file"), - MessageManager.getString("label.no_pdb_id_in_file"), - JvOptionPane.QUESTION_MESSAGE); - } - if (reply == null) - { - return null; - } - - entry.setId(reply); - } - else + String id = pdbfile.getId(); + if (id == null && (id = (prompt + ? JvOptionPane.showInternalInputDialog(Desktop.getDesktopPane(), + MessageManager + .getString("label.couldnt_find_pdb_id_in_file"), + MessageManager.getString("label.no_pdb_id_in_file"), + JvOptionPane.QUESTION_MESSAGE) + : null)) == null) { - entry.setId(pdbfile.getId()); + return null; } + entry.setId(id); entry.setType(PDBEntry.Type.FILE); - - if (pdbfile != null) - { - entry.setFile(choice); - sequence.getDatasetSequence().addPDBId(entry); - StructureSelectionManager.getStructureSelectionManager(ssmp) - .registerPDBEntry(entry); - } + entry.setFile(fileName); + sequence.getDatasetSequence().addPDBId(entry); + Desktop.getInstance().getStructureSelectionManager() + .registerPDBEntry(entry); return entry; } } diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index 097a5a0..5248306 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -62,8 +62,13 @@ import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; /** - * A dialog where a user can choose and action Tree or PCA calculation options + * A dialog where a user can choose and action Tree or PCA calculation options. + * + * Allows also for dialog-free static methods openPCAPanel(...) and + * openTreePanel(...) for scripted use. + * */ +@SuppressWarnings("serial") public class CalculationChooser extends JPanel { /* @@ -74,7 +79,7 @@ public class CalculationChooser extends JPanel */ private static boolean treeMatchGaps = true; - private static final Font VERDANA_11PT = new Font("Verdana", 0, 11); + private static Font VERDANA_11PT; private static final int MIN_TREE_SELECTION = 3; @@ -102,7 +107,7 @@ public class CalculationChooser extends JPanel private JCheckBox shorterSequence; - final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer(); + private static ComboBoxTooltipRenderer renderer; // BH was not static List tips = new ArrayList<>(); @@ -112,6 +117,37 @@ public class CalculationChooser extends JPanel private PCAPanel pcaPanel; /** + * Open a new Tree panel on the desktop statically. Params are standard (not + * set by Groovy). No dialog is opened. + * + * @param af + * @param treeType + * @param modelName + * @return null if successful; the string + * "label.you_need_at_least_n_sequences" if number of sequences + * selected is inappropriate + */ + public static Object openTreePanel(AlignFrame af, String treeType, + String modelName) + { + return openTreePanel(af, treeType, modelName, null); + } + + /** + * public static method for JalviewJS API to open a PCAPanel without + * necessarily using a dialog. + * + * @param af + * @param modelName + * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences" + * if number of sequences selected is inappropriate + */ + public static Object openPcaPanel(AlignFrame af, String modelName) + { + return openPcaPanel(af, modelName, null); + } + + /** * Constructor * * @param af @@ -232,6 +268,10 @@ public class CalculationChooser extends JPanel paramsPanel.add(includeGappedColumns); paramsPanel.add(shorterSequence); + if (VERDANA_11PT == null) + { + VERDANA_11PT = new Font("Verdana", 0, 11); + } /* * OK / Cancel buttons */ @@ -380,7 +420,11 @@ public class CalculationChooser extends JPanel */ protected JComboBox buildModelOptionsList() { - final JComboBox scoreModelsCombo = new JComboBox<>(); + JComboBox scoreModelsCombo = new JComboBox<>(); + if (renderer == null) + { + renderer = new ComboBoxTooltipRenderer(); + } scoreModelsCombo.setRenderer(renderer); /* @@ -500,7 +544,8 @@ public class CalculationChooser extends JPanel * for backwards compatibility with Jalview < 2.8 (JAL-2962) */ if (nucleotide && forPca - && Cache.getDefault("BLOSUM62_PCA_FOR_NUCLEOTIDE", false)) + && Cache.getDefault(Preferences.BLOSUM62_PCA_FOR_NUCLEOTIDE, + false)) { filtered.add(scoreModels.getBlosum62()); } @@ -537,6 +582,63 @@ public class CalculationChooser extends JPanel */ protected void openTreePanel(String modelName, SimilarityParamsI params) { + Object ret = openTreePanel(af, + neighbourJoining.isSelected() ? TreeBuilder.NEIGHBOUR_JOINING + : TreeBuilder.AVERAGE_DISTANCE, + modelName, params); + if (ret instanceof String) + { + JvOptionPane.showMessageDialog(this, // was opening on Desktop? + MessageManager.formatMessage( + (String) ret, + MIN_TREE_SELECTION), + MessageManager.getString("label.not_enough_sequences"), + JvOptionPane.WARNING_MESSAGE); + + } + } + + /** + * Open a new PCA panel on the desktop + * + * @param modelName + * @param params + */ + protected void openPcaPanel(String modelName, SimilarityParamsI params) + { + Object ret = openPcaPanel(af, modelName, params); + if (ret instanceof String) + { + JvOptionPane.showInternalMessageDialog(this, + MessageManager.formatMessage( + (String) ret, + MIN_PCA_SELECTION), + MessageManager + .getString("label.sequence_selection_insufficient"), + JvOptionPane.WARNING_MESSAGE); + } + else + { + // only used for test suite + pcaPanel = (PCAPanel) ret; + } + + } + + /** + * Open a new Tree panel on the desktop statically + * + * @param af + * @param treeType + * @param modelName + * @param params + * @return null, or the string "label.you_need_at_least_n_sequences" if number + * of sequences selected is inappropriate + */ + public static Object openTreePanel(AlignFrame af, String treeType, + String modelName, SimilarityParamsI params) + { + /* * gui validation shouldn't allow insufficient sequences here, but leave * this check in in case this method gets exposed programmatically in future @@ -545,56 +647,58 @@ public class CalculationChooser extends JPanel SequenceGroup sg = viewport.getSelectionGroup(); if (sg != null && sg.getSize() < MIN_TREE_SELECTION) { - JvOptionPane.showMessageDialog(Desktop.desktop, - MessageManager.formatMessage( - "label.you_need_at_least_n_sequences", - MIN_TREE_SELECTION), - MessageManager.getString("label.not_enough_sequences"), - JvOptionPane.WARNING_MESSAGE); - return; + return "label.you_need_at_least_n_sequences"; + } + + if (params == null) + { + params = getSimilarityParameters(false); } - String treeType = neighbourJoining.isSelected() - ? TreeBuilder.NEIGHBOUR_JOINING - : TreeBuilder.AVERAGE_DISTANCE; af.newTreePanel(treeType, modelName, params); + return null; } /** - * Open a new PCA panel on the desktop + * public static method for JalviewJS API * + * @param af * @param modelName * @param params + * @return the PCAPanel, or null if number of sequences selected is + * inappropriate */ - protected void openPcaPanel(String modelName, SimilarityParamsI params) + public static Object openPcaPanel(AlignFrame af, String modelName, + SimilarityParamsI params) { + AlignViewport viewport = af.getViewport(); /* * gui validation shouldn't allow insufficient sequences here, but leave * this check in in case this method gets exposed programmatically in future + * + * */ if (((viewport.getSelectionGroup() != null) && (viewport.getSelectionGroup().getSize() < MIN_PCA_SELECTION) && (viewport.getSelectionGroup().getSize() > 0)) || (viewport.getAlignment().getHeight() < MIN_PCA_SELECTION)) { - JvOptionPane.showInternalMessageDialog(this, - MessageManager.formatMessage( - "label.you_need_at_least_n_sequences", - MIN_PCA_SELECTION), - MessageManager - .getString("label.sequence_selection_insufficient"), - JvOptionPane.WARNING_MESSAGE); - return; + return "label.you_need_at_least_n_sequences"; + } + + if (params == null) + { + params = getSimilarityParameters(true); } /* * construct the panel and kick off its calculation thread */ - pcaPanel = new PCAPanel(af.alignPanel, modelName, params); - new Thread(pcaPanel).start(); - + PCAPanel pcap = new PCAPanel(af.alignPanel, modelName, params); + new Thread(pcap).start(); + return pcap; } /** @@ -610,6 +714,7 @@ public class CalculationChooser extends JPanel } } + /** * Returns a data bean holding parameters for similarity (or distance) model * calculation @@ -617,7 +722,8 @@ public class CalculationChooser extends JPanel * @param doPCA * @return */ - protected SimilarityParamsI getSimilarityParameters(boolean doPCA) + public static SimilarityParamsI getSimilarityParameters( + boolean doPCA) { // commented out: parameter choices read from gui widgets // SimilarityParamsI params = new SimilarityParams( @@ -638,6 +744,7 @@ public class CalculationChooser extends JPanel return new SimilarityParams(includeGapGap, matchGap, includeGapResidue, matchOnShortestLength); + } /** diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index c6d6e97..317eff5 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -336,7 +336,7 @@ public class ChimeraViewFrame extends StructureViewerBase if (!jmb.launchChimera()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.chimera_failed"), MessageManager.getString("label.error_loading_file"), JvOptionPane.ERROR_MESSAGE); @@ -497,7 +497,7 @@ public class ChimeraViewFrame extends StructureViewerBase if (errormsgs.length() > 0) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.pdb_entries_couldnt_be_retrieved", new Object[] { errormsgs.toString() }), diff --git a/src/jalview/gui/ColourMenuHelper.java b/src/jalview/gui/ColourMenuHelper.java index 6eab07d..e38b55b 100644 --- a/src/jalview/gui/ColourMenuHelper.java +++ b/src/jalview/gui/ColourMenuHelper.java @@ -158,7 +158,7 @@ public class ColourMenuHelper ActionListener al = radioItem.getActionListeners()[0]; radioItem.removeActionListener(al); int option = JvOptionPane.showInternalConfirmDialog( - Desktop.desktop, + Desktop.getDesktopPane(), MessageManager .getString("label.remove_from_default_list"), MessageManager @@ -314,7 +314,7 @@ public class ColourMenuHelper } else { - Cache.applicationProperties.remove("USER_DEFINED_COLOURS"); + Cache.removePropertyNoSave("USER_DEFINED_COLOURS"); } } } diff --git a/src/jalview/gui/CrossRefAction.java b/src/jalview/gui/CrossRefAction.java index 2ada4d2..cc25696 100644 --- a/src/jalview/gui/CrossRefAction.java +++ b/src/jalview/gui/CrossRefAction.java @@ -454,7 +454,7 @@ public class CrossRefAction implements Runnable .setGapCharacter(alignFrame.viewport.getGapCharacter()); StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + .getStructureSelectionManager(Desktop.getInstance()); /* * register any new mappings for sequence mouseover etc diff --git a/src/jalview/gui/CutAndPasteTransfer.java b/src/jalview/gui/CutAndPasteTransfer.java index d328a0d..4badcba 100644 --- a/src/jalview/gui/CutAndPasteTransfer.java +++ b/src/jalview/gui/CutAndPasteTransfer.java @@ -234,7 +234,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer .println(MessageManager.getString("label.couldnt_read_data")); if (!Jalview.isHeadlessMode()) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), AppletFormatAdapter.getSupportedFormats(), MessageManager.getString("label.couldnt_read_data"), JvOptionPane.WARNING_MESSAGE); @@ -253,7 +253,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer } catch (IOException ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .formatMessage("label.couldnt_read_pasted_text", new String[] { ex.toString() }), MessageManager.getString("label.error_parsing_text"), @@ -342,7 +342,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer .println(MessageManager.getString("label.couldnt_read_data")); if (!Jalview.isHeadlessMode()) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), AppletFormatAdapter.getSupportedFormats(), MessageManager.getString("label.couldnt_read_data"), JvOptionPane.WARNING_MESSAGE); diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 088d83d..52d7deb 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -51,7 +51,9 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileWriter; + import java.io.IOException; +import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; @@ -90,6 +92,15 @@ import javax.swing.event.HyperlinkEvent.EventType; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; +import java.io.BufferedInputStream; +import java.io.FileOutputStream; +import javax.swing.JFrame; +import jalview.api.StructureSelectionManagerProvider; + import org.stackoverflowusers.file.WindowsShortcut; import jalview.api.AlignViewportI; @@ -132,7 +143,7 @@ import jalview.ws.utils.UrlDownloadClient; */ public class Desktop extends jalview.jbgui.GDesktop implements DropTargetListener, ClipboardOwner, IProgressIndicator, - jalview.api.StructureSelectionManagerProvider + 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" @@ -143,15 +154,15 @@ public class Desktop extends jalview.jbgui.GDesktop private static final String DEFAULT_AUTHORS = "The Jalview Authors (See AUTHORS file for current list)"; - private static int DEFAULT_MIN_WIDTH = 300; + private final static int DEFAULT_MIN_WIDTH = 300; - private static int DEFAULT_MIN_HEIGHT = 250; + private final static int DEFAULT_MIN_HEIGHT = 250; - private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600; + private final static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600; - private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70; + private final static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70; - private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES"; + private final static String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES"; protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT"; @@ -201,16 +212,10 @@ public class Desktop extends jalview.jbgui.GDesktop listener); } - /** Singleton Desktop instance */ - public static Desktop instance; - - public static MyDesktopPane desktop; - - public static MyDesktopPane getDesktop() + public static StructureSelectionManager getStructureSelectionManager() { - // BH 2018 could use currentThread() here as a reference to a - // Hashtable in JavaScript - return desktop; + return StructureSelectionManager + .getStructureSelectionManager(getInstance()); } static int openFrameCount = 0; @@ -219,13 +224,20 @@ public class Desktop extends jalview.jbgui.GDesktop static final int yOffset = 30; - public static jalview.ws.jws1.Discoverer discoverer; + // BH was static + public jalview.ws.jws1.Discoverer discoverer; + + //BH was static + public Object[] jalviewClipboard; + +//BH was static + public boolean internalCopy = false; - public static Object[] jalviewClipboard; + private static int fileLoadingCount = 0; - public static boolean internalCopy = false; + public JInternalFrame conservationSlider; - static int fileLoadingCount = 0; + public JInternalFrame PIDSlider; class MyDesktopManager implements DesktopManager { @@ -246,7 +258,7 @@ public class Desktop extends jalview.jbgui.GDesktop } catch (NullPointerException npe) { Point p = getMousePosition(); - instance.showPasteMenu(p.x, p.y); + showPasteMenu(p.x, p.y); } } @@ -294,14 +306,14 @@ public class Desktop extends jalview.jbgui.GDesktop public void endDraggingFrame(JComponent f) { delegate.endDraggingFrame(f); - desktop.repaint(); + desktopPane.repaint(); } @Override public void endResizingFrame(JComponent f) { delegate.endResizingFrame(f); - desktop.repaint(); + desktopPane.repaint(); } @Override @@ -349,193 +361,206 @@ public class Desktop extends jalview.jbgui.GDesktop // All other methods, simply delegate } - /** - * Creates a new Desktop object. + * Private constructor enforces singleton pattern. It is called by reflection + * from ApplicationSingletonProvider.getInstance(). */ - public Desktop() + private Desktop() { - super(); - /** - * A note to implementors. It is ESSENTIAL that any activities that might - * block are spawned off as threads rather than waited for during this - * constructor. - */ - instance = this; - - doConfigureStructurePrefs(); - setTitle("Jalview " + Cache.getProperty("VERSION")); - /* - if (!Platform.isAMac()) - { - // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - } - else - { - this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - } - */ - + Cache.initLogger(); try { - APQHandlers.setAPQHandlers(this); - } catch (Throwable t) - { - System.out.println("Error setting APQHandlers: " + t.toString()); - // t.printStackTrace(); - } - - addWindowListener(new WindowAdapter() - { + /** + * A note to implementors. It is ESSENTIAL that any activities that might + * block are spawned off as threads rather than waited for during this + * constructor. + */ - @Override - public void windowClosing(WindowEvent ev) + doConfigureStructurePrefs(); + setTitle("Jalview " + Cache.getProperty("VERSION")); + + try { - quit(); + if (Platform.getJavaVersion() >= 11) + { + // BH use reflection so that this code can be in both the Java8 and Java11 versions + Class j11APQHandlers = Class.forName("jalview.gui.APQHandlers"); + Method meth = j11APQHandlers.getMethod("setAPQHandlers", new Class[] {Desktop.class}); + meth.invoke(j11APQHandlers.newInstance(), this); + } + } catch (Throwable t) + { + System.out.println("Desktop Error setting APQHandlers: " + t.toString()); } - }); - boolean selmemusage = Cache.getDefault("SHOW_MEMUSAGE", - false); + addWindowListener(new WindowAdapter() + { + + @Override + public void windowClosing(WindowEvent ev) + { + quit(); + } + }); + + boolean selmemusage = Cache.getDefault("SHOW_MEMUSAGE", + false); boolean showjconsole = Cache.getDefault("SHOW_JAVA_CONSOLE", false); - desktop = new MyDesktopPane(selmemusage); + desktopPane = new MyDesktopPane(selmemusage); showMemusage.setSelected(selmemusage); - desktop.setBackground(Color.white); + desktopPane.setBackground(Color.white); - getContentPane().setLayout(new BorderLayout()); - // alternate config - have scrollbars - see notes in JAL-153 - // JScrollPane sp = new JScrollPane(); - // sp.getViewport().setView(desktop); - // getContentPane().add(sp, BorderLayout.CENTER); + getContentPane().setLayout(new BorderLayout()); + // alternate config - have scrollbars - see notes in JAL-153 + // JScrollPane sp = new JScrollPane(); + // sp.getViewport().setView(desktop); + // getContentPane().add(sp, BorderLayout.CENTER); - // BH 2018 - just an experiment to try unclipped JInternalFrames. - if (Platform.isJS()) - { - getRootPane().putClientProperty("swingjs.overflow.hidden", "false"); - } + // BH 2018 - just an experiment to try unclipped JInternalFrames. + if (Platform.isJS()) + { + getRootPane().putClientProperty("swingjs.overflow.hidden", "false"); + } - getContentPane().add(desktop, BorderLayout.CENTER); - desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); + 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 - desktop.setDesktopManager(new MyDesktopManager( - (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager() - : Platform.isAMacAndNotJS() - ? new AquaInternalFrameManager( - desktop.getDesktopManager()) - : desktop.getDesktopManager()))); + // This line prevents Windows Look&Feel resizing all new windows to + // maximum + // if previous window was maximised + desktopPane.setDesktopManager(new MyDesktopManager( + (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager() + : Platform.isAMacAndNotJS() + ? new AquaInternalFrameManager( + desktopPane.getDesktopManager()) + : desktopPane.getDesktopManager()))); - Rectangle dims = getLastKnownDimensions(""); - if (dims != null) - { - setBounds(dims); - } - else - { - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - int xPos = Math.max(5, (screenSize.width - 900) / 2); - int yPos = Math.max(5, (screenSize.height - 650) / 2); - setBounds(xPos, yPos, 900, 650); - } + Rectangle dims = getLastKnownDimensions(""); + if (dims != null) + { + setBounds(dims); + } + else + { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int xPos = Math.max(5, (screenSize.width - 900) / 2); + int yPos = Math.max(5, (screenSize.height - 650) / 2); + setBounds(xPos, yPos, 900, 650); + } - if (!Platform.isJS()) - /** - * Java only - * - * @j2sIgnore - */ - { - jconsole = new Console(this, showjconsole); - jconsole.setHeader(Cache.getVersionDetailsForConsole()); - showConsole(showjconsole); + // Note that this next syntax, checking for Platform.isJS and also + // escaping the code using @j2sIgnore, serves two purposes. It gives + // us an easily findable tag, Platform.isJS(), to places in the code where + // there is something different about the SwingJS implementation. Second, + // it deletes the unneeded Java-only code form the JavaScript version + // completely (@j2sIgnore), since it will never be used there. - showNews.setVisible(false); + if (!Platform.isJS() && !Jalview.isSynchronous()) + /** + * Java only + * + * @j2sIgnore + */ + { - experimentalFeatures.setSelected(showExperimental()); + jconsole = new Console(this, showjconsole); + jconsole.setHeader(Cache.getVersionDetailsForConsole()); + showConsole(showjconsole); - getIdentifiersOrgData(); + showNews.setVisible(false); - checkURLLinks(); + experimentalFeatures.setSelected(showExperimental()); - // Spawn a thread that shows the splashscreen + getIdentifiersOrgData(); - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - new SplashScreen(true); - } - }); + checkURLLinks(); - // 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() + // Spawn a thread that shows the splashscreen + + SwingUtilities.invokeLater(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 run() + { + new SplashScreen(true); + } + }); - @Override - public void propertyChange(PropertyChangeEvent evt) + // 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() + { + 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() { - Cache.log.debug("Firing service changed event for " - + evt.getNewValue()); - JalviewServicesChanged(evt); - } - }); - } - this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this)); + @Override + public void propertyChange(PropertyChangeEvent evt) + { + Cache.log.debug("Firing service changed event for " + + evt.getNewValue()); + JalviewServicesChanged(evt); + } + + }); - this.addWindowListener(new WindowAdapter() - { - @Override - public void windowClosing(WindowEvent evt) - { - quit(); } - }); - MouseAdapter ma; - this.addMouseListener(ma = new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent evt) + if (!Jalview.isSynchronous()) { - if (evt.isPopupTrigger()) // Mac + this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this)); + + this.addWindowListener(new WindowAdapter() { - showPasteMenu(evt.getX(), evt.getY()); - } - } + @Override + public void windowClosing(WindowEvent evt) + { + quit(); + } + }); - @Override - public void mouseReleased(MouseEvent evt) - { - if (evt.isPopupTrigger()) // Windows + MouseAdapter ma; + this.addMouseListener(ma = new MouseAdapter() { - showPasteMenu(evt.getX(), evt.getY()); - } - } - }); - desktop.addMouseListener(ma); + @Override + public void mousePressed(MouseEvent evt) + { + if (evt.isPopupTrigger()) // Mac + { + showPasteMenu(evt.getX(), evt.getY()); + } + } + @Override + public void mouseReleased(MouseEvent evt) + { + if (evt.isPopupTrigger()) // Windows + { + showPasteMenu(evt.getX(), evt.getY()); + } + } + }); + desktopPane.addMouseListener(ma); + } + } catch (Throwable t) + { + t.printStackTrace(); + } } /** @@ -619,7 +644,7 @@ public class Desktop extends jalview.jbgui.GDesktop showNews(showNews.isSelected()); } - void showNews(boolean visible) + protected void showNews(boolean visible) { Cache.log.debug((visible ? "Showing" : "Hiding") + " news."); showNews.setSelected(visible); @@ -631,10 +656,10 @@ public class Desktop extends jalview.jbgui.GDesktop public void run() { long now = System.currentTimeMillis(); - Desktop.instance.setProgressBar( + setProgressBar( MessageManager.getString("status.refreshing_news"), now); jvnews.refreshNews(); - Desktop.instance.setProgressBar(null, now); + setProgressBar(null, now); jvnews.showNews(); } }).start(); @@ -699,7 +724,7 @@ public class Desktop extends jalview.jbgui.GDesktop return null; } - void showPasteMenu(int x, int y) + protected void showPasteMenu(int x, int y) { JPopupMenu popup = new JPopupMenu(); JMenuItem item = new JMenuItem( @@ -827,13 +852,15 @@ public class Desktop extends jalview.jbgui.GDesktop int w, int h, 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) + // BH fix + if (w > 0 && (frame.getWidth() < 1 || frame.getHeight() < 1)) { frame.setSize(w, h); } @@ -841,8 +868,7 @@ public class Desktop extends jalview.jbgui.GDesktop // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN // IF JALVIEW IS RUNNING HEADLESS // /////////////////////////////////////////////// - if (instance == null || (System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true"))) + if (Jalview.isHeadlessMode()) { return; } @@ -872,7 +898,8 @@ public class Desktop extends jalview.jbgui.GDesktop frame.setIconifiable(resizable); frame.setOpaque(Platform.isJS()); - if (frame.getX() < 1 && frame.getY() < 1) + boolean isEmbedded = (Platform.getDimIfEmbedded(frame, -1, -1) != null); + if (!isEmbedded && frame.getX() < 1 && frame.getY() < 1) { frame.setLocation(xOffset * openFrameCount, yOffset * ((openFrameCount - 1) % 10) + yOffset); @@ -882,13 +909,13 @@ public class Desktop extends jalview.jbgui.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); + JMenuItem menuItem = new JMenuItem(title); frame.addInternalFrameListener(new InternalFrameAdapter() { @Override public void internalFrameActivated(InternalFrameEvent evt) { - JInternalFrame itf = desktop.getSelectedFrame(); + JInternalFrame itf = getDesktopPane().getSelectedFrame(); if (itf != null) { if (itf instanceof AlignFrame) @@ -920,7 +947,7 @@ public class Desktop extends jalview.jbgui.GDesktop { menuItem.removeActionListener(menuItem.getActionListeners()[0]); } - windowMenu.remove(menuItem); + Desktop.getInstance().windowMenu.remove(menuItem); } }); @@ -942,9 +969,9 @@ public class Desktop extends jalview.jbgui.GDesktop setKeyBindings(frame); - desktop.add(frame); + getDesktopPane().add(frame); - windowMenu.add(menuItem); + Desktop.getInstance().windowMenu.add(menuItem); frame.toFront(); try @@ -1002,7 +1029,7 @@ public class Desktop extends jalview.jbgui.GDesktop { if (!internalCopy) { - Desktop.jalviewClipboard = null; + Desktop.getInstance().jalviewClipboard = null; } internalCopy = false; @@ -1237,7 +1264,8 @@ public class Desktop extends jalview.jbgui.GDesktop { String msg = MessageManager .formatMessage("label.couldnt_locate", url); - JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), + msg, MessageManager.getString("label.url_not_found"), JvOptionPane.WARNING_MESSAGE); @@ -1258,7 +1286,8 @@ public class Desktop extends jalview.jbgui.GDesktop }; String dialogOption = MessageManager .getString("label.input_alignment_from_url"); - JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action) + JvOptionPane.newOptionDialog(getDesktopPane()) + .setResponseHandler(0, action) .showInternalDialog(panel, dialogOption, JvOptionPane.YES_NO_CANCEL_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options, @@ -1348,7 +1377,8 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void run() { - new SplashScreen(false); + // BH! true meaning "interactive" here (applet branch); was false in develop version?? + new SplashScreen(true); } }).start(); } @@ -1436,8 +1466,12 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void closeAll_actionPerformed(ActionEvent e) { + if (desktopPane == null) + { + return; + } // TODO show a progress bar while closing? - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = desktopPane.getAllFrames(); for (int i = 0; i < frames.length; i++) { try @@ -1454,12 +1488,7 @@ public class Desktop extends jalview.jbgui.GDesktop * reset state of singleton objects as appropriate (clear down session state * when all windows are closed) */ - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(this); - if (ssm != null) - { - ssm.resetAll(); - } + getStructureSelectionManager().resetAll(); } @Override @@ -1504,7 +1533,7 @@ public class Desktop extends jalview.jbgui.GDesktop @Override protected void showMemusage_actionPerformed(ActionEvent e) { - desktop.showMemoryUsage(showMemusage.isSelected()); + getDesktopPane().showMemoryUsage(showMemusage.isSelected()); } /* @@ -1541,7 +1570,7 @@ public class Desktop extends jalview.jbgui.GDesktop void reorderAssociatedWindows(boolean minimize, boolean close) { - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = getDesktopPane().getAllFrames(); if (frames == null || frames.length < 1) { return; @@ -1725,7 +1754,7 @@ public class Desktop extends jalview.jbgui.GDesktop saveState_actionPerformed(true); } - private void setProjectFile(File choice) + protected void setProjectFile(File choice) { this.projectFile = choice; } @@ -1767,7 +1796,8 @@ public class Desktop extends jalview.jbgui.GDesktop { try { - new Jalview2XML().loadJalviewAlign(choice); + // BH was String "choice" here but needs to be File object + new Jalview2XML().loadJalviewAlign(selectedFile); } catch (OutOfMemoryError oom) { new OOMWarning("Whilst loading project from " + choice, oom); @@ -1775,7 +1805,7 @@ public class Desktop extends jalview.jbgui.GDesktop { Cache.log.error( "Problems whilst loading project from " + choice, ex); - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.error_whilst_loading_project_from", new Object[] @@ -1818,7 +1848,7 @@ public class Desktop extends jalview.jbgui.GDesktop { progressPanel = new JPanel(new GridLayout(1, 1)); totalProgressCount = 0; - instance.getContentPane().add(progressPanel, BorderLayout.SOUTH); + getContentPane().add(progressPanel, BorderLayout.SOUTH); } JPanel thisprogress = new JPanel(new BorderLayout(10, 5)); JProgressBar progressBar = new JProgressBar(); @@ -1831,7 +1861,7 @@ public class Desktop extends jalview.jbgui.GDesktop ((GridLayout) progressPanel.getLayout()).setRows( ((GridLayout) progressPanel.getLayout()).getRows() + 1); ++totalProgressCount; - instance.validate(); + validate(); return thisprogress; } @@ -1885,7 +1915,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public static AlignmentPanel[] getAlignmentPanels(String alignmentId) { - if (Desktop.desktop == null) + if (Desktop.getDesktopPane() == null) { // no frames created and in headless mode // TODO: verify that frames are recoverable when in headless mode @@ -1927,7 +1957,7 @@ public class Desktop extends jalview.jbgui.GDesktop public static AlignmentViewport[] getViewports(String sequenceSetId) { List viewp = new ArrayList<>(); - if (desktop != null) + if (getDesktopPane() != null) { AlignFrame[] frames = Desktop.getAlignFrames(); @@ -1974,6 +2004,7 @@ public class Desktop extends jalview.jbgui.GDesktop return; } + // BH! not in applet branch // FIXME: ideally should use UI interface API FeatureSettings viewFeatureSettings = (af.featureSettings != null && af.featureSettings.isOpen()) @@ -1983,9 +2014,9 @@ public class Desktop extends jalview.jbgui.GDesktop for (int i = 0; i < size; i++) { AlignmentPanel ap = af.alignPanels.get(i); - AlignFrame newaf = new AlignFrame(ap); + // BH! not in applet branch // transfer reference for existing feature settings to new alignFrame if (ap == af.alignPanel) { @@ -2011,6 +2042,7 @@ public class Desktop extends jalview.jbgui.GDesktop addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + // BH! not in applet branch // and materialise a new feature settings dialog instance for the new alignframe // (closes the old as if 'OK' was pressed) if (ap == af.alignPanel && newaf.featureSettings != null @@ -2021,6 +2053,7 @@ public class Desktop extends jalview.jbgui.GDesktop } } + // BH! not in applet branch af.featureSettings = null; af.alignPanels.clear(); af.closeMenuItem_actionPerformed(true); @@ -2039,8 +2072,9 @@ public class Desktop extends jalview.jbgui.GDesktop { source.viewport.setGatherViewsHere(true); source.viewport.setExplodedGeometry(source.getBounds()); - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = getAllFrames(); String viewId = source.viewport.getSequenceSetId(); + for (int t = 0; t < frames.length; t++) { if (frames[t] instanceof AlignFrame && frames[t] != source) @@ -2061,27 +2095,26 @@ public class Desktop extends jalview.jbgui.GDesktop if (gatherThis) { - if (af.featureSettings != null && af.featureSettings.isOpen()) - { - if (source.featureSettings == null) + if (af.featureSettings != null && af.featureSettings.isOpen()) { - // preserve the feature settings geometry for this frame - source.featureSettings = af.featureSettings; - source.setFeatureSettingsGeometry( - af.getFeatureSettingsGeometry()); - } - else - { - // close it and forget - af.featureSettings.close(); + if (source.featureSettings == null) + { + // preserve the feature settings geometry for this frame + source.featureSettings = af.featureSettings; + source.setFeatureSettingsGeometry( + af.getFeatureSettingsGeometry()); + } + else + { + // close it and forget + af.featureSettings.close(); + } } + af.alignPanels.clear(); + af.closeMenuItem_actionPerformed(true); } - af.alignPanels.clear(); - af.closeMenuItem_actionPerformed(true); } } - } - // refresh the feature setting UI for the source frame if it exists if (source.featureSettings != null && source.featureSettings.isOpen()) @@ -2092,7 +2125,7 @@ public class Desktop extends jalview.jbgui.GDesktop public JInternalFrame[] getAllFrames() { - return desktop.getAllFrames(); + return desktopPane.getAllFrames(); } /** @@ -2131,7 +2164,7 @@ public class Desktop extends jalview.jbgui.GDesktop while (li.hasNext()) { String link = li.next(); - if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID) + if (link.contains(UrlConstants.SEQUENCE_ID) && !UrlConstants.isDefaultString(link)) { check = true; @@ -2178,7 +2211,7 @@ public class Desktop extends jalview.jbgui.GDesktop }); msgPanel.add(jcb); - JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel, + JvOptionPane.showMessageDialog(desktopPane, msgPanel, MessageManager .getString("label.SEQUENCE_ID_no_longer_used"), JvOptionPane.WARNING_MESSAGE); @@ -2293,11 +2326,11 @@ public class Desktop extends jalview.jbgui.GDesktop { if (Jalview.isHeadlessMode()) { - // Desktop.desktop is null in headless mode - return new AlignFrame[] { Jalview.currentAlignFrame }; + // Desktop.getDesktopPane() is null in headless mode + return new AlignFrame[] { Jalview.getCurrentAlignFrame() }; } - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); if (frames == null) { @@ -2342,7 +2375,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public GStructureViewer[] getJmols() { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); if (frames == null) { @@ -2378,7 +2411,7 @@ public class Desktop extends jalview.jbgui.GDesktop } catch (Exception ex) { Cache.log.error("Groovy Shell Creation failed.", ex); - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(desktopPane, MessageManager.getString("label.couldnt_create_groovy_shell"), MessageManager.getString("label.groovy_support_failed"), @@ -2389,7 +2422,7 @@ public class Desktop extends jalview.jbgui.GDesktop /** * Open the Groovy console */ - void openGroovyConsole() + private void openGroovyConsole() { if (groovyConsole == null) { @@ -2438,7 +2471,7 @@ public class Desktop extends jalview.jbgui.GDesktop { getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()), + ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()), "Quit"); getRootPane().getActionMap().put("Quit", new AbstractAction() { @@ -2489,7 +2522,7 @@ public class Desktop extends jalview.jbgui.GDesktop @Override public void setProgressBar(String message, long id) { - // Platform.timeCheck("Desktop " + message, Platform.TIME_MARK); + // Platform.timeCheck("Desktop " + message, Platform.TIME_MARK); if (progressBars == null) { @@ -2575,7 +2608,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public static AlignFrame getAlignFrameFor(AlignViewportI viewport) { - if (desktop != null) + if (getDesktopPane() != null) { AlignmentPanel[] aps = getAlignmentPanels( viewport.getSequenceSetId()); @@ -2590,13 +2623,6 @@ public class Desktop extends jalview.jbgui.GDesktop return null; } - public VamsasApplication getVamsasApplication() - { - // TODO: JAL-3311 remove remaining code from Jalview relating to VAMSAS - return null; - - } - /** * flag set if jalview GUI is being operated programmatically */ @@ -2637,8 +2663,8 @@ public class Desktop extends jalview.jbgui.GDesktop // todo: changesupport handlers need to be transferred if (discoverer == null) { - discoverer = new jalview.ws.jws1.Discoverer(); - // register PCS handler for desktop. + discoverer = jalview.ws.jws1.Discoverer.getInstance(); + // register PCS handler for getDesktopPane(). discoverer.addPropertyChangeListener(changeSupport); } // JAL-940 - disabled JWS1 service configuration - always start discoverer @@ -2648,7 +2674,7 @@ public class Desktop extends jalview.jbgui.GDesktop if (Cache.getDefault("SHOW_JWS2_SERVICES", true)) { - t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() + t2 = jalview.ws.jws2.Jws2Discoverer.getInstance() .startDiscoverer(changeSupport); } Thread t3 = null; @@ -2681,7 +2707,7 @@ public class Desktop extends jalview.jbgui.GDesktop { if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector) { - final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer() + final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance() .getErrorMessages(); if (ermsg != null) { @@ -2720,7 +2746,7 @@ public class Desktop extends jalview.jbgui.GDesktop * * jd.waitForInput(); */ - JvOptionPane.showConfirmDialog(Desktop.desktop, + JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), new JLabel("
" + ermsg + "
" + "

It may be that you have invalid JABA URLs
in your web service preferences," @@ -2746,7 +2772,7 @@ public class Desktop extends jalview.jbgui.GDesktop } } - private Runnable serviceChangedDialog = null; + Runnable serviceChangedDialog = null; /** * start a thread to open a URL in the configured browser. Pops up a warning @@ -2757,7 +2783,7 @@ public class Desktop extends jalview.jbgui.GDesktop */ public static void showUrl(final String url) { - showUrl(url, Desktop.instance); + showUrl(url, Desktop.getInstance()); } /** @@ -2777,16 +2803,16 @@ public class Desktop extends jalview.jbgui.GDesktop { try { - if (progress != null) + if (progress != null && !Platform.isJS()) { progress.setProgressBar(MessageManager .formatMessage("status.opening_params", new Object[] { url }), this.hashCode()); } - jalview.util.BrowserLauncher.openURL(url); + Platform.openURL(url); } catch (Exception ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.web_browser_not_found_unix"), MessageManager.getString("label.web_browser_not_found"), @@ -2794,7 +2820,7 @@ public class Desktop extends jalview.jbgui.GDesktop ex.printStackTrace(); } - if (progress != null) + if (progress != null && !Platform.isJS()) { progress.setProgressBar(null, this.hashCode()); } @@ -2802,15 +2828,16 @@ public class Desktop extends jalview.jbgui.GDesktop }).start(); } - public static WsParamSetManager wsparamManager = null; + private WsParamSetManager wsparamManager = null; public static ParamManager getUserParameterStore() { - if (wsparamManager == null) + Desktop d = Desktop.getInstance(); + if (d.wsparamManager == null) { - wsparamManager = new WsParamSetManager(); + d.wsparamManager = new WsParamSetManager(); } - return wsparamManager; + return d.wsparamManager; } /** @@ -2862,7 +2889,10 @@ public class Desktop extends jalview.jbgui.GDesktop */ private java.util.concurrent.Semaphore block = new Semaphore(0); - private static groovy.ui.Console groovyConsole; + // BH was static + private groovy.ui.Console groovyConsole; + + public StructureViewer lastTargetedView; /** * add another dialog thread to the queue @@ -2885,7 +2915,8 @@ public class Desktop extends jalview.jbgui.GDesktop { } } - if (instance == null) + // BH! Q: do we mean System.headless ? or "nogui/nodisplay" headless? + if (Jalview.isHeadlessMode()) { return; } @@ -3049,7 +3080,7 @@ public class Desktop extends jalview.jbgui.GDesktop String topViewId = myTopFrame.viewport.getSequenceSetId(); String bottomViewId = myBottomFrame.viewport.getSequenceSetId(); - JInternalFrame[] frames = desktop.getAllFrames(); + JInternalFrame[] frames = desktopPane.getAllFrames(); for (JInternalFrame frame : frames) { if (frame instanceof SplitFrame && frame != source) @@ -3094,7 +3125,8 @@ public class Desktop extends jalview.jbgui.GDesktop public static groovy.ui.Console getGroovyConsole() { - return groovyConsole; + Desktop desktop = Desktop.getInstance(); + return desktop == null ? null : desktop.groovyConsole; } /** @@ -3112,6 +3144,7 @@ public class Desktop extends jalview.jbgui.GDesktop * - the payload from the drop event * @throws Exception */ + @SuppressWarnings("unchecked") public static void transferFromDropTarget(List files, List protocols, DropTargetDropEvent evt, Transferable t) throws Exception @@ -3181,7 +3214,7 @@ public class Desktop extends jalview.jbgui.GDesktop { // Works on Windows and MacOSX Cache.log.debug("Drop handled as javaFileListFlavor"); - for (Object file : (List) t + for (Object file : (List) t .getTransferData(DataFlavor.javaFileListFlavor)) { files.add(file); @@ -3345,7 +3378,7 @@ public class Desktop extends jalview.jbgui.GDesktop Class structureViewerClass) { List result = new ArrayList<>(); - JInternalFrame[] frames = Desktop.instance.getAllFrames(); + JInternalFrame[] frames = getAllFrames(); for (JInternalFrame frame : frames) { @@ -3364,4 +3397,40 @@ public class Desktop extends jalview.jbgui.GDesktop } return result; } + + + + public MyDesktopPane desktopPane; + + /** + * Get the instance of the JDesktopPane from the application-local Desktop + * (JFrame) instance + * + * The key here is that the Java application can have multiple static + * instances of the desktop JFrame because those instances are sandboxed, but + * the SwingJS JFrames will be in the same VM-like space. So we need + * application singletons, at least for JavaScript. + * + * @return + */ + public static MyDesktopPane getDesktopPane() + { + Desktop desktop = Desktop.getInstance(); + return desktop == null ? null : desktop.desktopPane; + } + + /** + * Answers an 'application scope' singleton instance of this class. Separate + * SwingJS 'applets' running in the same browser page will each have a + * distinct instance of Desktop. + * + * @return + */ + public static Desktop getInstance() + { + return Jalview.isHeadlessMode() ? null + : (Desktop) ApplicationSingletonProvider + .getInstance(Desktop.class); + } + } diff --git a/src/jalview/gui/FeatureEditor.java b/src/jalview/gui/FeatureEditor.java index d547c58..a02ec36 100644 --- a/src/jalview/gui/FeatureEditor.java +++ b/src/jalview/gui/FeatureEditor.java @@ -222,7 +222,7 @@ public class FeatureEditor updateColourButton(mainPanel, colour, featureColour); }; }; - JalviewColourChooser.showColourChooser(Desktop.getDesktop(), + JalviewColourChooser.showColourChooser(Desktop.getDesktopPane(), title, featureColour.getColour(), listener); } else @@ -412,7 +412,7 @@ public class FeatureEditor * set dialog action handlers for OK (create/Amend) and Cancel options * also for Delete if applicable (when amending features) */ - JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop) + JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()) .setResponseHandler(0, okAction).setResponseHandler(2, cancelAction); if (!forCreate) { diff --git a/src/jalview/gui/FeatureRenderer.java b/src/jalview/gui/FeatureRenderer.java index 83badd0..401fc7d 100644 --- a/src/jalview/gui/FeatureRenderer.java +++ b/src/jalview/gui/FeatureRenderer.java @@ -21,10 +21,14 @@ package jalview.gui; /** - * A class that manages drawing of sequence features for the Swing gui + * DOCUMENT ME! + * + * @author $author$ + * @version $Revision$ */ public class FeatureRenderer extends jalview.renderer.seqfeatures.FeatureRenderer + implements jalview.api.FeatureRenderer { AlignmentPanel ap; @@ -37,11 +41,10 @@ public class FeatureRenderer { super(alignPanel.av); this.ap = alignPanel; - if (alignPanel.getSeqPanel() != null - && alignPanel.getSeqPanel().seqCanvas != null - && alignPanel.getSeqPanel().seqCanvas.fr != null) + SeqPanel sp = alignPanel.getSeqPanel(); + if (sp != null && sp.seqCanvas != null && sp.seqCanvas.fr != null) { - transferSettings(alignPanel.getSeqPanel().seqCanvas.fr); + transferSettings(sp.seqCanvas.fr); } } } diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index b49593a..9ffcaee 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -408,8 +408,8 @@ public class FeatureSettings extends JPanel } else { - frame = new JInternalFrame(); - frame.setContentPane(this); + frame = new JInternalFrame(); + frame.setContentPane(this); Rectangle bounds = af.getFeatureSettingsGeometry(); String title; if (af.getAlignPanels().size() > 1 || Desktop.getAlignmentPanels( @@ -441,22 +441,22 @@ public class FeatureSettings extends JPanel frame.setBounds(bounds); frame.setVisible(true); } - frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); + frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); - frame.addInternalFrameListener( - new javax.swing.event.InternalFrameAdapter() + frame.addInternalFrameListener( + new javax.swing.event.InternalFrameAdapter() + { + @Override + public void internalFrameClosed( + javax.swing.event.InternalFrameEvent evt) { - @Override - public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) - { featureSettings_isClosed(); }; - }); - frame.setLayer(JLayeredPane.PALETTE_LAYER); + }); + frame.setLayer(JLayeredPane.PALETTE_LAYER); } - inConstruction = false; - } + inConstruction = false; + } /** * Sets the state of buttons to show complement features from viewport @@ -485,12 +485,12 @@ public class FeatureSettings extends JPanel /** * Constructs and shows a popup menu of possible actions on the selected row and * feature type - * - * @param rowSelected - * @param type - * @param typeCol - * @param pt - */ + * + * @param rowSelected + * @param type + * @param typeCol + * @param pt + */ protected void showPopupMenu(final int rowSelected, final String type, final Object typeCol, final Point pt) { JPopupMenu men = new JPopupMenu(MessageManager @@ -517,8 +517,8 @@ public class FeatureSettings extends JPanel { if (e.getSource() == variableColourCB) { - // BH 2018 for JavaScript because this is a checkbox - men.setVisible(true); + // BH 2018 for JavaScript because this is a checkbox + men.setVisible(true); men.setVisible(false); if (featureColour.isSimpleColour()) { @@ -577,6 +577,7 @@ public class FeatureSettings extends JPanel men.add(scr); scr.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -587,6 +588,7 @@ public class FeatureSettings extends JPanel MessageManager.getString("label.sort_by_density")); dens.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { @@ -1297,7 +1299,7 @@ public class FeatureSettings extends JPanel if (frame != null) { af.setFeatureSettingsGeometry(frame.getBounds()); - frame.setClosed(true); + frame.setClosed(true); } else { @@ -1472,8 +1474,8 @@ public class FeatureSettings extends JPanel { if (!hasComplement) { - close(); - } + close(); + } else { storeOriginalSettings(); @@ -1614,7 +1616,7 @@ public class FeatureSettings extends JPanel * * @param fcol * @param withHint - * if true include 'click to edit' and similar text + * if true include 'click to edit' and similar text * @return */ public static String getColorTooltip(FeatureColourI fcol, diff --git a/src/jalview/gui/Finder.java b/src/jalview/gui/Finder.java index a1693f7..2a6adda 100755 --- a/src/jalview/gui/Finder.java +++ b/src/jalview/gui/Finder.java @@ -176,7 +176,7 @@ public class Finder extends GFinder */ boolean getFocusedViewport() { - if (focusfixed || Desktop.desktop == null) + if (focusfixed || Desktop.getDesktopPane() == null) { if (ap != null && av != null) { @@ -187,7 +187,7 @@ public class Finder extends GFinder } // now checks further down the window stack to fix bug // https://mantis.lifesci.dundee.ac.uk/view.php?id=36008 - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); for (int f = 0; f < frames.length; f++) { JInternalFrame alignFrame = frames[f]; diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index f53d8b3..10641eb 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -245,7 +245,7 @@ public class IdPanel extends JPanel jalview.util.BrowserLauncher.openURL(url); } catch (Exception ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.web_browser_not_found_unix"), MessageManager.getString("label.web_browser_not_found"), JvOptionPane.WARNING_MESSAGE); @@ -440,8 +440,8 @@ public class IdPanel extends JPanel PopupMenu pop = new PopupMenu(alignPanel, sq, Preferences.getGroupURLLinks()); pop.show(this, e.getX(), e.getY()); + } } - } /** * On right mouse click on a Consensus annotation label, shows a limited popup diff --git a/src/jalview/gui/JalviewDialog.java b/src/jalview/gui/JalviewDialog.java index 1d7bf3d..0ff5606 100644 --- a/src/jalview/gui/JalviewDialog.java +++ b/src/jalview/gui/JalviewDialog.java @@ -78,11 +78,11 @@ public abstract class JalviewDialog extends JPanel boolean block, String title, int width, int height) { - frame = new JDialog(Desktop.instance, modal); + frame = new JDialog(Desktop.getInstance(), modal); frame.setTitle(title); - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Rectangle deskr = Desktop.instance.getBounds(); + Rectangle deskr = Desktop.getInstance().getBounds(); frame.setBounds(new Rectangle((int) (deskr.getCenterX() - width / 2), (int) (deskr.getCenterY() - height / 2), width, height)); } diff --git a/src/jalview/gui/JvSwingUtils.java b/src/jalview/gui/JvSwingUtils.java index 2f4a0fe..7dd3e80 100644 --- a/src/jalview/gui/JvSwingUtils.java +++ b/src/jalview/gui/JvSwingUtils.java @@ -20,6 +20,8 @@ */ package jalview.gui; +import jalview.util.MessageManager; + import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -56,12 +58,15 @@ import jalview.util.MessageManager; */ public final class JvSwingUtils { + static final String HTML_PREFIX = "
"; + /** * wrap a bare html safe string to around 60 characters per line using a CSS * style class specifying word-wrap and break-word * * @param enclose - * if true, add <html> wrapper tags + * if true, add <html> wrapper tags (currently false for only + * two references -- both in Jws2Discoverer -- * @param ttext * * @return @@ -94,16 +99,9 @@ public final class JvSwingUtils { return enclose ? "" + ttext + "" : ttext; } + // BH 2018,2019 + return (enclose ? HTML_PREFIX + ttext + "
" : ttext); - return (enclose ? "" : "") - // BH 2018 - + "
" -// + "

" - + ttext - + "

" -// + "

" - + ((enclose ? "" : "")); } public static JButton makeButton(String label, String tooltip, @@ -346,6 +344,7 @@ public final class JvSwingUtils combo.setToolTipText(tooltips.get(j)); } } + @Override public void mouseExited(MouseEvent e) { diff --git a/src/jalview/gui/LineartOptions.java b/src/jalview/gui/LineartOptions.java index d55733c..62bdd35 100644 --- a/src/jalview/gui/LineartOptions.java +++ b/src/jalview/gui/LineartOptions.java @@ -86,7 +86,7 @@ public class LineartOptions extends JPanel ex.printStackTrace(); } - dialog = JvOptionPane.newOptionDialog(Desktop.desktop); + dialog = JvOptionPane.newOptionDialog(Desktop.getDesktopPane()); } /** @@ -188,7 +188,7 @@ public class LineartOptions extends JPanel } else { - Cache.applicationProperties.remove(preferencesKey); + Cache.removePropertyNoSave(preferencesKey); } } diff --git a/src/jalview/gui/OOMWarning.java b/src/jalview/gui/OOMWarning.java index 02c8fe1..dc5d0f5 100644 --- a/src/jalview/gui/OOMWarning.java +++ b/src/jalview/gui/OOMWarning.java @@ -72,7 +72,7 @@ public class OOMWarning implements Runnable public OOMWarning(String string, OutOfMemoryError oomerror) { - this(string, oomerror, Desktop.desktop); + this(string, oomerror, Desktop.getDesktopPane()); } @Override diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index 8be93a1..2e6e1b8 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -298,10 +298,10 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { try { - jalview.util.BrowserLauncher.openURL(url); + Platform.openURL(url); } catch (Exception ex) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.web_browser_not_found_unix"), MessageManager.getString("label.web_browser_not_found"), JvOptionPane.WARNING_MESSAGE); @@ -459,7 +459,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener if (forIdPanel) { - JMenuItem menuItem; + JMenuItem menuItem; sequenceMenu.setText(sequence.getName()); if (seq == alignPanel.av.getAlignment().getSeqrep()) { @@ -773,12 +773,12 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener /* * add features in CDS/protein complement at the corresponding * position if configured to do so - */ + */ MappedFeatures mf = null; if (ap.av.isShowComplementFeatures()) { if (!Comparison.isGap(sequence.getCharAt(column))) - { + { AlignViewportI complement = ap.getAlignViewport() .getCodingComplement(); AlignFrame af = Desktop.getAlignFrameFor(complement); @@ -795,7 +795,6 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener */ return; } - JMenu details = new JMenu( MessageManager.getString("label.feature_details")); add(details); @@ -829,19 +828,19 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener void addFeatureDetailsMenuItem(JMenu details, final String seqName, final SequenceFeature sf) { - int start = sf.getBegin(); - int end = sf.getEnd(); + int start = sf.getBegin(); + int end = sf.getEnd(); StringBuilder desc = new StringBuilder(); desc.append(sf.getType()).append(" ").append(String.valueOf(start)); if (start != end) - { + { desc.append("-").append(String.valueOf(end)); - } - String description = sf.getDescription(); - if (description != null) - { + } + String description = sf.getDescription(); + if (description != null) + { desc.append(" "); - description = StringUtils.stripHtmlTags(description); + description = StringUtils.stripHtmlTags(description); /* * truncate overlong descriptions unless they contain an href @@ -849,28 +848,28 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener */ boolean hasLink = description.indexOf("a href") > -1; if (description.length() > FEATURE_DESC_MAX && !hasLink) - { + { description = description.substring(0, FEATURE_DESC_MAX) + "..."; - } + } desc.append(description); - } + } String featureGroup = sf.getFeatureGroup(); if (featureGroup != null) - { + { desc.append(" (").append(featureGroup).append(")"); - } + } String htmlText = JvSwingUtils.wrapTooltip(true, desc.toString()); JMenuItem item = new JMenuItem(htmlText); - item.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) + item.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { showFeatureDetails(seqName, sf); - } - }); - details.add(item); - } + } + }); + details.add(item); + } /** * Opens a panel showing a text report of feature dteails @@ -1217,7 +1216,6 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener groupLinksMenu.add(linkMenus[m]); } } - groupMenu.add(groupLinksMenu); } } @@ -1473,15 +1471,15 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { JMenuItem hideInsertions = new JMenuItem( MessageManager.getString("label.hide_insertions")); - hideInsertions.addActionListener(new ActionListener() - { + hideInsertions.addActionListener(new ActionListener() + { - @Override - public void actionPerformed(ActionEvent e) - { - hideInsertions_actionPerformed(e); - } - }); + @Override + public void actionPerformed(ActionEvent e) + { + hideInsertions_actionPerformed(e); + } + }); add(hideInsertions); } // annotations configuration panel suppressed for now @@ -2069,8 +2067,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener getGroup().setOutlineColour(c); refresh(); } - }; - JalviewColourChooser.showColourChooser(Desktop.getDesktop(), + }; + JalviewColourChooser.showColourChooser(Desktop.getDesktopPane(), title, Color.BLUE, listener); } diff --git a/src/jalview/gui/PromptUserConfig.java b/src/jalview/gui/PromptUserConfig.java index cb59452..77d83a8 100644 --- a/src/jalview/gui/PromptUserConfig.java +++ b/src/jalview/gui/PromptUserConfig.java @@ -200,7 +200,7 @@ public class PromptUserConfig implements Runnable } try { - int reply = JvOptionPane.showConfirmDialog(Desktop.desktop, // component, + int reply = JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), // component, dialogText, dialogTitle, (allowCancel) ? JvOptionPane.YES_NO_CANCEL_OPTION : JvOptionPane.YES_NO_OPTION, diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 18e9365..85d6025 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -77,7 +77,8 @@ import javax.swing.Timer; import javax.swing.ToolTipManager; /** - * DOCUMENT ME! + * The main scrollable region containing the alignment and just to the right of + * the IDPanel. * * @author $author$ * @version $Revision: 1.130 $ @@ -137,7 +138,6 @@ public class SeqPanel extends JPanel MousePos o = (MousePos) obj; boolean b = (column == o.column && seqIndex == o.seqIndex && annotationIndex == o.annotationIndex); - // System.out.println(obj + (b ? "= " : "!= ") + this); return b; } @@ -1610,7 +1610,6 @@ public class SeqPanel extends JPanel return; } - // System.out.print(y1+" "+y2+" "+fixedLeft+" "+fixedRight+"~~"); // Selection spans a hidden region if (fixedLeft < y1 && (fixedRight > y2 || fixedRight == -1)) { @@ -2050,11 +2049,22 @@ public class SeqPanel extends JPanel { lastMousePosition = null; ap.alignFrame.setStatus(" "); + if (av.getWrapAlignment()) { return; } + // BH check was: +// /* +// * start scrolling if mouse dragging, whether the drag started +// * in the scale panel or this panel +// */ +// if (mouseDragging || ap.getScalePanel().isMouseDragging()) +// { +// startScrolling(new Point(e.getX(), 0)); +// } + if (mouseDragging && scrollThread == null) { startScrolling(e.getPoint()); @@ -2280,8 +2290,8 @@ public class SeqPanel extends JPanel if (sequence != null) { PopupMenu pop = new PopupMenu(ap, sequence, column); - pop.show(this, evt.getX(), evt.getY()); - } + pop.show(this, evt.getX(), evt.getY()); + } } /** @@ -2839,7 +2849,7 @@ public class SeqPanel extends JPanel * Map sequence selection */ SequenceGroup sg = MappingUtils.mapSequenceGroup(seqsel, sourceAv, av); - av.setSelectionGroup(sg != null && sg.getSize() > 0 ? sg : null); + av.setSelectionGroup(sg); av.isSelectionGroupChanged(true); /* @@ -2876,4 +2886,45 @@ public class SeqPanel extends JPanel { return lastSearchResults; } + + /** + * scroll to the given row/column - or nearest visible location + * + * @param row + * @param column + */ + public void scrollTo(int row, int column) + { + + row = row < 0 ? ap.av.getRanges().getStartSeq() : row; + column = column < 0 ? ap.av.getRanges().getStartRes() : column; + ap.scrollTo(column, column, row, true, true); + } + + /** + * scroll to the given row - or nearest visible location + * + * @param row + */ + public void scrollToRow(int row) + { + + row = row < 0 ? ap.av.getRanges().getStartSeq() : row; + ap.scrollTo(ap.av.getRanges().getStartRes(), + ap.av.getRanges().getStartRes(), row, true, true); + } + + /** + * scroll to the given column - or nearest visible location + * + * @param column + */ + public void scrollToColumn(int column) + { + + column = column < 0 ? ap.av.getRanges().getStartRes() : column; + ap.scrollTo(column, column, ap.av.getRanges().getStartSeq(), true, + true); + } + } diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index 8b5d3b7..7c83259 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -868,7 +868,7 @@ public class SequenceFetcher extends JPanel implements Runnable @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, error, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), error, MessageManager.getString("label.error_retrieving_data"), JvOptionPane.WARNING_MESSAGE); } diff --git a/src/jalview/gui/SplashScreen.java b/src/jalview/gui/SplashScreen.java index f4b275d..0edede4 100755 --- a/src/jalview/gui/SplashScreen.java +++ b/src/jalview/gui/SplashScreen.java @@ -160,7 +160,7 @@ public class SplashScreen extends JPanel System.err.println("Error when loading images!"); } } while (!mt.checkAll()); - Desktop.instance.setIconImage(logo); + Desktop.getInstance().setIconImage(logo); } } catch (Exception ex) { @@ -191,7 +191,7 @@ public class SplashScreen extends JPanel } add(splashText, BorderLayout.CENTER); splashText.addMouseListener(closer); - Desktop.desktop.add(iframe); + Desktop.getDesktopPane().add(iframe); refreshText(); } @@ -200,7 +200,7 @@ public class SplashScreen extends JPanel */ protected boolean refreshText() { - String newtext = Desktop.instance.getAboutMessage(); + String newtext = Desktop.getInstance().getAboutMessage(); // System.err.println("Text found: \n"+newtext+"\nEnd of newtext."); if (oldTextLength != newtext.length()) { @@ -239,8 +239,8 @@ public class SplashScreen extends JPanel splashText.setSize(new Dimension(750, 375)); add(splashText, BorderLayout.CENTER); revalidate(); - iframe.setBounds((Desktop.instance.getWidth() - 750) / 2, - (Desktop.instance.getHeight() - 375) / 2, 750, + iframe.setBounds((Desktop.getInstance().getWidth() - 750) / 2, + (Desktop.getInstance().getHeight() - 375) / 2, 750, splashText.getHeight() + iconimg.getHeight()); iframe.validate(); iframe.setVisible(true); @@ -286,7 +286,7 @@ public class SplashScreen extends JPanel } closeSplash(); - Desktop.instance.startDialogQueue(); + Desktop.getInstance().startDialogQueue(); } /** diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index e8f30b7..d13be17 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -152,7 +152,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI // allow about 65 pixels for Desktop decorators on Windows int newHeight = Math.min(height, - Desktop.instance.getHeight() - DESKTOP_DECORATORS_HEIGHT); + Desktop.getInstance().getHeight() - DESKTOP_DECORATORS_HEIGHT); if (newHeight != height) { int oldDividerLocation = getDividerLocation(); @@ -169,8 +169,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI { // TODO if CommandListener is only ever 1:1 for complementary views, // may change broadcast pattern to direct messaging (more efficient) - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + final StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); ssm.addCommandListener(((AlignFrame) getTopFrame()).getViewport()); ssm.addCommandListener(((AlignFrame) getBottomFrame()).getViewport()); } @@ -297,7 +297,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI public void internalFrameClosed(InternalFrameEvent evt) { close(); - }; + } }); } @@ -570,8 +570,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI */ adjustLayout(); - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + final StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); ssm.addCommandListener(newTopPanel.av); ssm.addCommandListener(newBottomPanel.av); } @@ -698,7 +698,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI */ protected void expandViews_actionPerformed() { - Desktop.instance.explodeViews(this); + Desktop.getInstance().explodeViews(this); } /** @@ -707,7 +707,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI */ protected void gatherViews_actionPerformed() { - Desktop.instance.gatherViews(this); + Desktop.getInstance().gatherViews(this); } /** @@ -884,7 +884,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI return; } getAlignFrames().get(tab).showFeatureSettingsUI(); - } +} }); featureSettingsUI = new JInternalFrame(MessageManager.getString( "label.sequence_feature_settings_for_CDS_and_Protein")); @@ -971,7 +971,6 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI 1); } featureSettingsPanels.setSelectedComponent((Component) featureSettings); - // TODO: JAL-3535 - construct a feature settings title including names of // currently selected CDS and Protein names diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index 33d8c33..97dfa86 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -148,7 +148,7 @@ public class StructureChooser extends GStructureChooser */ private void discoverStructureViews() { - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { targetView.removeAllItems(); if (lastTargetedView != null && !lastTargetedView.isVisible()) @@ -156,7 +156,7 @@ public class StructureChooser extends GStructureChooser lastTargetedView = null; } int linkedViewsAt = 0; - for (StructureViewerBase view : Desktop.instance + for (StructureViewerBase view : Desktop.getInstance() .getStructureViewers(null, null)) { StructureViewer viewHandler = (lastTargetedView != null @@ -1008,7 +1008,7 @@ public class StructureChooser extends GStructureChooser PDBEntry fileEntry = new AssociatePdbFileWithSeq() .associatePdbWithSeq(selectedPdbFileName, DataSourceType.FILE, selectedSequence, true, - Desktop.instance); + Desktop.getInstance()); sViewer = launchStructureViewer( ssm, new PDBEntry[] diff --git a/src/jalview/gui/StructureViewer.java b/src/jalview/gui/StructureViewer.java index 0c8354b..17b786d 100644 --- a/src/jalview/gui/StructureViewer.java +++ b/src/jalview/gui/StructureViewer.java @@ -25,7 +25,12 @@ import jalview.bin.Cache; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.datamodel.StructureViewerModel; +import jalview.structure.StructureMapping; import jalview.structure.StructureSelectionManager; +import jalview.util.MessageManager; +import jalview.util.Platform; +import jalview.ws.DBRefFetcher; +import jalview.ws.sifts.SiftsSettings; import java.awt.Rectangle; import java.util.ArrayList; @@ -45,6 +50,12 @@ import java.util.Map.Entry; */ public class StructureViewer { + + static + { + Platform.ensureJmol(); + } + private static final String UNKNOWN_VIEWER_TYPE = "Unknown structure viewer type "; StructureSelectionManager ssm; @@ -57,7 +68,7 @@ public class StructureViewer public enum ViewerType { JMOL, CHIMERA - }; + } /** * Constructor @@ -388,4 +399,135 @@ public class StructureViewer superposeAdded = alignAddedStructures; } + /** + * Launch a minimal implementation of a StructureViewer. + * + * @param alignPanel + * @param pdb + * @param seqs + * @return + */ + public static StructureViewer launchStructureViewer( + AlignmentPanel alignPanel, PDBEntry pdb, SequenceI[] seqs) + { + return launchStructureViewer(alignPanel, new PDBEntry[] { pdb }, seqs, + false, null, null); + } + + /** + * Launch a structure viewer with or without an open StructureChooser. + * + * Moved from StructureChooser to enable JalviewJS startup with structure + * display. + * + * @param ap + * @param pdbEntriesToView + * @param sequences + * @param superimpose + * @param theViewer + * @param pb + * @return + */ + protected static StructureViewer launchStructureViewer( + final AlignmentPanel ap, + final PDBEntry[] pdbEntriesToView, SequenceI[] sequences, + boolean superimpose, StructureViewer theViewer, + IProgressIndicator pb) + { + final StructureSelectionManager ssm = ap.getStructureSelectionManager(); + long progressId = sequences.hashCode(); + if (pb != null) + { + pb.setProgressBar(MessageManager + .getString("status.launching_3d_structure_viewer"), progressId); + } + if (theViewer == null) + { + theViewer = new StructureViewer(ssm); + } + theViewer.setSuperpose(superimpose); + + if (pb != null) + { + pb.setProgressBar(null, progressId); + } + if (SiftsSettings.isMapWithSifts()) + { + List seqsWithoutSourceDBRef = new ArrayList<>(); + int p = 0; + // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a + // real PDB ID. For moment, we can also safely do this if there is already + // a known mapping between the PDBEntry and the sequence. + for (SequenceI seq : sequences) + { + PDBEntry pdbe = pdbEntriesToView[p++]; + if (pdbe != null && pdbe.getFile() != null) + { + StructureMapping[] smm = ssm.getMapping(pdbe.getFile()); + if (smm != null && smm.length > 0) + { + for (StructureMapping sm : smm) + { + if (sm.getSequence() == seq) + { + continue; + } + } + } + } + if (seq.getPrimaryDBRefs().isEmpty()) + { + seqsWithoutSourceDBRef.add(seq); + continue; + } + } + if (!seqsWithoutSourceDBRef.isEmpty()) + { + int y = seqsWithoutSourceDBRef.size(); + if (pb != null) + { + pb.setProgressBar(MessageManager.formatMessage( + "status.fetching_dbrefs_for_sequences_without_valid_refs", + y), progressId); + } + SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef + .toArray(new SequenceI[y]); + DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef); + dbRefFetcher.fetchDBRefs(true); + + if (pb != null) + { + pb.setProgressBar("Fetch complete.", progressId); // todo i18n + } + } + } + if (pdbEntriesToView.length > 1) + { + if (pb != null) + { + pb.setProgressBar(MessageManager.getString( + "status.fetching_3d_structures_for_selected_entries"), + progressId); + } + theViewer.viewStructures(pdbEntriesToView, sequences, ap); + } + else + { + if (pb != null) + { + pb.setProgressBar(MessageManager.formatMessage( + "status.fetching_3d_structures_for", + pdbEntriesToView[0].getId()),progressId); + } + theViewer.viewStructures(pdbEntriesToView[0], sequences, ap); + } + if (pb != null) + { + pb.setProgressBar(null, progressId); + } + // remember the last viewer we used... + Desktop.getInstance().lastTargetedView = theViewer; + return theViewer; + } + } diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 418a84d..af48093 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -407,7 +407,7 @@ public abstract class StructureViewerBase extends GStructureViewer */ protected List getViewersFor(AlignmentPanel alp) { - return Desktop.instance.getStructureViewers(alp, this.getClass()); + return Desktop.getInstance().getStructureViewers(alp, this.getClass()); } @Override diff --git a/src/jalview/gui/UserDefinedColours.java b/src/jalview/gui/UserDefinedColours.java index 4846049..2f18f43 100755 --- a/src/jalview/gui/UserDefinedColours.java +++ b/src/jalview/gui/UserDefinedColours.java @@ -448,7 +448,7 @@ public class UserDefinedColours extends GUserDefinedColours { if (isNoSelectionMade()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.no_colour_selection_in_scheme"), MessageManager.getString("label.no_colour_selection_warn"), @@ -503,7 +503,7 @@ public class UserDefinedColours extends GUserDefinedColours String[] options = new String[] { title, MessageManager.getString("label.dont_save_changes"), }; final String question = JvSwingUtils.wrapTooltip(true, message); - int response = JvOptionPane.showOptionDialog(Desktop.desktop, + int response = JvOptionPane.showOptionDialog(Desktop.getDesktopPane(), question, title, JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options, options[0]); @@ -557,7 +557,7 @@ public class UserDefinedColours extends GUserDefinedColours { if (isNoSelectionMade()) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.no_colour_selection_in_scheme"), MessageManager.getString("label.no_colour_selection_warn"), @@ -741,7 +741,7 @@ public class UserDefinedColours extends GUserDefinedColours String name = schemeName.getText().trim(); if (name.length() < 1) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager .getString("label.user_colour_scheme_must_have_name"), MessageManager.getString("label.no_name_colour_scheme"), @@ -756,7 +756,7 @@ public class UserDefinedColours extends GUserDefinedColours * @j2sIgnore */ { - int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop, + int reply = JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.colour_scheme_exists_overwrite", new Object[] { name, name }), diff --git a/src/jalview/gui/UserQuestionnaireCheck.java b/src/jalview/gui/UserQuestionnaireCheck.java index ef86756..e12586a 100644 --- a/src/jalview/gui/UserQuestionnaireCheck.java +++ b/src/jalview/gui/UserQuestionnaireCheck.java @@ -141,7 +141,7 @@ public class UserQuestionnaireCheck implements Runnable + qid + "&rid=" + rid; jalview.bin.Cache.log .info("Prompting user for questionnaire at " + qurl); - int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop, + int reply = JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), MessageManager.getString("label.jalview_new_questionnaire"), MessageManager.getString("label.jalview_user_survey"), JvOptionPane.YES_NO_OPTION, JvOptionPane.QUESTION_MESSAGE); diff --git a/src/jalview/gui/VamsasApplication.java b/src/jalview/gui/VamsasApplication.java index 0848a4d..1320c0f 100644 --- a/src/jalview/gui/VamsasApplication.java +++ b/src/jalview/gui/VamsasApplication.java @@ -173,7 +173,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource } } catch (InvalidSessionDocumentException e) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString( "label.vamsas_doc_couldnt_be_opened_as_new_session"), @@ -455,7 +455,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj, baseProvEntry(), alRedoState); // wander through frames - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); if (frames == null) { @@ -660,7 +660,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource Cache.log.debug( "Asking user if the vamsas session should be stored."); int reply = JvOptionPane.showInternalConfirmDialog( - Desktop.desktop, + Desktop.getDesktopPane(), "The current VAMSAS session has unsaved data - do you want to save it ?", "VAMSAS Session Shutdown", JvOptionPane.YES_NO_OPTION, @@ -669,7 +669,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource if (reply == JvOptionPane.YES_OPTION) { Cache.log.debug("Prompting for vamsas store filename."); - Desktop.instance.vamsasSave_actionPerformed(null); + Desktop.getInstance().vamsasSave_actionPerformed(null); Cache.log .debug("Finished attempt at storing document."); } @@ -762,10 +762,10 @@ public class VamsasApplication implements SelectionSource, VamsasSource } try { - final IPickManager pm = vclient.getPickManager(); - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - final VamsasApplication me = this; + IPickManager pm = vclient.getPickManager(); + StructureSelectionManager ssm = Desktop + .getStructureSelectionManager(); + VamsasApplication me = this; pm.registerMessageHandler(new IMessageHandler() { String last = null; @@ -831,7 +831,6 @@ public class VamsasApplication implements SelectionSource, VamsasSource { type = jvobjs[o].getClass(); } - ; if (type != jvobjs[o].getClass()) { send = false; @@ -955,7 +954,6 @@ public class VamsasApplication implements SelectionSource, VamsasSource { jvobjs[c] = null; } - ; jvobjs = null; return; } diff --git a/src/jalview/gui/WebserviceInfo.java b/src/jalview/gui/WebserviceInfo.java index 25ade21..101acbe 100644 --- a/src/jalview/gui/WebserviceInfo.java +++ b/src/jalview/gui/WebserviceInfo.java @@ -746,7 +746,7 @@ public class WebserviceInfo extends GWebserviceInfo @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, message, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), message, title, JvOptionPane.WARNING_MESSAGE); } diff --git a/src/jalview/gui/WsJobParameters.java b/src/jalview/gui/WsJobParameters.java index 976e551..06d44f6 100644 --- a/src/jalview/gui/WsJobParameters.java +++ b/src/jalview/gui/WsJobParameters.java @@ -215,12 +215,12 @@ public class WsJobParameters extends JPanel implements ItemListener, public boolean showRunDialog() { - frame = new JDialog(Desktop.instance, true); + frame = new JDialog(Desktop.getInstance(), true); frame.setTitle(MessageManager.formatMessage("label.edit_params_for", new String[] { service.getActionText() })); - Rectangle deskr = Desktop.instance.getBounds(); + Rectangle deskr = Desktop.getInstance().getBounds(); Dimension pref = this.getPreferredSize(); frame.setBounds( new Rectangle((int) (deskr.getCenterX() - pref.width / 2), @@ -436,8 +436,8 @@ public class WsJobParameters extends JPanel implements ItemListener, dialogpanel.add(canceljob); // JAL-1580: setMaximumSize() doesn't work, so just size for the worst case: // check for null is for JUnit usage - final int windowHeight = Desktop.instance == null ? 540 - : Desktop.instance.getHeight(); + final int windowHeight = Desktop.getInstance() == null ? 540 + : Desktop.getInstance().getHeight(); setPreferredSize(new Dimension(540, windowHeight)); add(dialogpanel, BorderLayout.SOUTH); validate(); @@ -969,7 +969,7 @@ public class WsJobParameters extends JPanel implements ItemListener, { Vector services = new Vector<>(); services.addElement(args[p++]); - Jws2Discoverer.getDiscoverer().setServiceUrls(services); + Jws2Discoverer.getInstance().setServiceUrls(services); } try { diff --git a/src/jalview/gui/WsParamSetManager.java b/src/jalview/gui/WsParamSetManager.java index bb5d996..0f315eb 100644 --- a/src/jalview/gui/WsParamSetManager.java +++ b/src/jalview/gui/WsParamSetManager.java @@ -203,7 +203,7 @@ public class WsParamSetManager implements ParamManager chooser.setDialogTitle(MessageManager .getString("label.choose_filename_for_param_file")); chooser.setToolTipText(MessageManager.getString("action.save")); - int value = chooser.showSaveDialog(Desktop.instance); + int value = chooser.showSaveDialog(Desktop.getInstance()); if (value == JalviewFileChooser.APPROVE_OPTION) { outfile = chooser.getSelectedFile(); @@ -311,7 +311,7 @@ public class WsParamSetManager implements ParamManager File pfile = new File(filename); if (pfile.exists() && pfile.canWrite()) { - if (JvOptionPane.showConfirmDialog(Desktop.instance, + if (JvOptionPane.showConfirmDialog(Desktop.getInstance(), "Delete the preset's file, too ?", "Delete User Preset ?", JvOptionPane.OK_CANCEL_OPTION) == JvOptionPane.OK_OPTION) { diff --git a/src/jalview/gui/WsPreferences.java b/src/jalview/gui/WsPreferences.java index 5186a26..b97a25e 100644 --- a/src/jalview/gui/WsPreferences.java +++ b/src/jalview/gui/WsPreferences.java @@ -65,7 +65,7 @@ public class WsPreferences extends GWsPreferences private void initFromPreferences() { - wsUrls = Jws2Discoverer.getDiscoverer().getServiceUrls(); + wsUrls = Jws2Discoverer.getInstance().getServiceUrls(); if (!wsUrls.isEmpty()) { oldUrls = new Vector(wsUrls); @@ -122,7 +122,7 @@ public class WsPreferences extends GWsPreferences int r = 0; for (String url : wsUrls) { - int status = Jws2Discoverer.getDiscoverer().getServerStatusFor(url); + int status = Jws2Discoverer.getInstance().getServerStatusFor(url); tdat[r][1] = Integer.valueOf(status); tdat[r++][0] = url; } @@ -241,7 +241,7 @@ public class WsPreferences extends GWsPreferences private void updateServiceList() { - Jws2Discoverer.getDiscoverer().setServiceUrls(wsUrls); + Jws2Discoverer.getInstance().setServiceUrls(wsUrls); } private void updateRsbsServiceList() @@ -454,7 +454,7 @@ public class WsPreferences extends GWsPreferences boolean valid = false; int resp = JvOptionPane.CANCEL_OPTION; while (!valid && (resp = JvOptionPane.showInternalConfirmDialog( - Desktop.desktop, panel, title, + Desktop.getDesktopPane(), panel, title, JvOptionPane.OK_CANCEL_OPTION)) == JvOptionPane.OK_OPTION) { try @@ -472,13 +472,13 @@ public class WsPreferences extends GWsPreferences } catch (Exception e) { valid = false; - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.invalid_url")); } } if (valid && resp == JvOptionPane.OK_OPTION) { - int validate = JvOptionPane.showInternalConfirmDialog(Desktop.desktop, + int validate = JvOptionPane.showInternalConfirmDialog(Desktop.getDesktopPane(), MessageManager.getString("info.validate_jabaws_server"), MessageManager.getString("label.test_server"), JvOptionPane.YES_NO_OPTION); @@ -491,7 +491,7 @@ public class WsPreferences extends GWsPreferences } else { - int opt = JvOptionPane.showInternalOptionDialog(Desktop.desktop, + int opt = JvOptionPane.showInternalOptionDialog(Desktop.getDesktopPane(), "The Server '" + foo.toString() + "' failed validation,\ndo you want to add it anyway? ", "Server Validation Failed", JvOptionPane.YES_NO_OPTION, @@ -502,7 +502,7 @@ public class WsPreferences extends GWsPreferences } else { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString( "warn.server_didnt_pass_validation")); } @@ -595,7 +595,7 @@ public class WsPreferences extends GWsPreferences if (lastrefresh != update) { lastrefresh = update; - Desktop.instance.startServiceDiscovery(true); // wait around for all + Desktop.getInstance().startServiceDiscovery(true); // wait around for all // threads to complete updateList(); @@ -616,15 +616,15 @@ public class WsPreferences extends GWsPreferences public void run() { long ct = System.currentTimeMillis(); - Desktop.instance.setProgressBar(MessageManager + Desktop.getInstance().setProgressBar(MessageManager .getString("status.refreshing_web_service_menus"), ct); if (lastrefresh != update) { lastrefresh = update; - Desktop.instance.startServiceDiscovery(true); + Desktop.getInstance().startServiceDiscovery(true); updateList(); } - Desktop.instance.setProgressBar(null, ct); + Desktop.getInstance().setProgressBar(null, ct); } }).start(); @@ -646,8 +646,8 @@ public class WsPreferences extends GWsPreferences @Override protected void resetWs_actionPerformed(ActionEvent e) { - Jws2Discoverer.getDiscoverer().setServiceUrls(null); - List nwsUrls = Jws2Discoverer.getDiscoverer().getServiceUrls(); + Jws2Discoverer.getInstance().setServiceUrls(null); + List nwsUrls = Jws2Discoverer.getInstance().getServiceUrls(); if (!wsUrls.equals(nwsUrls)) { update++; diff --git a/src/jalview/io/FeaturesFile.java b/src/jalview/io/FeaturesFile.java index d2a9b0a..821384a 100755 --- a/src/jalview/io/FeaturesFile.java +++ b/src/jalview/io/FeaturesFile.java @@ -88,6 +88,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI private static final String ID_NOT_SPECIFIED = "ID_NOT_SPECIFIED"; + private static final String NOTE = "Note"; + protected static final String GFF_VERSION = "##gff-version"; private AlignmentI lastmatchedAl = null; @@ -591,6 +593,14 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI .getDisplayedFeatureCols(); Map featureFilters = fr.getFeatureFilters(); + // BH check this is out? +// if (!includeNonPositional +// && (visibleColours == null || visibleColours.isEmpty())) +// { +// // no point continuing. +// return "No Features Visible"; +// } + /* * write out feature colours (if we know them) */ @@ -908,7 +918,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * @param sequenceName * @param sequenceFeature */ - protected void formatJalviewFeature( + protected String formatJalviewFeature( StringBuilder out, String sequenceName, SequenceFeature sequenceFeature) { @@ -962,6 +972,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI out.append(sequenceFeature.score); } out.append(newline); + + return out.toString(); } /** @@ -973,14 +985,15 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI AlignViewportI av = getViewport(); if (av != null) { - if (av.getAlignment() != null) + AlignmentI a = av.getAlignment(); + if (a != null) { - dataset = av.getAlignment().getDataset(); + dataset = a.getDataset(); } if (dataset == null) { // working in the applet context ? - dataset = av.getAlignment(); + dataset = a; } } else @@ -1020,11 +1033,9 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * Returns features output in GFF2 format * * @param sequences - * the sequences whose features are to be - * output + * the sequences whose features are to be output * @param visible - * a map whose keys are the type names of - * visible features + * a map whose keys are the type names of visible features * @param visibleFeatureGroups * @param includeNonPositionalFeatures * @param includeComplement @@ -1036,7 +1047,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI { FeatureRenderer fr2 = null; if (includeComplement) - { + { AlignViewportI comp = fr.getViewport().getCodingComplement(); fr2 = Desktop.getAlignFrameFor(comp).getFeatureRenderer(); } @@ -1063,6 +1074,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI { features.addAll(seq.getFeatures().getPositionalFeatures(types)); } + for (SequenceFeature sf : features) { if (sf.isNonPositional() || fr.isVisible(sf)) @@ -1099,34 +1111,34 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI private void formatGffFeature(StringBuilder out, SequenceI seq, SequenceFeature sf) { - String source = sf.featureGroup; - if (source == null) - { - source = sf.getDescription(); - } - - out.append(seq.getName()); - out.append(TAB); - out.append(source); - out.append(TAB); - out.append(sf.type); - out.append(TAB); - out.append(sf.begin); - out.append(TAB); - out.append(sf.end); - out.append(TAB); - out.append(sf.score); - out.append(TAB); - - int strand = sf.getStrand(); - out.append(strand == 1 ? "+" : (strand == -1 ? "-" : ".")); - out.append(TAB); + String source = sf.featureGroup; + if (source == null) + { + source = sf.getDescription(); + } - String phase = sf.getPhase(); - out.append(phase == null ? "." : phase); + out.append(seq.getName()); + out.append(TAB); + out.append(source); + out.append(TAB); + out.append(sf.type); + out.append(TAB); + out.append(sf.begin); + out.append(TAB); + out.append(sf.end); + out.append(TAB); + out.append(sf.score); + out.append(TAB); + + int strand = sf.getStrand(); + out.append(strand == 1 ? "+" : (strand == -1 ? "-" : ".")); + out.append(TAB); + + String phase = sf.getPhase(); + out.append(phase == null ? "." : phase); if (sf.otherDetails != null && !sf.otherDetails.isEmpty()) - { + { Map map = sf.otherDetails; formatAttributes(out, map); } @@ -1237,11 +1249,11 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI * format) * * @param alignedRegions - * a list of "Align fromStart toStart fromCount" + * a list of "Align fromStart toStart fromCount" * @param mapIsFromCdna - * if true, 'from' is dna, else 'from' is protein + * if true, 'from' is dna, else 'from' is protein * @param strand - * either 1 (forward) or -1 (reverse) + * either 1 (forward) or -1 (reverse) * @return * @throws IOException */ @@ -1376,6 +1388,39 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI return seq; } + // BH! check that we did not lose something here. +// /** +// * Process the 'column 9' data of the GFF file. This is less formally defined, +// * and its interpretation will vary depending on the tool that has generated +// * it. +// * +// * @param attributes +// * @param sf +// */ +// protected void processGffColumnNine(String attributes, SequenceFeature sf) +// { +// sf.setAttributes(attributes); +// +// /* +// * Parse attributes in column 9 and add them to the sequence feature's +// * 'otherData' table; use Note as a best proxy for description +// */ +// char nameValueSeparator = gffVersion == 3 ? '=' : ' '; +// // TODO check we don't break GFF2 values which include commas here +// Map> nameValues = GffHelperBase +// .parseNameValuePairs(attributes, ";", nameValueSeparator, ","); +// for (Entry> attr : nameValues.entrySet()) +// { +// String values = StringUtils.listToDelimitedString(attr.getValue(), +// "; "); +// sf.setValue(attr.getKey(), values); +// if (NOTE.equals(attr.getKey())) +// { +// sf.setDescription(values); +// } +// } +// } + /** * After encountering ##fasta in a GFF3 file, process the remainder of the * file as FAST sequence data. Any placeholder sequences created during diff --git a/src/jalview/io/FileLoader.java b/src/jalview/io/FileLoader.java index 1d5be1b..a64582d 100755 --- a/src/jalview/io/FileLoader.java +++ b/src/jalview/io/FileLoader.java @@ -37,11 +37,11 @@ import jalview.gui.JvOptionPane; import jalview.json.binding.biojson.v1.ColourSchemeMapper; import jalview.project.Jalview2XML; import jalview.schemes.ColourSchemeI; -import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.utils.UrlDownloadClient; +import java.awt.Dimension; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; @@ -49,23 +49,35 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; -import java.util.StringTokenizer; -import java.util.Vector; +import java.util.ArrayList; +import java.util.List; import javax.swing.SwingUtilities; public class FileLoader implements Runnable { + private static final String DEFAULT_FILE_FORMAT_PROPERTY = "DEFAULT_FILE_FORMAT"; + + private static final String RECENT_URL_PROPERTY = "RECENT_URL"; + + private static final String RECENT_FILE_PROPERTY = "RECENT_FILE"; + + private static final String TAB = "\t"; + + /* + * maximum number of items in file/url history lists; + * pseudo-constant (not final) so amendable by Groovy if wanted + */ + private static int MAX_HISTORY = 11; + String file; DataSourceType protocol; FileFormatI format; - AlignmentFileReaderI source = null; // alternative specification of where data - // comes - - // from + AlignmentFileReaderI source; // alternative specification of where data + // comes from AlignViewport viewport; @@ -98,20 +110,90 @@ public class FileLoader implements Runnable this.raiseGUI = raiseGUI; } - public void LoadFile(AlignViewport viewport, Object file, + /** + * It is critical that all these fields are set, as this instance is reused. + * + * @param source + * @param file + * @param inFile + * @param dataSourceType + * @param format + */ + private void setFileFields(AlignmentFileReaderI source, File file, + String inFile, DataSourceType dataSourceType, FileFormatI format) + { + this.source = source; + this.file = inFile; + this.selectedFile = file; + this.protocol = dataSourceType; + this.format = format; + } + + + /** + * Uppercase LoadFile is deprecated because it does not pass byte[] data to + * JavaScript + * + * @param viewport + * @param file + * @param protocol + * @param format + */ + @Deprecated + public void LoadFile(AlignViewport viewport, String file, DataSourceType protocol, FileFormatI format) { - this.viewport = viewport; - if (file instanceof File) { - this.selectedFile = (File) file; - file = selectedFile.getPath(); + if (viewport != null) + { + this.viewport = viewport; } - LoadFile(file.toString(), protocol, format); + loadFile(file, protocol, format); } + public void LoadFile(AlignViewport viewport, File file, + DataSourceType protocol, FileFormatI format) + { + loadFile(viewport, file, protocol, format); + } + + /** + * Uppercase LoadFile is deprecated because it does not pass byte[] data to + * JavaScript + * + * @param file + * @param protocol + * @param format + */ + @Deprecated public void LoadFile(String file, DataSourceType protocol, FileFormatI format) { + loadFile(file, protocol, format); + } + + /** + * necessary to use Object here in order to pass the file data + * + * @param viewport + * @param file + * File preferably to String + * @param protocol + * @param format + */ + public void loadFile(AlignViewport viewport, File file, + DataSourceType protocol, FileFormatI format) + { + if (viewport != null) + { + this.viewport = viewport; + } + this.selectedFile = file; + loadFile(selectedFile.getPath(), protocol, format); + } + + private void loadFile(String file, DataSourceType protocol, + FileFormatI format) + { this.file = file; this.protocol = protocol; this.format = format; @@ -129,23 +211,13 @@ public class FileLoader implements Runnable } /** - * Load a (file, protocol) source of unknown type - * - * @param file - * @param protocol - */ - public void LoadFile(String file, DataSourceType protocol) - { - LoadFile(file, protocol, null); - } - - /** * Load alignment from (file, protocol) and wait till loaded * * @param file * @param sourceType * @return alignFrame constructed from file contents */ + @Deprecated public AlignFrame LoadFileWaitTillLoaded(String file, DataSourceType sourceType) { @@ -160,93 +232,84 @@ public class FileLoader implements Runnable * @param format * @return alignFrame constructed from file contents */ + @Deprecated public AlignFrame LoadFileWaitTillLoaded(String file, DataSourceType sourceType, FileFormatI format) { - this.file = file; - this.protocol = sourceType; - this.format = format; - return _LoadFileWaitTillLoaded(); + setFileFields(null, null, file, sourceType, format); + return _loadFileWaitTillLoaded(); } /** * Load alignment from (file, protocol) of type format and wait till loaded * - * @param file + * @param fileObject * @param sourceType * @param format * @return alignFrame constructed from file contents + * @throws NullPointerException + * if {@code file} is null */ - public AlignFrame LoadFileWaitTillLoaded(File file, + public AlignFrame loadFileWaitTillLoaded(File fileObject, DataSourceType sourceType, FileFormatI format) { - this.selectedFile = file; - this.file = file.getPath(); - this.protocol = sourceType; - this.format = format; - return _LoadFileWaitTillLoaded(); + setFileFields(null, fileObject, fileObject.getPath(), sourceType, format); + return _loadFileWaitTillLoaded(); } /** - * Load alignment from FileParse source of type format and wait till loaded - * - * @param source - * @param format - * @return alignFrame constructed from file contents - */ - public AlignFrame LoadFileWaitTillLoaded(AlignmentFileReaderI source, - FileFormatI format) - { - this.source = source; - - file = source.getInFile(); - protocol = source.getDataSourceType(); - this.format = format; - return _LoadFileWaitTillLoaded(); - } - - /** - * runs the 'run' method (in this thread), then return the alignFrame that's - * (hopefully) been read + * Runs the 'run' method (in this thread), then returns the alignFrame that + * (hopefully) has been constructed * * @return */ - protected AlignFrame _LoadFileWaitTillLoaded() + private AlignFrame _loadFileWaitTillLoaded() { this.run(); - return alignFrame; } + /** + * Updates the Jalview properties file to add the last file or URL read to the + * tab-separated list in property RECENT_FILE or RECENT_URL respectively. The + * property is created if it does not already exist. The new entry is added as + * the first item (without duplication). If the list exceeds some maximum + * length (currently 10 entries), the oldest (last) entry is dropped. + *

+ * Files read from the temporary file directory are not added to the property. + *

+ * Property DEFAULT_FILE_FORMAT (e.g. "Fasta" etc) is also set if currently + * reading from file. + */ public void updateRecentlyOpened() { - Vector recent = new Vector<>(); + List recent = new ArrayList<>(); if (protocol == DataSourceType.PASTE) { // do nothing if the file was pasted in as text... there is no filename to // refer to it as. return; } - if (file != null - && file.indexOf(System.getProperty("java.io.tmpdir")) > -1) + // BH logic change here just includes ignoring file==null + if (file == null + || file.indexOf(System.getProperty("java.io.tmpdir")) > -1) { // ignore files loaded from the system's temporary directory return; } - String type = protocol == DataSourceType.FILE ? "RECENT_FILE" - : "RECENT_URL"; + String type = protocol == DataSourceType.FILE ? RECENT_FILE_PROPERTY + : RECENT_URL_PROPERTY; String historyItems = Cache.getProperty(type); - StringTokenizer st; - + // BH simpler coding if (historyItems != null) { - st = new StringTokenizer(historyItems, "\t"); + String[] tokens = historyItems.split("\\t"); - while (st.hasMoreTokens()) + for (String token : tokens) { - recent.addElement(st.nextToken().trim()); + recent.add(token.trim()); } } @@ -255,18 +318,18 @@ public class FileLoader implements Runnable recent.remove(file); } - StringBuffer newHistory = new StringBuffer(file); - for (int i = 0; i < recent.size() && i < 10; i++) + StringBuilder newHistory = new StringBuilder(file); + for (int i = 0; i < recent.size() && i < MAX_HISTORY - 1; i++) { - newHistory.append("\t"); - newHistory.append(recent.elementAt(i)); + newHistory.append(TAB); + newHistory.append(recent.get(i)); } Cache.setProperty(type, newHistory.toString()); if (protocol == DataSourceType.FILE) { - Cache.setProperty("DEFAULT_FILE_FORMAT", format.getName()); + Cache.setProperty(DEFAULT_FILE_FORMAT_PROPERTY, format.getName()); } } @@ -279,9 +342,9 @@ public class FileLoader implements Runnable Runtime rt = Runtime.getRuntime(); try { - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.startLoading(file); + Desktop.getInstance().startLoading(file); } if (format == null) { @@ -303,12 +366,12 @@ public class FileLoader implements Runnable if (format == null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); System.err.println("The input file \"" + file + "\" has null or unidentifiable data content!"); if (!Jalview.isHeadlessMode()) { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.getString("label.couldnt_read_data") + " in " + file + "\n" + AppletFormatAdapter.getSupportedFormats(), @@ -319,7 +382,7 @@ public class FileLoader implements Runnable } // TODO: cache any stream datasources as a temporary file (eg. PDBs // retrieved via URL) - if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage()) + if (Desktop.getDesktopPane() != null && Desktop.getDesktopPane().isShowMemoryUsage()) { System.gc(); memused = (rt.maxMemory() - rt.totalMemory() + rt.freeMemory()); // free @@ -340,7 +403,10 @@ public class FileLoader implements Runnable // We read the data anyway - it might make sense. } // BH 2018 switch to File object here instead of filename + Platform.timeCheck(null, Platform.TIME_MARK); alignFrame = new Jalview2XML(raiseGUI).loadJalviewAlign(selectedFile == null ? file : selectedFile); + Platform.timeCheck("JVP loaded", Platform.TIME_MARK); + } else { @@ -362,15 +428,15 @@ public class FileLoader implements Runnable if (downloadStructureFile) { String structExt = format.getExtensions().split(",")[0]; - String urlLeafName = file.substring( - file.lastIndexOf( - System.getProperty("file.separator")), + int pt = file.lastIndexOf(file.indexOf('/') >= 0 ? "/" + : System.getProperty("file.separator")); + String urlLeafName = file.substring(pt, file.lastIndexOf(".")); String tempStructureFileStr = createNamedJvTempFile( urlLeafName, structExt); - // BH - switching to File object here so as to hold - // ._bytes array directly + // BH - switching to File object here so as to hold on to the + // bytes array directly File tempFile = new File(tempStructureFileStr); UrlDownloadClient.download(file, tempFile); @@ -411,8 +477,7 @@ public class FileLoader implements Runnable { // register PDB entries with desktop's structure selection // manager - StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + Desktop.getStructureSelectionManager() .registerPDBEntry(pdbe); } } @@ -486,8 +551,13 @@ public class FileLoader implements Runnable // status in Jalview 3 // TODO: define 'virtual desktop' for benefit of headless scripts // that perform queries to find the 'current working alignment' - Desktop.addInternalFrame(alignFrame, title, + + + Dimension dim = Platform.getDimIfEmbedded(alignFrame, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + alignFrame.setSize(dim); + Desktop.addInternalFrame(alignFrame, title, dim.width, + dim.height); } try @@ -501,23 +571,23 @@ public class FileLoader implements Runnable } else { - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } final String errorMessage = MessageManager.getString( "label.couldnt_load_file") + " " + title + "\n" + error; // TODO: refactor FileLoader to be independent of Desktop / Applet GUI // bits ? - if (raiseGUI && Desktop.desktop != null) + if (raiseGUI && Desktop.getDesktopPane() != null) { javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), errorMessage, MessageManager .getString("label.error_loading_file"), @@ -545,7 +615,7 @@ public class FileLoader implements Runnable @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.problems_opening_file", new String[] { file }), @@ -567,7 +637,7 @@ public class FileLoader implements Runnable @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "warn.out_of_memory_loading_file", new String[] { file }), @@ -589,7 +659,7 @@ public class FileLoader implements Runnable // memory // after // load - if (Desktop.desktop != null && Desktop.desktop.isShowMemoryUsage()) + if (Desktop.getDesktopPane() != null && Desktop.getDesktopPane().isShowMemoryUsage()) { if (alignFrame != null) { @@ -611,9 +681,9 @@ public class FileLoader implements Runnable } } // remove the visual delay indicator - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } } diff --git a/src/jalview/io/VamsasAppDatastore.java b/src/jalview/io/VamsasAppDatastore.java index 387dbfa..c60fd88 100644 --- a/src/jalview/io/VamsasAppDatastore.java +++ b/src/jalview/io/VamsasAppDatastore.java @@ -720,9 +720,9 @@ public class VamsasAppDatastore // /SAVE THE TREES // ///////////////////////////////// // FIND ANY ASSOCIATED TREES - if (Desktop.desktop != null) + if (Desktop.getDesktopPane() != null) { - javax.swing.JInternalFrame[] frames = Desktop.instance + javax.swing.JInternalFrame[] frames = Desktop.getInstance() .getAllFrames(); for (int t = 0; t < frames.length; t++) @@ -1479,7 +1479,7 @@ public class VamsasAppDatastore if (mappings != null) { jalview.structure.StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + .getStructureSelectionManager(Desktop.getInstance()) .registerMappings(mappings); } } diff --git a/src/jalview/io/WSWUBlastClient.java b/src/jalview/io/WSWUBlastClient.java index 63b78b2..e24c2f3 100755 --- a/src/jalview/io/WSWUBlastClient.java +++ b/src/jalview/io/WSWUBlastClient.java @@ -150,7 +150,7 @@ public class WSWUBlastClient { // This must be outside the run() body as java 1.5 // will not return any value from the OptionPane to the expired thread. - int reply = JvOptionPane.showConfirmDialog(Desktop.desktop, + int reply = JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(), "Automatically update suggested ids?", "Auto replace sequence ids", JvOptionPane.YES_NO_OPTION); diff --git a/src/jalview/io/gff/Gff3Helper.java b/src/jalview/io/gff/Gff3Helper.java index 1ef8848..e422ed4 100644 --- a/src/jalview/io/gff/Gff3Helper.java +++ b/src/jalview/io/gff/Gff3Helper.java @@ -91,7 +91,7 @@ public class Gff3Helper extends GffHelperBase String atts = gff[ATTRIBUTES_COL]; Map> attributes = parseNameValuePairs(atts); - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); if (so.isA(soTerm, SequenceOntologyI.PROTEIN_MATCH)) { sf = processProteinMatch(attributes, seq, gff, align, newseqs, @@ -385,7 +385,7 @@ public class Gff3Helper extends GffHelperBase desc = target.split(" ")[0]; } - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); String type = sf.getType(); if (so.isA(type, SequenceOntologyI.SEQUENCE_VARIANT)) { diff --git a/src/jalview/io/gff/InterProScanHelper.java b/src/jalview/io/gff/InterProScanHelper.java index 948cdd2..141b677 100644 --- a/src/jalview/io/gff/InterProScanHelper.java +++ b/src/jalview/io/gff/InterProScanHelper.java @@ -108,7 +108,7 @@ public class InterProScanHelper extends Gff3Helper */ public static boolean recognises(String[] columns) { - SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + SequenceOntologyI so = SequenceOntologyFactory.getSequenceOntology(); String type = columns[TYPE_COL]; if (so.isA(type, SequenceOntologyI.PROTEIN_MATCH) || (".".equals(columns[SOURCE_COL]) diff --git a/src/jalview/io/gff/SequenceOntologyFactory.java b/src/jalview/io/gff/SequenceOntologyFactory.java index 90cae7a..2ba41da 100644 --- a/src/jalview/io/gff/SequenceOntologyFactory.java +++ b/src/jalview/io/gff/SequenceOntologyFactory.java @@ -20,29 +20,62 @@ */ package jalview.io.gff; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; + /** * A factory class that returns a model of the Sequence Ontology. By default a - * hard-coded subset is used (for the applet, or testing), or setInstance() can - * be used to set full Ontology data. + * hard-coded subset is used (for the applet, or testing), or + * setSequenceOntology() can be used to set full Ontology data. * * @author gmcarstairs * */ -public class SequenceOntologyFactory +public class SequenceOntologyFactory implements ApplicationSingletonI { - private static SequenceOntologyI instance; + /** + * Answers an instance of this class for the current application context. Note + * that this supports running two JS 'applets' on the same page, one with the + * full Sequence Ontology (USE_FULL_SO = true) and one with a hard-coded + * subset (USE_FULL_SO = false). If this is overkill, could change this method + * to just return a common static instance. + * + * @return + */ + private static synchronized SequenceOntologyFactory getInstance() + { + return (SequenceOntologyFactory) ApplicationSingletonProvider + .getInstance(SequenceOntologyFactory.class); + } + + /** + * Answers the configured model of the Sequence Ontology. + * + * @return + */ + public static synchronized SequenceOntologyI getSequenceOntology() + { + SequenceOntologyFactory f = getInstance(); + return (f.sequenceOntology == null + ? f.sequenceOntology = new SequenceOntologyLite() + : f.sequenceOntology); + } - public static synchronized SequenceOntologyI getInstance() + /** + * For testng only + * + * @param so + */ + public static void setSequenceOntology(SequenceOntologyI so) { - if (instance == null) - { - instance = new SequenceOntologyLite(); - } - return instance; + getInstance().sequenceOntology = so; } - public static void setInstance(SequenceOntologyI so) + private SequenceOntologyI sequenceOntology; + + private SequenceOntologyFactory() { - instance = so; + // private singleton } + } diff --git a/src/jalview/io/vamsas/Sequencemapping.java b/src/jalview/io/vamsas/Sequencemapping.java index 0a582e5..402ffdf 100644 --- a/src/jalview/io/vamsas/Sequencemapping.java +++ b/src/jalview/io/vamsas/Sequencemapping.java @@ -365,7 +365,7 @@ public class Sequencemapping extends Rangetype } bindjvvobj(mapping, sequenceMapping); jalview.structure.StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + .getStructureSelectionManager(Desktop.getInstance()) .registerMapping(acf); // Try to link up any conjugate database references in the two sequences // matchConjugateDBRefs(from, to, mapping); diff --git a/src/jalview/javascript/JSFunctionExec.java b/src/jalview/javascript/JSFunctionExec.java index 29f3fa9..ad7a379 100644 --- a/src/jalview/javascript/JSFunctionExec.java +++ b/src/jalview/javascript/JSFunctionExec.java @@ -20,26 +20,28 @@ */ package jalview.javascript; -import jalview.bin.JalviewLite; +import jalview.api.JalviewApp; import java.net.URL; +import java.util.Hashtable; import java.util.Vector; import netscape.javascript.JSObject; public class JSFunctionExec implements Runnable { - public JalviewLite jvlite; + public JalviewApp jvlite; - public JSFunctionExec(JalviewLite applet) + protected boolean debug; + + public JSFunctionExec(JalviewApp applet, boolean debug) { jvlite = applet; - - jsExecQueue = jvlite.getJsExecQueue(); - jvlite.setExecutor(this); + this.debug = debug; + jsExecQueue = jvlite.getJsExecQueue(this); } - private Vector jsExecQueue; + private Vector jsExecQueue; private Thread executor = null; @@ -47,7 +49,7 @@ public class JSFunctionExec implements Runnable { if (jsExecQueue != null) { - Vector q = null; + Vector q = null; synchronized (jsExecQueue) { q = jsExecQueue; @@ -55,9 +57,9 @@ public class JSFunctionExec implements Runnable } if (q != null) { - for (JSFunctionExec jx : q) + for (Runnable jx : q) { - jx.jvlite = null; + ((JSFunctionExec) jx).jvlite = null; } q.removeAllElements(); @@ -78,7 +80,7 @@ public class JSFunctionExec implements Runnable { if (jsExecQueue.size() > 0) { - Runnable r = (Runnable) jsExecQueue.elementAt(0); + Runnable r = jsExecQueue.elementAt(0); jsExecQueue.removeElementAt(0); try { @@ -162,14 +164,14 @@ public class JSFunctionExec implements Runnable JSObject scriptObject = null; try { - scriptObject = JSObject.getWindow(jvlite); + scriptObject = jvlite.getJSObject(); } catch (Exception ex) { } ; if (scriptObject != null) { - if (jvlite.debug && dbgMsg != null) + if (debug && dbgMsg != null) { System.err.println(dbgMsg); } @@ -180,15 +182,15 @@ public class JSFunctionExec implements Runnable // squash any malformedURLExceptions thrown by windows/safari if (!(jex instanceof java.net.MalformedURLException)) { - if (jvlite.debug) + if (debug) { System.err.println(jex); } if (jex instanceof netscape.javascript.JSException - && jvlite.jsfallbackEnabled) + && jvlite.isJsfallbackEnabled()) { jsex[0] = jex; - if (jvlite.debug) + if (debug) { System.err.println("Falling back to javascript: url call"); } @@ -211,7 +213,7 @@ public class JSFunctionExec implements Runnable sb.append("\""); } sb.append(")"); - if (jvlite.debug) + if (debug) { System.err.println(sb.toString()); } @@ -248,7 +250,7 @@ public class JSFunctionExec implements Runnable { if (executor == null) { - executor = new Thread(new JSFunctionExec(jvlite)); + executor = new Thread(new JSFunctionExec(jvlite, debug)); executor.start(); } synchronized (jsExecQueue) @@ -268,4 +270,80 @@ public class JSFunctionExec implements Runnable } } + public static void setJsMessageSet(String messageclass, String viewId, + String[] colcommands, JalviewApp app) + { + Hashtable> jsmessages = app + .getJSMessages(); + Hashtable jshashes = app.getJSHashes(); + + Hashtable msgset = jsmessages.get(messageclass); + if (msgset == null) + { + msgset = new Hashtable<>(); + jsmessages.put(messageclass, msgset); + } + msgset.put(viewId, colcommands); + int[] l = new int[colcommands.length]; + for (int i = 0; i < colcommands.length; i++) + { + l[i] = colcommands[i].hashCode(); + } + jshashes.put(messageclass + "|" + viewId, l); + } + + /* + * (non-Javadoc) + * + * @see jalview.bin.JalviewLiteJsApi#getJsMessage(java.lang.String, + * java.lang.String) + */ + public static String getJsMessage(String messageclass, String viewId, + JalviewApp app) + { + Hashtable msgset = app.getJSMessages() + .get(messageclass); + if (msgset != null) + { + String[] msgs = msgset.get(viewId); + if (msgs != null) + { + for (int i = 0; i < msgs.length; i++) + { + if (msgs[i] != null) + { + String m = msgs[i]; + msgs[i] = null; + return m; + } + } + } + } + return ""; + } + + public static boolean isJsMessageSetChanged(String string, String string2, + String[] colcommands, JalviewApp app) + { + int[] l = app.getJSHashes().get(string + "|" + string2); + if (l == null && colcommands != null) + { + return true; + } + for (int i = 0; i < colcommands.length; i++) + { + if (l[i] != colcommands[i].hashCode()) + { + return true; + } + } + return false; + } + + public void tidyUp() + { + stopQueue(); + jvlite = null; + } + } diff --git a/src/jalview/javascript/JalviewLiteJsApi.java b/src/jalview/javascript/JalviewLiteJsApi.java index b5811aa..3ce2c9f 100644 --- a/src/jalview/javascript/JalviewLiteJsApi.java +++ b/src/jalview/javascript/JalviewLiteJsApi.java @@ -1,13 +1,13 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) - * Copyright (C) $$Year-Rel$$ The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$); + * Copyright (C); $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 - * of the License, or (at your option) any later version. + * of the License, or (at your option); any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty @@ -20,13 +20,13 @@ */ package jalview.javascript; -import jalview.appletgui.AlignFrame; +import jalview.api.AlignFrameI; /** * The following public methods may be called * externally, eg via javascript in an HTML page. * - *
TODO: introduce abstract interface for jalview.appletgui.AlignFrame
+ *
TODO: introduce abstract interface for jalview.appletgui.AlignFrameI
* * Most function arguments are strings, which contain serialised versions of lists. * Lists of things are separated by a separator character - either the default or a user supplied one. @@ -42,7 +42,7 @@ public interface JalviewLiteJsApi /** * @return String list of selected sequence IDs, each terminated by the - * 'boolean not' character (""+0x00AC) or (¬) + * 'boolean not' character (""+0x00AC); or (¬); */ public abstract String getSelectedSequences(); @@ -56,12 +56,12 @@ public interface JalviewLiteJsApi /** * @param alf - * alignframe containing selection + * AlignFrameI containing selection * @return String list of selected sequence IDs, each terminated by current * default separator sequence * */ - public abstract String getSelectedSequencesFrom(AlignFrame alf); + public abstract String getSelectedSequencesFrom(AlignFrameI alf); /** * get list of selected sequence IDs separated by given separator @@ -73,7 +73,7 @@ public interface JalviewLiteJsApi * @return String list of selected sequence IDs, each terminated by the given * separator */ - public abstract String getSelectedSequencesFrom(AlignFrame alf, + public abstract String getSelectedSequencesFrom(AlignFrameI alf, String sep); /** @@ -99,7 +99,7 @@ public interface JalviewLiteJsApi * false, blank or something else - indicate if position is an * alignment column or unaligned sequence position */ - public abstract void highlightIn(AlignFrame alf, String sequenceId, + public abstract void highlightIn(AlignFrameI alf, String sequenceId, String position, String alignedPosition); /** @@ -133,7 +133,7 @@ public interface JalviewLiteJsApi * @param sep * separator between toselect fields */ - public abstract void selectIn(AlignFrame alf, String sequenceIds, + public abstract void selectIn(AlignFrameI alf, String sequenceIds, String columns); /** @@ -145,11 +145,11 @@ public interface JalviewLiteJsApi * @param sep * separator between toselect fields */ - public abstract void selectIn(AlignFrame alf, String sequenceIds, + public abstract void selectIn(AlignFrameI alf, String sequenceIds, String columns, String sep); /** - * get sequences selected in current alignFrame and return their alignment in + * get sequences selected in current AlignFrameI and return their alignment in * format 'format' either with or without suffix * * @param alf @@ -177,7 +177,8 @@ public interface JalviewLiteJsApi * @return selected sequences as flat file or empty string if there was no * current selection */ - public abstract String getSelectedSequencesAsAlignmentFrom(AlignFrame alf, + public abstract String getSelectedSequencesAsAlignmentFrom( + AlignFrameI alf, String format, String suffix); /** @@ -195,7 +196,7 @@ public interface JalviewLiteJsApi * @param alf * @return */ - public abstract String getAlignmentOrderFrom(AlignFrame alf); + public abstract String getAlignmentOrderFrom(AlignFrameI alf); /** * get a sep separated list of sequence IDs reflecting the order of the @@ -206,7 +207,8 @@ public interface JalviewLiteJsApi * - separator to use * @return */ - public abstract String getAlignmentOrderFrom(AlignFrame alf, String sep); + public abstract String getAlignmentOrderFrom(AlignFrameI alf, + String sep); /** * re-order the current alignment using the given list of sequence IDs @@ -232,7 +234,8 @@ public interface JalviewLiteJsApi * @return 'true' if alignment was actually reordered. empty string if * alignment did not contain sequences. */ - public abstract String orderBy(String order, String undoName, String sep); + public abstract String orderBy(String order, String undoName, + String sep); /** * re-order the given alignment using the given list of sequence IDs separated @@ -247,12 +250,12 @@ public interface JalviewLiteJsApi * @return 'true' if alignment was actually reordered. empty string if * alignment did not contain sequences. */ - public abstract String orderAlignmentBy(AlignFrame alf, String order, + public abstract String orderAlignmentBy(AlignFrameI alf, String order, String undoName, String sep); /** * get alignment as format (format names FASTA, BLC, CLUSTAL, MSF, PILEUP, - * PFAM - see jalview.io.AppletFormatAdapter for full list) + * PFAM - see jalview.io.AppletFormatAdapter for full list); * * @param format * @return @@ -266,7 +269,7 @@ public interface JalviewLiteJsApi * @param format * @return */ - public abstract String getAlignmentFrom(AlignFrame alf, String format); + public abstract String getAlignmentFrom(AlignFrameI alf, String format); /** * get alignment as format with jalview start-end sequence suffix appended @@ -286,7 +289,7 @@ public interface JalviewLiteJsApi * @param suffix * @return */ - public abstract String getAlignmentFrom(AlignFrame alf, String format, + public abstract String getAlignmentFrom(AlignFrameI alf, String format, String suffix); /** @@ -302,12 +305,12 @@ public interface JalviewLiteJsApi * @param alf * @param annotation */ - public abstract void loadAnnotationFrom(AlignFrame alf, + public abstract void loadAnnotationFrom(AlignFrameI alf, String annotation); /** * parse the given string as a jalview feature or GFF annotation file and - * optionally enable feature display on the current alignFrame + * optionally enable feature display on the current AlignFrameI * * @param features * - gff or features file @@ -320,7 +323,7 @@ public interface JalviewLiteJsApi /** * parse the given string as a jalview feature or GFF annotation file and - * optionally enable feature display on the given alignFrame. + * optionally enable feature display on the given AlignFrameI. * * @param alf * @param features @@ -330,11 +333,11 @@ public interface JalviewLiteJsApi * be parsed from the string. * @return true if data parsed as features */ - public abstract boolean loadFeaturesFrom(AlignFrame alf, String features, + public abstract boolean loadFeaturesFrom(AlignFrameI alf, String features, boolean autoenabledisplay); /** - * get the sequence features in the given format (Jalview or GFF) + * get the sequence features in the given format (Jalview or GFF); * * @param format * @return @@ -342,13 +345,13 @@ public interface JalviewLiteJsApi public abstract String getFeatures(String format); /** - * get the sequence features in alf in the given format (Jalview or GFF) + * get the sequence features in alf in the given format (Jalview or GFF); * * @param alf * @param format * @return */ - public abstract String getFeaturesFrom(AlignFrame alf, String format); + public abstract String getFeaturesFrom(AlignFrameI alf, String format); /** * get current alignment's annotation as an annotation file @@ -363,30 +366,30 @@ public interface JalviewLiteJsApi * @param alf * @return */ - public abstract String getAnnotationFrom(AlignFrame alf); + public abstract String getAnnotationFrom(AlignFrameI alf); /** - * create a new view and return the alignFrame instance + * create a new view and return the AlignFrameI instance * * @return */ - public abstract AlignFrame newView(); + public abstract AlignFrameI newView(); /** - * create a new view named name and return the alignFrame instance + * create a new view named name and return the AlignFrameI instance * * @param name * @return */ - public abstract AlignFrame newView(String name); + public abstract AlignFrameI newView(String name); /** - * create a new view on alf and return the alignFrame instance + * create a new view on alf and return the AlignFrameI instance * * @param alf * @return */ - public abstract AlignFrame newViewFrom(AlignFrame alf); + public abstract AlignFrameI newViewFrom(AlignFrameI alf); /** * create a new view named name on alf @@ -395,7 +398,7 @@ public interface JalviewLiteJsApi * @param name * @return */ - public abstract AlignFrame newViewFrom(AlignFrame alf, String name); + public abstract AlignFrameI newViewFrom(AlignFrameI alf, String name); /** * @@ -405,15 +408,15 @@ public interface JalviewLiteJsApi * window title * @return null or new alignment frame */ - public abstract AlignFrame loadAlignment(String text, String title); + public abstract AlignFrameI loadAlignment(String text, String title); /** * register a javascript function to handle any alignment mouseover events * * @param listener * name of javascript function (called with arguments - * [jalview.appletgui.AlignFrame,String(sequence id),String(column in - * alignment), String(position in sequence)] + * [jalview.appletgui.AlignFrameI,String(sequence id);,String(column + * in alignment);, String(position in sequence);] */ public abstract void setMouseoverListener(String listener); @@ -421,12 +424,13 @@ public interface JalviewLiteJsApi * register a javascript function to handle mouseover events * * @param af - * (null or specific alignframe for which events are to be listened - * for) + * (null or specific AlignFrameI for which events are to be listened + * for); * @param listener * name of javascript function */ - public abstract void setMouseoverListener(AlignFrame af, String listener); + public abstract void setMouseoverListener(AlignFrameI af, + String listener); /** * register a javascript function to handle any alignment selection events. @@ -435,14 +439,15 @@ public interface JalviewLiteJsApi * * @param listener * name of javascript function (called with arguments - * [jalview.appletgui.AlignFrame, String(sequence set id), - * String(separator separated list of sequences which were selected), - * String(separator separated list of column ranges (i.e. single - * number or hyphenated range) that were selected)] + * [jalview.appletgui.AlignFrameI, String(sequence set id);, + * String(separator separated list of sequences which were + * selected);, String(separator separated list of column ranges (i.e. + * single number or hyphenated range); that were selected);] */ public abstract void setSelectionListener(String listener); - public abstract void setSelectionListener(AlignFrame af, String listener); + public abstract void setSelectionListener(AlignFrameI af, + String listener); /** * register a javascript function to handle events normally routed to a Jmol @@ -450,11 +455,11 @@ public interface JalviewLiteJsApi * * @param listener * - javascript function (arguments are variable, see - * jalview.javascript.MouseOverStructureListener for full details) + * jalview.javascript.MouseOverStructureListener for full details); * @param modelSet * - separator separated list of PDB file URIs that this viewer is * handling. These files must be in the same order they appear in - * Jmol (e.g. first one is frame 1, second is frame 2, etc). + * Jmol (e.g. first one is frame 1, second is frame 2, etc);. * @see jalview.javascript.MouseOverStructureListener */ public abstract void setStructureListener(String listener, @@ -462,14 +467,14 @@ public interface JalviewLiteJsApi /** * remove any callback using the given listener function and associated with - * the given alignFrame (or null for all callbacks) + * the given AlignFrameI (or null for all callbacks); * * @param af - * (may be null) + * (may be null); * @param listener - * (may be null) + * (may be null); */ - public abstract void removeJavascriptListener(AlignFrame af, + public abstract void removeJavascriptListener(AlignFrameI af, String listener); /** @@ -484,10 +489,10 @@ public interface JalviewLiteJsApi String pdbfile); /** - * bind a pdb file to a sequence in the given alignFrame. + * bind a pdb file to a sequence in the given AlignFrameI. * * @param alFrame - * - null or specific alignFrame. This specifies the dataset that + * - null or specific AlignFrameI. This specifies the dataset that * will be searched for a seuqence called sequenceId * @param sequenceId * - sequenceId within the dataset. @@ -499,7 +504,7 @@ public interface JalviewLiteJsApi * structure for indicating when PDB parsing or sequenceId location * fails. */ - public abstract boolean addPdbFile(AlignFrame alFrame, String sequenceId, + public abstract boolean addPdbFile(AlignFrameI alFrame, String sequenceId, String pdbEntryString, String pdbFile); /** @@ -510,7 +515,7 @@ public interface JalviewLiteJsApi * @param topRow * @param leftHandColumn */ - public abstract void scrollViewToIn(AlignFrame alf, String topRow, + public abstract void scrollViewToIn(AlignFrameI alf, String topRow, String leftHandColumn); /** @@ -519,7 +524,7 @@ public interface JalviewLiteJsApi * @param alf * @param topRow */ - public abstract void scrollViewToRowIn(AlignFrame alf, String topRow); + public abstract void scrollViewToRowIn(AlignFrameI alf, String topRow); /** * adjust horizontal scroll to make the given column the left one in the given @@ -528,28 +533,28 @@ public interface JalviewLiteJsApi * @param alf * @param leftHandColumn */ - public abstract void scrollViewToColumnIn(AlignFrame alf, + public abstract void scrollViewToColumnIn(AlignFrameI alf, String leftHandColumn); /** * * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroups() + * @see jalview.appletgui.AlignFrameI#getFeatureGroups(); */ public abstract String getFeatureGroups(); /** * @param alf - * alignframe to get feature groups on + * AlignFrameI to get feature groups on * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroups() + * @see jalview.appletgui.AlignFrameI#getFeatureGroups(); */ - public abstract String getFeatureGroupsOn(AlignFrame alf); + public abstract String getFeatureGroupsOn(AlignFrameI alf); /** * @param visible * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean) + * @see jalview.appletgui.AlignFrameI#getFeatureGroupsOfState(boolean); */ public abstract String getFeatureGroupsOfState(boolean visible); @@ -558,9 +563,9 @@ public interface JalviewLiteJsApi * align frame to get groups of state visible * @param visible * @return - * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean) + * @see jalview.appletgui.AlignFrameI#getFeatureGroupsOfState(boolean); */ - public abstract String getFeatureGroupsOfStateOn(AlignFrame alf, + public abstract String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible); /** @@ -568,10 +573,11 @@ public interface JalviewLiteJsApi * tab separated list of group names * @param state * true or false - * @see jalview.appletgui.AlignFrame#setFeatureGroupState(java.lang.String[], - * boolean) + * @see jalview.appletgui.AlignFrameI#setFeatureGroupState(java.lang.String[], + * boolean); */ - public abstract void setFeatureGroupStateOn(AlignFrame alf, String groups, + public abstract void setFeatureGroupStateOn(AlignFrameI alf, + String groups, boolean state); public abstract void setFeatureGroupState(String groups, boolean state); @@ -600,4 +606,24 @@ public interface JalviewLiteJsApi */ public abstract String getJsMessage(String messageclass, String viewId); + /// in http://www.jalview.org/examples/jalviewLiteJs.html but missing here + + // get selected sequences as alignment as format with or without start-end + // suffix + public String getSelectedSequencesAsAlignment(String format, + boolean suffix); + + // get selected sequences as alignment from given view as format with or + // without start-end suffix + public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf, + String format, boolean suffix); + + public String arrayToSeparatorList(String[] array); + + // get a string array from a list + public String[] separatorListToArray(String list); + + // debug flag - controls output to standard out + public static boolean debug = false; + } diff --git a/src/jalview/javascript/MouseOverListener.java b/src/jalview/javascript/MouseOverListener.java index 6a4d0f8..7c74965 100644 --- a/src/jalview/javascript/MouseOverListener.java +++ b/src/jalview/javascript/MouseOverListener.java @@ -20,8 +20,8 @@ */ package jalview.javascript; +import jalview.api.JalviewApp; import jalview.appletgui.AlignFrame; -import jalview.bin.JalviewLite; import jalview.datamodel.SequenceI; import jalview.structure.VamsasListener; import jalview.structure.VamsasSource; @@ -48,25 +48,12 @@ public class MouseOverListener extends JSFunctionExec // + seq + " at " + index); last = seq; i = index; - AlignFrame src = null; + Object alignFrame = jvlite.getFrameForSource(source); try { - if (source != null) - { - if (source instanceof jalview.appletgui.AlignViewport - && ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame.viewport == source) - { - // should be valid if it just generated an event! - src = ((jalview.appletgui.AlignViewport) source).applet.currentAlignFrame; - - } - // TODO: ensure that if '_af' is specified along with a handler - // function, then only events from that alignFrame are sent to that - // function - } executeJavascriptFunction(_listener, new Object[] - { src, seq.getDisplayId(false), "" + (1 + i), + { alignFrame, seq.getDisplayId(false), "" + (1 + i), "" + seq.findPosition(i) }); } catch (Exception ex) { @@ -84,10 +71,10 @@ public class MouseOverListener extends JSFunctionExec } } - public MouseOverListener(JalviewLite applet, AlignFrame af, - String listener) + public MouseOverListener(JalviewApp applet, AlignFrame af, + String listener, boolean debug) { - super(applet); + super(applet, debug); _af = af; _listener = listener; } diff --git a/src/jalview/jbgui/GDesktop.java b/src/jalview/jbgui/GDesktop.java index e4a5905..9e15eea 100755 --- a/src/jalview/jbgui/GDesktop.java +++ b/src/jalview/jbgui/GDesktop.java @@ -21,11 +21,13 @@ package jalview.jbgui; import jalview.api.AlignmentViewPanel; +import jalview.bin.Jalview; import jalview.io.FileFormatException; import jalview.util.MessageManager; import jalview.util.Platform; import java.awt.FlowLayout; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -36,16 +38,15 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; /** - * DOCUMENT ME! + * abstract class super to jalview.gui.Desktop * - * @author $author$ - * @version $Revision$ */ @SuppressWarnings("serial") -public class GDesktop extends JFrame +// BH made abstract +public abstract class GDesktop extends JFrame { - protected static JMenu windowMenu = new JMenu(); + protected JMenu windowMenu = new JMenu(); // BH 2019.05.07 was static JMenuBar desktopMenubar = new JMenuBar(); @@ -53,6 +54,10 @@ public class GDesktop extends JFrame JMenu HelpMenu = new JMenu(); + protected JMenu VamsasMenu = new JMenu(); + + protected JMenu VamsasStMenu = new JMenu(); + JMenuItem inputLocalFileMenuItem = new JMenuItem(); JMenuItem inputURLMenuItem = new JMenuItem(); @@ -79,6 +84,15 @@ public class GDesktop extends JFrame JMenu inputMenu = new JMenu(); + // in JalviewJS + protected JMenuItem vamsasStart = new JMenuItem(); + + protected JMenuItem vamsasImport = new JMenuItem(); + + protected JMenuItem vamsasSave = new JMenuItem(); + + protected JMenuItem vamsasStop = new JMenuItem(); + JMenuItem inputSequence = new JMenuItem(); JMenuItem closeAll = new JMenuItem(); @@ -97,7 +111,8 @@ public class GDesktop extends JFrame protected JCheckBoxMenuItem showConsole = new JCheckBoxMenuItem(); - protected JCheckBoxMenuItem showNews = new JCheckBoxMenuItem(); + // BH public for Runnable + public JCheckBoxMenuItem showNews = new JCheckBoxMenuItem(); protected JMenuItem snapShotWindow = new JMenuItem(); @@ -106,7 +121,6 @@ public class GDesktop extends JFrame */ public GDesktop() { - super(); try { jbInit(); @@ -122,6 +136,7 @@ public class GDesktop extends JFrame // but here we want just not a Mac, period, right? FileMenu.setMnemonic('F'); inputLocalFileMenuItem.setMnemonic('L'); + VamsasMenu.setMnemonic('V'); inputURLMenuItem.setMnemonic('U'); inputTextboxMenuItem.setMnemonic('C'); quit.setMnemonic('Q'); @@ -139,14 +154,20 @@ public class GDesktop extends JFrame */ private void jbInit() throws Exception { - setName("jalview-desktop"); + setName(Jalview.getAppID("desktop")); FileMenu.setText(MessageManager.getString("action.file")); HelpMenu.setText(MessageManager.getString("action.help")); + VamsasMenu.setText("Vamsas"); + VamsasMenu.setToolTipText(MessageManager + .getString("label.share_data_vamsas_applications")); + VamsasStMenu.setText(MessageManager.getString("label.connect_to")); + VamsasStMenu.setToolTipText( + MessageManager.getString("label.join_existing_vamsas_session")); inputLocalFileMenuItem .setText(MessageManager.getString("label.load_tree_from_file")); inputLocalFileMenuItem.setAccelerator( javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, - jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false)); inputLocalFileMenuItem .addActionListener(new java.awt.event.ActionListener() @@ -254,6 +275,39 @@ public class GDesktop extends JFrame } }); inputMenu.setText(MessageManager.getString("label.input_alignment")); + vamsasStart + .setText(MessageManager.getString("label.new_vamsas_session")); + vamsasStart.setVisible(false); + vamsasStart.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + vamsasStart_actionPerformed(e); + } + }); + vamsasImport.setText( + MessageManager.getString("action.load_vamsas_session")); + vamsasImport.setVisible(false); + vamsasImport.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + vamsasImport_actionPerformed(e); + } + }); + vamsasSave.setText( + MessageManager.getString("action.save_vamsas_session")); + vamsasSave.setVisible(false); + vamsasSave.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + vamsasSave_actionPerformed(e); + } + }); inputSequence .setText(MessageManager.getString("action.fetch_sequences")); inputSequence.addActionListener(new ActionListener() @@ -264,6 +318,17 @@ public class GDesktop extends JFrame inputSequence_actionPerformed(e); } }); + vamsasStop + .setText(MessageManager.getString("label.stop_vamsas_session")); + vamsasStop.setVisible(false); + vamsasStop.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + vamsasStop_actionPerformed(e); + } + }); closeAll.setText(MessageManager.getString("action.close_all")); closeAll.addActionListener(new ActionListener() { @@ -366,32 +431,36 @@ public class GDesktop extends JFrame } }); - Float specversion = Platform.isJS() ? Float.valueOf(8) - : Float.parseFloat( - System.getProperty("java.specification.version")); - desktopMenubar.add(FileMenu); desktopMenubar.add(toolsMenu); + VamsasMenu.setVisible(false); + desktopMenubar.add(VamsasMenu); desktopMenubar.add(HelpMenu); desktopMenubar.add(windowMenu); FileMenu.add(inputMenu); FileMenu.add(inputSequence); FileMenu.addSeparator(); - //FileMenu.add(saveState); + FileMenu.add(saveState); FileMenu.add(saveAsState); FileMenu.add(loadState); FileMenu.addSeparator(); FileMenu.add(quit); HelpMenu.add(aboutMenuItem); HelpMenu.add(documentationMenuItem); - if (!Platform.isAMacAndNotJS() || specversion < 11) - { - toolsMenu.add(preferences); - } + VamsasMenu.add(VamsasStMenu); + VamsasStMenu.setVisible(false); + VamsasMenu.add(vamsasStart); + VamsasMenu.add(vamsasImport); + VamsasMenu.add(vamsasSave); + VamsasMenu.add(vamsasStop); + toolsMenu.add(preferences); if (!Platform.isJS()) { toolsMenu.add(showMemusage); toolsMenu.add(showConsole); + } + if (!Platform.isJS()) + { toolsMenu.add(showNews); toolsMenu.add(garbageCollect); toolsMenu.add(groovyShell); @@ -493,7 +562,6 @@ public class GDesktop extends JFrame */ protected void quit() { - //System.out.println("********** GDesktop.quit()"); } /** diff --git a/src/jalview/jbgui/GSequenceLink.java b/src/jalview/jbgui/GSequenceLink.java index a43e504..2ec7051 100755 --- a/src/jalview/jbgui/GSequenceLink.java +++ b/src/jalview/jbgui/GSequenceLink.java @@ -219,7 +219,7 @@ public class GSequenceLink extends JPanel return true; } - JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.desktop, + JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.getDesktopPane(), MessageManager.getString("warn.url_must_contain"), MessageManager.getString("label.invalid_url"), JvOptionPane.WARNING_MESSAGE); @@ -228,7 +228,7 @@ public class GSequenceLink extends JPanel public void notifyDuplicate() { - JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.desktop, + JvOptionPane.showInternalMessageDialog(jalview.gui.Desktop.getDesktopPane(), MessageManager.getString("warn.name_cannot_be_duplicate"), MessageManager.getString("label.invalid_name"), JvOptionPane.WARNING_MESSAGE); diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index 6340e64..15ac169 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -1082,7 +1082,7 @@ public class Jalview2XML * only view *should* be coped with sensibly. */ // This must have been loaded, is it still visible? - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); String matchedFile = null; for (int f = frames.length - 1; f > -1; f--) { @@ -1234,9 +1234,9 @@ public class Jalview2XML { // FIND ANY ASSOCIATED TREES // NOT IMPLEMENTED FOR HEADLESS STATE AT PRESENT - if (Desktop.desktop != null) + if (Desktop.getDesktopPane() != null) { - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); for (int t = 0; t < frames.length; t++) { @@ -1280,9 +1280,9 @@ public class Jalview2XML /* * save PCA viewers */ - if (!storeDS && Desktop.desktop != null) + if (!storeDS && Desktop.getDesktopPane() != null) { - for (JInternalFrame frame : Desktop.desktop.getAllFrames()) + for (JInternalFrame frame : Desktop.getDesktopPane().getAllFrames()) { if (frame instanceof PCAPanel) { @@ -1923,11 +1923,11 @@ public class Jalview2XML final SequenceI jds, List viewIds, AlignmentPanel ap, boolean storeDataset) { - if (Desktop.desktop == null) + if (Desktop.getDesktopPane() == null) { return; } - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames(); for (int f = frames.length - 1; f > -1; f--) { if (frames[f] instanceof AppVarna) @@ -2383,7 +2383,7 @@ public class Jalview2XML if (calcIdParam.getVersion().equals("1.0")) { final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]); - Jws2Instance service = Jws2Discoverer.getDiscoverer() + Jws2Instance service = Jws2Discoverer.getInstance() .getPreferredServiceFor(calcIds); if (service != null) { @@ -2926,9 +2926,9 @@ public class Jalview2XML { // used to attempt to parse as V1 castor-generated xml } - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } if (af != null) { @@ -2956,7 +2956,7 @@ public class Jalview2XML */ for (AlignFrame fr : gatherToThisFrame.values()) { - Desktop.instance.gatherViews(fr); + Desktop.getInstance().gatherViews(fr); } restoreSplitFrames(); @@ -2965,7 +2965,7 @@ public class Jalview2XML if (ds.getCodonFrames() != null) { StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + .getStructureSelectionManager(Desktop.getInstance()) .registerMappings(ds.getCodonFrames()); } } @@ -2974,9 +2974,9 @@ public class Jalview2XML reportErrors(); } - if (Desktop.instance != null) + if (Desktop.getInstance() != null) { - Desktop.instance.stopLoading(); + Desktop.getInstance().stopLoading(); } return af; @@ -3057,7 +3057,7 @@ public class Jalview2XML */ for (SplitFrame sf : gatherTo) { - Desktop.instance.gatherViews(sf); + Desktop.getInstance().gatherViews(sf); } splitFrameCandidates.clear(); @@ -3116,7 +3116,7 @@ public class Jalview2XML @Override public void run() { - JvOptionPane.showInternalMessageDialog(Desktop.desktop, + JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(), finalErrorMessage, "Error " + (saving ? "saving" : "loading") + " Jalview file", @@ -3589,7 +3589,7 @@ public class Jalview2XML entry.setProperty(prop.getName(), prop.getValue()); } StructureSelectionManager - .getStructureSelectionManager(Desktop.instance) + .getStructureSelectionManager(Desktop.getInstance()) .registerPDBEntry(entry); // adds PDBEntry to datasequence's set (since Jalview 2.10) if (al.getSequenceAt(i).getDatasetSequence() != null) @@ -4307,7 +4307,7 @@ public class Jalview2XML int height = safeInt(structureState.getHeight()); // Probably don't need to do this anymore... - // Desktop.desktop.getComponentAt(x, y); + // Desktop.getDesktopPane().getComponentAt(x, y); // TODO: NOW: check that this recovers the PDB file correctly. String pdbFile = loadPDBFile(jprovider, pdbid.getId(), pdbid.getFile()); @@ -4791,7 +4791,7 @@ public class Jalview2XML { try { - frames = Desktop.desktop.getAllFrames(); + frames = Desktop.getDesktopPane().getAllFrames(); } catch (ArrayIndexOutOfBoundsException e) { // occasional No such child exceptions are thrown here... diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 798b07a..d6eec47 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -22,6 +22,8 @@ package jalview.structure; import jalview.analysis.AlignSeq; import jalview.api.StructureSelectionManagerProvider; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.commands.CommandI; import jalview.commands.EditCommand; import jalview.commands.OrderCommand; @@ -61,12 +63,10 @@ import mc_view.Atom; import mc_view.PDBChain; import mc_view.PDBfile; -public class StructureSelectionManager +public class StructureSelectionManager implements ApplicationSingletonI { public final static String NEWLINE = System.lineSeparator(); - static IdentityHashMap instances; - private List mappings = new ArrayList<>(); private boolean processSecondaryStructure = false; @@ -84,6 +84,77 @@ public class StructureSelectionManager private List sel_listeners = new ArrayList<>(); + /* + * instances of this class scoped by some context class + */ + private IdentityHashMap selectionManagers; + + /** + * Answers an instance of this class for the current application (Java or JS + * 'applet') scope + * + * @return + */ + private static StructureSelectionManager getInstance() + { + return (StructureSelectionManager) ApplicationSingletonProvider + .getInstance(StructureSelectionManager.class); + } + + /** + * Answers an instance of this class for the current application (Java or JS + * 'applet') scope, and scoped to the specified context + * + * @param context + * @return + */ + public static StructureSelectionManager getStructureSelectionManager( + StructureSelectionManagerProvider context) + { + return getInstance().getInstanceForContext(context); + } + + /** + * Answers an instance of this class scoped to the given context. The instance + * is created on the first request for the context, thereafter the same + * instance is returned. Note that the context may be null (this is the case + * when running headless without a Desktop). + * + * @param context + * @return + */ + StructureSelectionManager getInstanceForContext( + StructureSelectionManagerProvider context) + { + StructureSelectionManager instance = selectionManagers.get(context); + if (instance == null) + { + instance = new StructureSelectionManager(); + selectionManagers.put(context, instance); + } + return instance; + } + + /** + * Removes the instance associated with this provider + * + * @param provider + */ + + public static void release(StructureSelectionManagerProvider provider) + { + getInstance().selectionManagers.remove(provider); + } + + /** + * Private constructor as all 'singleton' instances are managed here or by + * ApplicationSingletonProvider + */ + private StructureSelectionManager() + { + selectionManagers = new IdentityHashMap<>(); + } + /** * @return true if will try to use external services for processing secondary * structure @@ -198,49 +269,6 @@ public class StructureSelectionManager || pdbIdFileName.containsKey(idOrFile); } - private static StructureSelectionManager nullProvider = null; - - public static StructureSelectionManager getStructureSelectionManager( - StructureSelectionManagerProvider context) - { - if (context == null) - { - if (nullProvider == null) - { - if (instances != null) - { - throw new Error(MessageManager.getString( - "error.implementation_error_structure_selection_manager_null"), - new NullPointerException(MessageManager - .getString("exception.ssm_context_is_null"))); - } - else - { - nullProvider = new StructureSelectionManager(); - } - return nullProvider; - } - } - if (instances == null) - { - instances = new java.util.IdentityHashMap<>(); - } - StructureSelectionManager instance = instances.get(context); - if (instance == null) - { - if (nullProvider != null) - { - instance = nullProvider; - } - else - { - instance = new StructureSelectionManager(); - } - instances.put(context, instance); - } - return instance; - } - /** * flag controlling whether SeqMappings are relayed from received sequence * mouse over events to other sequences @@ -270,7 +298,7 @@ public class StructureSelectionManager return relaySeqMappings; } - Vector listeners = new Vector(); + Vector listeners = new Vector<>(); /** * register a listener for alignment sequence mouseover events @@ -308,6 +336,8 @@ public class StructureSelectionManager * Import structure data and register a structure mapping for broadcasting * colouring, mouseovers and selection events (convenience wrapper). * + * This is the standard entry point. + * * @param sequence * - one or more sequences to be mapped to pdbFile * @param targetChains @@ -332,8 +362,11 @@ public class StructureSelectionManager * broadcasting colouring, mouseovers and selection events (convenience * wrapper). * + * + * * @param forStructureView - * when true, record the mapping for use in mouseOvers + * when true (testng only), record the mapping for use in mouseOvers + * (testng only) * @param sequence * - one or more sequences to be mapped to pdbFile * @param targetChains @@ -377,7 +410,7 @@ public class StructureSelectionManager * mapping operation * @return null or the structure data parsed as a pdb file */ - synchronized public StructureFile computeMapping( + synchronized private StructureFile computeMapping( boolean forStructureView, SequenceI[] sequenceArray, String[] targetChainIds, String pdbFile, DataSourceType sourceType, IProgressIndicator progress) @@ -651,7 +684,6 @@ public class StructureSelectionManager { ds = ds.getDatasetSequence(); } - ; if (ds.getAnnotation() != null) { for (AlignmentAnnotation ala : ds.getAnnotation()) @@ -1328,41 +1360,10 @@ public class StructureSelectionManager { slis.viewPosition(startRes, endRes, startSeq, endSeq, source); } - ; - } - } - } - - /** - * release all references associated with this manager provider - * - * @param jalviewLite - */ - public static void release(StructureSelectionManagerProvider jalviewLite) - { - // synchronized (instances) - { - if (instances == null) - { - return; - } - StructureSelectionManager mnger = (instances.get(jalviewLite)); - if (mnger != null) - { - instances.remove(jalviewLite); - try - { - /* bsoares 2019-03-20 finalize deprecated, no apparent external - * resources to close - */ - // mnger.finalize(); - } catch (Throwable x) - { - } } } } - + public void registerPDBEntry(PDBEntry pdbentry) { if (pdbentry.getFile() != null diff --git a/src/jalview/util/Platform.java b/src/jalview/util/Platform.java index 99c82a4..d32735b 100644 --- a/src/jalview/util/Platform.java +++ b/src/jalview/util/Platform.java @@ -133,6 +133,7 @@ public class Platform /** * * @return true if we are running in non-interactive no UI mode + * based on System.getProperty("java.awt.headless") */ public static boolean isHeadless() { @@ -847,4 +848,22 @@ public class Platform return f.toString(); } + private static float javaVersion; + + public static float getJavaVersion() + { + if (javaVersion == 0) + { + try + { + return javaVersion = Float.parseFloat( + System.getProperty("java.specification.version")); + } catch (Exception e) + { + javaVersion = 1.8f; + } + } + return javaVersion; + } + } diff --git a/src/jalview/util/ShortcutKeyMaskExWrapper.java b/src/jalview/util/ShortcutKeyMaskExWrapper.java index c83da4e..93ce13e 100644 --- a/src/jalview/util/ShortcutKeyMaskExWrapper.java +++ b/src/jalview/util/ShortcutKeyMaskExWrapper.java @@ -1,49 +1,65 @@ package jalview.util; +import java.awt.Toolkit; import java.awt.event.MouseEvent; +/** + * retrieve KeyEvent masks for Java 8 or Java 11+ + * + * @author hansonr + * + */ public class ShortcutKeyMaskExWrapper { - - private static final Float specversion; - - private static final float modern; - public static final int SHIFT_DOWN_MASK; public static final int ALT_DOWN_MASK; - private static final ShortcutKeyMaskExWrapperI wrapper; + public static final int SHORTCUT_MASK; static { - specversion = Platform.isJS() ? Float.valueOf(8) - : Float.parseFloat( - System.getProperty("java.specification.version")); - modern = 11; - - if (specversion >= modern) + float specversion = Platform.getJavaVersion(); + String method; + // BH technically, these are not masks; they are bits. + if (specversion >= 11) { - wrapper = new jalview.util.ShortcutKeyMaskExWrapper11(); - SHIFT_DOWN_MASK = jalview.util.ShortcutKeyMaskExWrapper11.SHIFT_DOWN_MASK; - ALT_DOWN_MASK = jalview.util.ShortcutKeyMaskExWrapper11.ALT_DOWN_MASK; + SHIFT_DOWN_MASK = 0x040; // KeyEvent.SHIFT_DOWN_MASK; + ALT_DOWN_MASK = 0x200; // KeyEvent.ALT_DOWN_MASK; + method = "getMenuShortcutKeyMaskEx"; } else { - wrapper = new jalview.util.ShortcutKeyMaskExWrapper8(); - SHIFT_DOWN_MASK = jalview.util.ShortcutKeyMaskExWrapper8.SHIFT_DOWN_MASK; - ALT_DOWN_MASK = jalview.util.ShortcutKeyMaskExWrapper8.ALT_DOWN_MASK; + SHIFT_DOWN_MASK = 0x01; // KeyEvent.SHIFT_MASK; + ALT_DOWN_MASK = 0x08; // KeyEvent.ALT_MASK; + method = "getMenuShortcutKeyMask"; } + + int mask = 0; + try + { + // Just use reflection -- doesn't matter what version is running. + Toolkit tk = Toolkit.getDefaultToolkit(); + mask = (int) (tk.getClass().getMethod(method, new Class[0]) + .invoke(tk, new Object[0])); + } catch (Exception e) + { + System.out.println("Shortcut exception: " + e); + } + + SHORTCUT_MASK = mask; } + // BH Q: Why not just use the public static field? public static int getMenuShortcutKeyMaskEx() { - return wrapper.getMenuShortcutKeyMaskEx(); + return SHORTCUT_MASK; } + // BH Q: Why is this here? public static int getModifiersEx(MouseEvent e) { - return wrapper.getModifiersEx(e); + return e.getModifiersEx(); } } diff --git a/src/jalview/util/StringUtils.java b/src/jalview/util/StringUtils.java index 1f114a8..a05dc95 100644 --- a/src/jalview/util/StringUtils.java +++ b/src/jalview/util/StringUtils.java @@ -518,6 +518,34 @@ public class StringUtils * {@code "a=b;c"}. * * @param s + * @return + */ + public static boolean isHexString(String s) + { + int j = s.length(); + if (j == 0) + { + return false; + } + for (int i = 0; i < j; i++) + { + int c = s.charAt(i); + if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') + && !(c >= 'A' && c <= 'F')) + { + return false; + } + } + return true; + } + /** + * Answers the input string with any occurrences of the specified (unencoded) + * characters replaced by their URL decoding. + *

+ * Example: {@code urlDecode("a%3Db%3Bc", "-;=,")} should answer + * {@code "a=b;c"}. + * + * @param s * @param encodable * @return */ @@ -541,31 +569,33 @@ public class StringUtils } /** - * Does a lazy lookup of the url encoding of the given character, saving the - * value for repeat lookups - * - * @param c - * @return - */ - private static String getUrlEncoding(char c) - { - if (c < 0 || c >= urlEncodings.length) - { - return String.valueOf(c); - } + * Does a lazy lookup of the url encoding of the given character, saving the + * value for repeat lookups + * + * @param c + * @return + */ + private static String getUrlEncoding(char c) + { + if (c < 0 || c >= urlEncodings.length) + { + return String.valueOf(c); + } + + String enc = urlEncodings[c]; + if (enc == null) + { + try + { + enc = urlEncodings[c] = URLEncoder.encode(String.valueOf(c), + "UTF-8"); + } catch (UnsupportedEncodingException e) + { + enc = urlEncodings[c] = String.valueOf(c); + } + } + return enc; + } - String enc = urlEncodings[c]; - if (enc == null) - { - try - { - enc = urlEncodings[c] = URLEncoder.encode(String.valueOf(c), - "UTF-8"); - } catch (UnsupportedEncodingException e) - { - enc = urlEncodings[c] = String.valueOf(c); - } - } - return enc; - } + } diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 4f399f0..b1f595f 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -605,10 +605,30 @@ public abstract class AlignmentViewport protected ColumnSelection colSel = new ColumnSelection(); - public boolean autoCalculateConsensus = true; + protected boolean autoCalculateConsensusAndConservation = true; + + public boolean getAutoCalculateConsensusAndConservation() + { // BH 2019.07.24 + return autoCalculateConsensusAndConservation; + } + + public void setAutoCalculateConsensusAndConservation(boolean b) + { + autoCalculateConsensusAndConservation = b; + } protected boolean autoCalculateStrucConsensus = true; + public boolean getAutoCalculateStrucConsensus() + { // BH 2019.07.24 + return autoCalculateStrucConsensus; + } + + public void setAutoCalculateStrucConsensus(boolean b) + { + autoCalculateStrucConsensus = b; + } + protected boolean ignoreGapsInConsensusCalculation = false; protected ResidueShaderI residueShading = new ResidueShader(); @@ -824,7 +844,7 @@ public abstract class AlignmentViewport // see note in mantis : issue number 8585 if (alignment.isNucleotide() || (conservation == null && quality == null) - || !autoCalculateConsensus) + || !autoCalculateConsensusAndConservation) { return; } @@ -842,7 +862,7 @@ public abstract class AlignmentViewport public void updateConsensus(final AlignmentViewPanel ap) { // see note in mantis : issue number 8585 - if (consensus == null || !autoCalculateConsensus) + if (consensus == null || !autoCalculateConsensusAndConservation) { return; } @@ -1195,6 +1215,13 @@ public abstract class AlignmentViewport public void setSequenceSetId(String newid) { + // // BH 2020.04.07 do we need to do this if it is the same? + // // (Jalview project files) + // if (newid.equals(sequenceSetID)) + // { + // return; + // } + if (sequenceSetID != null) { System.err.println( @@ -1859,11 +1886,11 @@ public abstract class AlignmentViewport { alignment.padGaps(); } - if (autoCalculateConsensus) + if (autoCalculateConsensusAndConservation) { updateConsensus(ap); } - if (hconsensus != null && autoCalculateConsensus) + if (hconsensus != null && autoCalculateConsensusAndConservation) { updateConservation(ap); } diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 68345b9..5ca3ac5 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -328,12 +328,14 @@ public abstract class FeatureRendererModel visibleTypes); /* - * include features unless they are hidden (have no colour), based on - * feature group visibility, or a filter or colour threshold + * include features unless their feature group is not displayed, or + * they are hidden (have no colour) based on a filter or colour threshold */ + + // BH! check -- !featureGroupNotShown(sf) is from applet branch. for (SequenceFeature sf : features) { - if (getColour(sf) != null) + if (!featureGroupNotShown(sf) && getColour(sf) != null) { result.add(sf); } @@ -1046,6 +1048,8 @@ public abstract class FeatureRendererModel */ public void filterFeaturesForDisplay(List features) { +// BH! check -- what was the problem here? How is JalviewJS's IntervalStore different from + // other IntervalStore? /* * fudge: JalviewJS's IntervalStore lacks the sort method called :-( */ @@ -1130,7 +1134,7 @@ public abstract class FeatureRendererModel /** * Answers the colour for the feature, or null if the feature is excluded by * feature group visibility, by filters, or by colour threshold settings. This - * method does not take feature type visibility into account. + * method does not take feature visibility into account. * * @param sf * @param fc diff --git a/src/jalview/ws/DBRefFetcher.java b/src/jalview/ws/DBRefFetcher.java index 6b8843d..736d8cb 100644 --- a/src/jalview/ws/DBRefFetcher.java +++ b/src/jalview/ws/DBRefFetcher.java @@ -33,6 +33,7 @@ import jalview.gui.Desktop; import jalview.gui.FeatureSettings; import jalview.gui.IProgressIndicator; import jalview.gui.OOMWarning; +import jalview.gui.Preferences; import jalview.util.DBRefUtils; import jalview.util.MessageManager; import jalview.ws.seqfetcher.DbSourceProxy; @@ -137,7 +138,7 @@ public class DBRefFetcher implements Runnable } this.dataset = ds; // TODO Jalview 2.5 lots of this code should be in the gui package! - sfetcher = jalview.gui.SequenceFetcher.getSequenceFetcherSingleton(); + sfetcher = SequenceFetcher.getInstance(); // set default behaviour for transferring excess sequence data to the // dataset trimDsSeqs = Cache.getDefault(TRIM_RETRIEVED_SEQUENCES, true); @@ -305,7 +306,7 @@ public class DBRefFetcher implements Runnable } try { - if (Cache.getDefault("DBREFFETCH_USEPICR", false)) + if (Cache.getDefault(Preferences.DBREFFETCH_USEPICR, false)) { picrClient = new AccessionMapperServiceLocator() .getAccessionMapperPort(); diff --git a/src/jalview/ws/SequenceFetcher.java b/src/jalview/ws/SequenceFetcher.java index a480176..10a2b28 100644 --- a/src/jalview/ws/SequenceFetcher.java +++ b/src/jalview/ws/SequenceFetcher.java @@ -20,13 +20,10 @@ */ package jalview.ws; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; +import jalview.datamodel.DBRefSource; import jalview.ext.ensembl.EnsemblGene; -import jalview.ws.dbsources.EmblCdsSource; -import jalview.ws.dbsources.EmblSource; -import jalview.ws.dbsources.Pdb; -import jalview.ws.dbsources.PfamFull; -import jalview.ws.dbsources.PfamSeed; -import jalview.ws.dbsources.RfamSeed; import jalview.ws.dbsources.Uniprot; import jalview.ws.seqfetcher.ASequenceFetcher; import jalview.ws.seqfetcher.DbSourceProxy; @@ -36,57 +33,102 @@ import java.util.Collections; import java.util.List; /** - * This implements the run-time discovery of sequence database clients. + * Thread safe construction of database proxies. This implements the run-time + * discovery of sequence database clients. * + * TODO: extend to a configurable database plugin mechanism where classes are + * instantiated by reflection and queried for their DbRefSource and version + * association. */ -public class SequenceFetcher extends ASequenceFetcher +public class SequenceFetcher extends ASequenceFetcher implements ApplicationSingletonI { + /* + * set a mock fetcher here for testing only - reset to null afterwards + */ + private static SequenceFetcher mockFetcher; + + /** + * Returns a new SequenceFetcher singleton, or a mock object if one has been + * set. + * + * @return + */ + public static SequenceFetcher getInstance() + { + return mockFetcher != null ? mockFetcher + : (SequenceFetcher) ApplicationSingletonProvider + .getInstance(SequenceFetcher.class); + } + + /** + * Set the instance object to use (intended for unit testing with mock + * objects). + * + * Be sure to reset to null in the tearDown method of any tests! + * + * @param sf + */ + public static void setSequenceFetcher(SequenceFetcher sf) + { + mockFetcher = sf; + } + /** - * Thread safe construction of database proxies TODO: extend to a configurable - * database plugin mechanism where classes are instantiated by reflection and - * queried for their DbRefSource and version association. + * + * This public constructor is only is for use by testng to anonymously + * subclass SequenceFetcher. + * * */ public SequenceFetcher() { - addDBRefSourceImpl(EnsemblGene.class); - // addDBRefSourceImpl(EnsemblGenomes.class); - addDBRefSourceImpl(EmblSource.class); - addDBRefSourceImpl(EmblCdsSource.class); - addDBRefSourceImpl(Uniprot.class); - addDBRefSourceImpl(Pdb.class); - addDBRefSourceImpl(PfamFull.class); - addDBRefSourceImpl(PfamSeed.class); - addDBRefSourceImpl(RfamSeed.class); + addAllDatabases(); + } + + public void addAllDatabases() + { + addDBRefSourceImpl(EnsemblGene.class); // includes EnsemblGenomes.class + addDBRefSourceImpl(Uniprot.class); // includes UniprotName.class + // addDBRefSourceImpl(EmblSource.class); + // addDBRefSourceImpl(EmblCdsSource.class); + // addDBRefSourceImpl(Pdb.class); + // addDBRefSourceImpl(PfamFull.class); + // addDBRefSourceImpl(PfamSeed.class); + // addDBRefSourceImpl(RfamSeed.class); + addDBRefSourceImpl(DBRefSource.EMBL, + "jalview.ws.dbsources.EmblSource"); + addDBRefSourceImpl(DBRefSource.EMBLCDS, + "jalview.ws.dbsources.EmblCdsSource"); + addDBRefSourceImpl(DBRefSource.PDB, "jalview.ws.dbsources.Pdb"); + addDBRefSourceImpl(DBRefSource.PFAM_FULL, + "jalview.ws.dbsources.PfamFull"); + addDBRefSourceImpl(DBRefSource.PFAM_SEED, + "jalview.ws.dbsources.PfamSeed"); + addDBRefSourceImpl(DBRefSource.RFAM_SEED, + "jalview.ws.dbsources.RfamSeed"); } /** - * return an ordered list of database sources excluding alignment only databases + * return an ordered list of database sources excluding alignment only + * databases */ public String[] getNonAlignmentSources() { String[] srcs = this.getSupportedDb(); List src = new ArrayList<>(); - - for (int i = 0; i < srcs.length; i++) + outer: for (int i = 0; i < srcs.length; i++) { - boolean accept = true; for (DbSourceProxy dbs : getSourceProxy(srcs[i])) { // Skip the alignment databases for the moment - they're not useful for // verifying a single sequence against its reference source if (dbs.isAlignmentSource()) { - accept = false; - break; + continue outer; } } - if (accept) - { - src.add(srcs[i]); - } + src.add(srcs[i]); } - Collections.sort(src, String.CASE_INSENSITIVE_ORDER); return src.toArray(new String[src.size()]); } diff --git a/src/jalview/ws/SequenceFetcherFactory.java b/src/jalview/ws/SequenceFetcherFactory.java index 9cc4960..7aad74a 100644 --- a/src/jalview/ws/SequenceFetcherFactory.java +++ b/src/jalview/ws/SequenceFetcherFactory.java @@ -20,33 +20,7 @@ */ package jalview.ws; -import jalview.ws.seqfetcher.ASequenceFetcher; - public class SequenceFetcherFactory { - - private static SequenceFetcher instance; - - /** - * Returns a new SequenceFetcher object, or a mock object if one has been set - * - * @return - */ - public static ASequenceFetcher getSequenceFetcher() - { - return instance == null ? new SequenceFetcher() : instance; - } - - /** - * Set the instance object to use (intended for unit testing with mock - * objects). - * - * Be sure to reset to null in the tearDown method of any tests! - * - * @param sf - */ - public static void setSequenceFetcher(SequenceFetcher sf) - { - instance = sf; - } + // BH the two methods in this class merged into SequenceFetcher } diff --git a/src/jalview/ws/jws1/Discoverer.java b/src/jalview/ws/jws1/Discoverer.java index bee9fad..943305e 100644 --- a/src/jalview/ws/jws1/Discoverer.java +++ b/src/jalview/ws/jws1/Discoverer.java @@ -20,6 +20,8 @@ */ package jalview.ws.jws1; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.gui.JvOptionPane; import jalview.util.MessageManager; @@ -34,9 +36,36 @@ import ext.vamsas.RegistryServiceSoapBindingStub; import ext.vamsas.ServiceHandle; import ext.vamsas.ServiceHandles; -public class Discoverer implements Runnable +public class Discoverer implements Runnable, ApplicationSingletonI { - ext.vamsas.IRegistry registry; // the root registry service. + + public static Discoverer getInstance() + { + return (Discoverer) ApplicationSingletonProvider.getInstance(Discoverer.class); + } + + private Discoverer() + { + // use getInstance() + } + + private java.net.URL RootServiceURL = null; + + private Vector ServiceURLList = null; + + private boolean reallyDiscoverServices = true; + + private Hashtable> services = null; + + public Hashtable> getServices() + { + return services; + } + + private Vector serviceList = null; + + // private ext.vamsas.IRegistry registry; // the root registry service. + private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport( this); @@ -110,19 +139,6 @@ public class Discoverer implements Runnable return server; } - static private java.net.URL RootServiceURL = null; - - static public Vector ServiceURLList = null; - - static private boolean reallyDiscoverServices = true; - - public static java.util.Hashtable> services = null; - // stored by - // abstractServiceType - // string - - public static java.util.Vector serviceList = null; - static private Vector getDiscoveryURLS() { Vector urls = new Vector<>(); @@ -178,55 +194,64 @@ public class Discoverer implements Runnable { jalview.bin.Cache.log .debug("(Re)-Initialising the discovery URL list."); + Discoverer d = getInstance(); try { - reallyDiscoverServices = jalview.bin.Cache + d.reallyDiscoverServices = jalview.bin.Cache .getDefault("DISCOVERY_START", false); - if (reallyDiscoverServices) + if (d.reallyDiscoverServices) { - ServiceURLList = getDiscoveryURLS(); + d.ServiceURLList = getDiscoveryURLS(); } else { jalview.bin.Cache.log.debug("Setting default services"); - services = new Hashtable<>(); + d.services = new Hashtable<>(); // Muscle, Clustal and JPred. - ServiceHandle[] defServices = { new ServiceHandle("MsaWS", - "Edgar, Robert C. (2004), MUSCLE: multiple sequence alignment " - + "with high accuracy and high throughput, Nucleic Acids Research 32(5), 1792-97.", - "http://www.compbio.dundee.ac.uk/JalviewWS/services/MuscleWS", - MessageManager.getString( - "label.muscle_multiple_protein_sequence_alignment")), - new ServiceHandle("MsaWS", - "Katoh, K., K. Kuma, K., Toh, H., and Miyata, T. (2005) " - + "\"MAFFT version 5: improvement in accuracy of multiple sequence alignment.\"" - + " Nucleic Acids Research, 33 511-518", - "http://www.compbio.dundee.ac.uk/JalviewWS/services/MafftWS", - MessageManager.getString( - "label.mafft_multiple_sequence_alignment")), - new ServiceHandle("MsaWS", - "Thompson, J.D., Higgins, D.G. and Gibson, T.J. (1994) CLUSTAL W: improving the sensitivity of progressive multiple" - + " sequence alignment through sequence weighting, position specific gap penalties and weight matrix choice." - + " Nucleic Acids Research, 22 4673-4680", - "http://www.compbio.dundee.ac.uk/JalviewWS/services/ClustalWS", - MessageManager.getString( - "label.clustalw_multiple_sequence_alignment")), - new ServiceHandle("SecStrPred", - "Drozdetskiy A, Cole C, Procter J & Barton GJ. (2015)\nJPred4: a protein secondary structure prediction server" - + "\nNucleic Acids Research, Web Server issue (first published 15th April 2015)" - + "\ndoi://10.1093/nar/gkv332", - "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred", - "JPred Secondary Structure Prediction") }; - services = new Hashtable<>(); - serviceList = new Vector<>(); - buildServiceLists(defServices, serviceList, services); + ServiceHandle[] defServices = new ServiceHandle[0]; + try + { + // BH 2020.03.18 issue with applet branch Module problem. + defServices = new ServiceHandle[] { new ServiceHandle("MsaWS", + "Edgar, Robert C. (2004), MUSCLE: multiple sequence alignment " + + "with high accuracy and high throughput, Nucleic Acids Research 32(5), 1792-97.", + "http://www.compbio.dundee.ac.uk/JalviewWS/services/MuscleWS", + MessageManager.getString( + "label.muscle_multiple_protein_sequence_alignment")), + new ServiceHandle("MsaWS", + "Katoh, K., K. Kuma, K., Toh, H., and Miyata, T. (2005) " + + "\"MAFFT version 5: improvement in accuracy of multiple sequence alignment.\"" + + " Nucleic Acids Research, 33 511-518", + "http://www.compbio.dundee.ac.uk/JalviewWS/services/MafftWS", + MessageManager.getString( + "label.mafft_multiple_sequence_alignment")), + new ServiceHandle("MsaWS", + "Thompson, J.D., Higgins, D.G. and Gibson, T.J. (1994) CLUSTAL W: improving the sensitivity of progressive multiple" + + " sequence alignment through sequence weighting, position specific gap penalties and weight matrix choice." + + " Nucleic Acids Research, 22 4673-4680", + "http://www.compbio.dundee.ac.uk/JalviewWS/services/ClustalWS", + MessageManager.getString( + "label.clustalw_multiple_sequence_alignment")), + new ServiceHandle("SecStrPred", + "Drozdetskiy A, Cole C, Procter J & Barton GJ. (2015)\nJPred4: a protein secondary structure prediction server" + + "\nNucleic Acids Research, Web Server issue (first published 15th April 2015)" + + "\ndoi://10.1093/nar/gkv332", + "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred", + "JPred Secondary Structure Prediction") }; + } catch (Throwable e) + { + + } + d.services = new Hashtable<>(); + d.serviceList = new Vector<>(); + buildServiceLists(defServices, d.serviceList, d.services); } } catch (Exception e) { System.err.println( "jalview.rootRegistry is not a proper url!\nWas set to " - + RootServiceURL + "\n" + e); + + d.RootServiceURL + "\n" + e); } } @@ -246,9 +271,9 @@ public class Discoverer implements Runnable // JBPNote - should do this a better way! if (f.getFaultReason().indexOf("(407)") > -1) { - if (jalview.gui.Desktop.desktop != null) + if (jalview.gui.Desktop.getDesktopPane() != null) { - JvOptionPane.showMessageDialog(jalview.gui.Desktop.desktop, + JvOptionPane.showMessageDialog(jalview.gui.Desktop.getDesktopPane(), MessageManager.getString("label.set_proxy_settings"), MessageManager .getString("label.proxy_authorization_failed"), @@ -307,17 +332,18 @@ public class Discoverer implements Runnable cat.add(sh[i]); if (sh[i].getAbstractName().equals("Registry")) { - for (int s = 0, sUrls = ServiceURLList.size(); s < sUrls; s++) + Vector list = getInstance().ServiceURLList; + for (int s = 0, sUrls = list.size(); s < sUrls; s++) { java.net.URL disc_serv = null; try { disc_serv = new java.net.URL(sh[i].getEndpointURL()); - if (!ServiceURLList.contains(disc_serv)) + if (!list.contains(disc_serv)) { jalview.bin.Cache.log.debug( "Adding new discovery service at " + disc_serv); - ServiceURLList.add(disc_serv); + list.add(disc_serv); seenNewDiscovery = true; } } catch (Exception e) diff --git a/src/jalview/ws/jws1/JPredClient.java b/src/jalview/ws/jws1/JPredClient.java index 3b7bdb6..3dd8104 100644 --- a/src/jalview/ws/jws1/JPredClient.java +++ b/src/jalview/ws/jws1/JPredClient.java @@ -323,7 +323,7 @@ public class JPredClient extends WS1Client } catch (Exception ex) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.secondary_structure_prediction_service_couldnt_be_located", new String[] diff --git a/src/jalview/ws/jws1/MsaWSClient.java b/src/jalview/ws/jws1/MsaWSClient.java index 4a09625..e97d309 100644 --- a/src/jalview/ws/jws1/MsaWSClient.java +++ b/src/jalview/ws/jws1/MsaWSClient.java @@ -78,7 +78,7 @@ public class MsaWSClient extends WS1Client alignFrame = _alignFrame; if (!sh.getAbstractName().equals("MsaWS")) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.service_called_is_not_msa_service", new String[] @@ -91,7 +91,7 @@ public class MsaWSClient extends WS1Client if ((wsInfo = setWebService(sh)) == null) { - JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager .formatMessage("label.msa_service_is_unknown", new String[] { sh.getName() }), MessageManager.getString("label.internal_jalview_error"), diff --git a/src/jalview/ws/jws1/SeqSearchWSClient.java b/src/jalview/ws/jws1/SeqSearchWSClient.java index 53338d3..cb965f0 100644 --- a/src/jalview/ws/jws1/SeqSearchWSClient.java +++ b/src/jalview/ws/jws1/SeqSearchWSClient.java @@ -84,7 +84,7 @@ public class SeqSearchWSClient extends WS1Client // name to service client name if (!sh.getAbstractName().equals(this.getServiceActionKey())) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.service_called_is_not_seq_search_service", new String[] @@ -97,7 +97,7 @@ public class SeqSearchWSClient extends WS1Client if ((wsInfo = setWebService(sh)) == null) { - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.seq_search_service_is_unknown", new String[] { sh.getName() }), diff --git a/src/jalview/ws/jws2/Jws2Client.java b/src/jalview/ws/jws2/Jws2Client.java index 0f1a25e..62f2a03 100644 --- a/src/jalview/ws/jws2/Jws2Client.java +++ b/src/jalview/ws/jws2/Jws2Client.java @@ -398,7 +398,7 @@ public abstract class Jws2Client extends jalview.ws.WSClient { // check service is actually in the list of currently avaialable // services - if (!Jws2Discoverer.getDiscoverer().getServices().contains(service)) + if (!Jws2Discoverer.getInstance().getServices().contains(service)) { // it isn't .. service = null; @@ -408,7 +408,7 @@ public abstract class Jws2Client extends jalview.ws.WSClient if (service == null) { // get the default service for AACon - service = Jws2Discoverer.getDiscoverer().getPreferredServiceFor(null, + service = Jws2Discoverer.getInstance().getPreferredServiceFor(null, aaui.getServiceType()); } if (service == null) diff --git a/src/jalview/ws/jws2/Jws2Discoverer.java b/src/jalview/ws/jws2/Jws2Discoverer.java index 516a719..bd4d352 100644 --- a/src/jalview/ws/jws2/Jws2Discoverer.java +++ b/src/jalview/ws/jws2/Jws2Discoverer.java @@ -21,6 +21,8 @@ package jalview.ws.jws2; import jalview.bin.Cache; +import jalview.bin.ApplicationSingletonProvider; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; import jalview.gui.AlignFrame; import jalview.gui.Desktop; import jalview.gui.JvSwingUtils; @@ -60,8 +62,29 @@ import compbio.ws.client.Services; * @author JimP * */ -public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI +public class Jws2Discoverer + implements Runnable, WSMenuEntryProviderI, ApplicationSingletonI { + + /** + * Returns the singleton instance of this class. + * + * @return + */ + public static Jws2Discoverer getInstance() + { + return (Jws2Discoverer) ApplicationSingletonProvider + .getInstance(Jws2Discoverer.class); + } + + /** + * Private constructor enforces use of singleton via getDiscoverer() + */ + private Jws2Discoverer() + { + // use getInstance(); + } + public static final String COMPBIO_JABAWS = "http://www.compbio.dundee.ac.uk/jabaws"; /* @@ -70,11 +93,6 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI private final static String JWS2HOSTURLS = "JWS2HOSTURLS"; /* - * Singleton instance - */ - private static Jws2Discoverer discoverer; - - /* * Override for testing only */ private static List testUrls = null; @@ -82,7 +100,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI // preferred url has precedence over others private String preferredUrl; - private PropertyChangeSupport changeSupport = new PropertyChangeSupport( + protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( this); private Vector invalidServiceUrls = null; @@ -103,13 +121,6 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI protected Vector services; /** - * Private constructor enforces use of singleton via getDiscoverer() - */ - private Jws2Discoverer() - { - } - - /** * change listeners are notified of "services" property changes * * @param listener @@ -190,7 +201,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI oldthread = Thread.currentThread(); try { - Class foo = getClass().getClassLoader() + getClass().getClassLoader() .loadClass("compbio.ws.client.Jws2Client"); } catch (ClassNotFoundException e) { @@ -591,19 +602,19 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI testUrls.add(url); } } - Thread runner = getDiscoverer() + Thread runner = getInstance() .startDiscoverer(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - if (getDiscoverer().services != null) + if (getInstance().services != null) { System.out.println("Changesupport: There are now " - + getDiscoverer().services.size() + " services"); + + getInstance().services.size() + " services"); int i = 1; - for (Jws2Instance instance : getDiscoverer().services) + for (Jws2Instance instance : getInstance().services) { System.out.println("Service " + i++ + " " + instance.getClass() + "@" + instance.getHost() @@ -630,20 +641,6 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI } } - /** - * Returns the singleton instance of this class. - * - * @return - */ - public static Jws2Discoverer getDiscoverer() - { - if (discoverer == null) - { - discoverer = new Jws2Discoverer(); - } - return discoverer; - } - public boolean hasServices() { return !running && services != null && services.size() > 0; diff --git a/src/jalview/ws/jws2/MsaWSClient.java b/src/jalview/ws/jws2/MsaWSClient.java index 23c6949..319252a 100644 --- a/src/jalview/ws/jws2/MsaWSClient.java +++ b/src/jalview/ws/jws2/MsaWSClient.java @@ -107,7 +107,7 @@ public class MsaWSClient extends Jws2Client if (!(sh.service instanceof MsaWS)) { // redundant at mo - but may change - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager.formatMessage( "label.service_called_is_not_msa_service", new String[] @@ -120,7 +120,7 @@ public class MsaWSClient extends Jws2Client server = (MsaWS) sh.service; if ((wsInfo = setWebService(sh, false)) == null) { - JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager .formatMessage("label.msa_service_is_unknown", new String[] { sh.serviceType }), MessageManager.getString("label.internal_jalview_error"), diff --git a/src/jalview/ws/jws2/SequenceAnnotationWSClient.java b/src/jalview/ws/jws2/SequenceAnnotationWSClient.java index 45bddac..e8116a1 100644 --- a/src/jalview/ws/jws2/SequenceAnnotationWSClient.java +++ b/src/jalview/ws/jws2/SequenceAnnotationWSClient.java @@ -67,7 +67,7 @@ public class SequenceAnnotationWSClient extends Jws2Client // dan changed! dan test. comment out if conditional // if (alignFrame.getViewport().getAlignment().isNucleotide()) // { - // JvOptionPane.showMessageDialog(Desktop.desktop, sh.serviceType + // JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), sh.serviceType // + " can only be used\nfor amino acid alignments.", // "Wrong type of sequences!", JvOptionPane.WARNING_MESSAGE); // return; @@ -242,7 +242,7 @@ public class SequenceAnnotationWSClient extends Jws2Client @Override public void actionPerformed(ActionEvent arg0) { - Desktop.instance.showUrl(service.docUrl); + Desktop.getInstance().showUrl(service.docUrl); } }); annotservice.setToolTipText( diff --git a/src/jalview/ws/jws2/jabaws2/Jws2Instance.java b/src/jalview/ws/jws2/jabaws2/Jws2Instance.java index e092192..7954db0 100644 --- a/src/jalview/ws/jws2/jabaws2/Jws2Instance.java +++ b/src/jalview/ws/jws2/jabaws2/Jws2Instance.java @@ -186,7 +186,7 @@ public class Jws2Instance implements AutoCloseable try { paramStore = new JabaParamStore(this, - (Desktop.instance != null ? Desktop.getUserParameterStore() + (Desktop.getInstance() != null ? Desktop.getUserParameterStore() : null)); } catch (Exception ex) { diff --git a/src/jalview/ws/rest/RestClient.java b/src/jalview/ws/rest/RestClient.java index a71b70d..08f137d 100644 --- a/src/jalview/ws/rest/RestClient.java +++ b/src/jalview/ws/rest/RestClient.java @@ -329,7 +329,7 @@ public class RestClient extends WSClient else { // TODO: try to tell the user why the job couldn't be started. - JvOptionPane.showMessageDialog(Desktop.desktop, + JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), (jobsthread.hasWarnings() ? jobsthread.getWarnings() : MessageManager.getString( "label.job_couldnt_be_started_check_input")), diff --git a/src/jalview/ws/seqfetcher/ASequenceFetcher.java b/src/jalview/ws/seqfetcher/ASequenceFetcher.java index 2a27cce..97babfd 100644 --- a/src/jalview/ws/seqfetcher/ASequenceFetcher.java +++ b/src/jalview/ws/seqfetcher/ASequenceFetcher.java @@ -36,6 +36,7 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Stack; import java.util.Vector; @@ -45,7 +46,7 @@ public class ASequenceFetcher /* * set of databases we can retrieve entries from */ - protected Hashtable> fetchableDbs; + protected Hashtable> fetchableDbs; /* * comparator to sort by tier (0/1/2) and name @@ -57,8 +58,6 @@ public class ASequenceFetcher */ protected ASequenceFetcher() { - super(); - /* * comparator to sort proxies by tier and name */ @@ -305,7 +304,7 @@ public class ASequenceFetcher public List getSourceProxy(String db) { db = DBRefUtils.getCanonicalName(db); - Map dblist = fetchableDbs.get(db); + Map dblist = fetchableDbs.get(db); if (dblist == null) { return new ArrayList<>(); @@ -314,27 +313,74 @@ public class ASequenceFetcher /* * sort so that primary sources precede secondary */ - List dbs = new ArrayList<>(dblist.values()); + List dbs = new ArrayList<>(); + for (Entry entry : dblist.entrySet()) + { + DbSourceProxyRoot proxy = entry.getValue(); + if (proxy instanceof DbRoot) + { + proxy = setProxy((DbRoot) proxy, dblist); + } + dbs.add((DbSourceProxy) proxy); + } Collections.sort(dbs, proxyComparator); return dbs; } + class DbRoot implements DbSourceProxyRoot + { + + private String sourceName; + + private String className; + + DbRoot(String sourceName, String className) + { + this.sourceName = sourceName; + this.className = className; + } + + @Override + public String getDbSource() + { + return sourceName; + } + + /** + * lazy class creation + * + * @return the actual proxy object + */ + public DbSourceProxy getProxy() + { + try + { + return (DbSourceProxy) Class.forName(className).newInstance(); + } catch (Exception e) + { + // Serious problems if this happens. + throw new Error(MessageManager.getString( + "error.dbrefsource_implementation_exception"), e); + } + } + + } + /** * constructs an instance of the proxy and registers it as a valid dbrefsource * - * @param dbSourceProxy + * @param dbSourceProxyClass * reference for class implementing * jalview.ws.seqfetcher.DbSourceProxy */ protected void addDBRefSourceImpl( - Class dbSourceProxy) + Class dbSourceProxyClass) throws IllegalArgumentException { DbSourceProxy proxy = null; try { - DbSourceProxy proxyObj = dbSourceProxy.getConstructor().newInstance(); - proxy = proxyObj; + proxy = dbSourceProxyClass.getConstructor().newInstance(); } catch (IllegalArgumentException e) { throw e; @@ -347,13 +393,18 @@ public class ASequenceFetcher addDbRefSourceImpl(proxy); } + public void addDBRefSourceImpl(String sourceName, String className) + { + addDbRefSourceImpl(new DbRoot(sourceName, className)); + } + /** * add the properly initialised DbSourceProxy object 'proxy' to the list of * sequence fetchers * * @param proxy */ - protected void addDbRefSourceImpl(DbSourceProxy proxy) + void addDbRefSourceImpl(DbSourceProxyRoot proxy) { if (proxy != null) { @@ -361,25 +412,31 @@ public class ASequenceFetcher { fetchableDbs = new Hashtable<>(); } - Map slist = fetchableDbs - .get(proxy.getDbSource()); + String key = proxy.getDbSource(); + Map slist = fetchableDbs.get(key); if (slist == null) { - fetchableDbs.put(proxy.getDbSource(), - slist = new Hashtable<>()); + fetchableDbs.put(key, slist = new Hashtable<>()); + } + if (proxy instanceof DbRoot) + { + slist.put("", proxy); + } + else + { + slist.put(((DbSourceProxy) proxy).getDbName(), proxy); } - slist.put(proxy.getDbName(), proxy); } } /** * select sources which are implemented by instances of the given class * - * @param class + * @param class1 * that implements DbSourceProxy * @return null or vector of source names for fetchers */ - public String[] getDbInstances(Class class1) + public String[] getDbInstances(Class class1) { if (!DbSourceProxy.class.isAssignableFrom(class1)) { @@ -392,20 +449,25 @@ public class ASequenceFetcher { return null; } - String[] sources = null; Vector src = new Vector<>(); - Enumeration dbs = fetchableDbs.keys(); - while (dbs.hasMoreElements()) + for (String dbSource : fetchableDbs.keySet()) { - String dbn = dbs.nextElement(); - for (DbSourceProxy dbp : fetchableDbs.get(dbn).values()) + Map dblist = fetchableDbs.get(dbSource); + for (Entry entry : dblist.entrySet()) { - if (class1.isAssignableFrom(dbp.getClass())) + DbSourceProxyRoot proxy = entry.getValue(); + if (proxy instanceof DbRoot) { - src.addElement(dbn); + proxy = setProxy((DbRoot) proxy, dblist); + } + Class c = proxy.getClass(); + if (class1 == c || class1.isAssignableFrom(c)) + { + src.addElement(dbSource); } } } + String[] sources = null; if (src.size() > 0) { src.copyInto(sources = new String[src.size()]); @@ -413,10 +475,24 @@ public class ASequenceFetcher return sources; } - public DbSourceProxy[] getDbSourceProxyInstances(Class class1) + private DbSourceProxyRoot setProxy(DbRoot root, + Map dblist) + { + DbSourceProxy proxy = root.getProxy(); + // Time to create the actual proxy + dblist.remove(""); + dblist.put(proxy.getDbName(), proxy); + return proxy; + } + + public DbSourceProxy[] getDbSourceProxyInstances(Class class1) { + if (fetchableDbs == null) + { + return null; + } List prlist = new ArrayList<>(); - for (String fetchable : getSupportedDb()) + for (String fetchable : fetchableDbs.keySet()) { for (DbSourceProxy pr : getSourceProxy(fetchable)) { diff --git a/src/jalview/ws/seqfetcher/DbSourceProxyRoot.java b/src/jalview/ws/seqfetcher/DbSourceProxyRoot.java new file mode 100644 index 0000000..7b0c2a7 --- /dev/null +++ b/src/jalview/ws/seqfetcher/DbSourceProxyRoot.java @@ -0,0 +1,11 @@ +package jalview.ws.seqfetcher; + +public interface DbSourceProxyRoot +{ + /** + * + * @return source string constant used for this DB source + */ + String getDbSource(); + +} diff --git a/test/jalview/analysis/FinderTest.java b/test/jalview/analysis/FinderTest.java index 5f64b28..bd18abd 100644 --- a/test/jalview/analysis/FinderTest.java +++ b/test/jalview/analysis/FinderTest.java @@ -68,7 +68,7 @@ public class FinderTest public void setUp() { Cache.loadProperties("test/jalview/io/testProps.jvprops"); - Cache.applicationProperties.setProperty("PAD_GAPS", + Cache.setPropertyNoSave("PAD_GAPS", Boolean.FALSE.toString()); String seqData = "seq1seq1/8-18 ABCD--EF-GHIJI\n" + "seq2 A--BCDefHI\n" diff --git a/test/jalview/ext/jmol/JmolParserTest.java b/test/jalview/ext/jmol/JmolParserTest.java index 2832135..0977669 100644 --- a/test/jalview/ext/jmol/JmolParserTest.java +++ b/test/jalview/ext/jmol/JmolParserTest.java @@ -98,11 +98,11 @@ public class JmolParserTest public void setUp() { Cache.loadProperties("test/jalview/io/testProps.jvprops"); - Cache.applicationProperties.setProperty("STRUCT_FROM_PDB", + Cache.setPropertyNoSave("STRUCT_FROM_PDB", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("ADD_TEMPFACT_ANN", + Cache.setPropertyNoSave("ADD_TEMPFACT_ANN", Boolean.FALSE.toString()); - Cache.applicationProperties.setProperty("ADD_SS_ANN", + Cache.setPropertyNoSave("ADD_SS_ANN", Boolean.TRUE.toString()); StructureImportSettings.setDefaultStructureFileFormat("PDB"); StructureImportSettings diff --git a/test/jalview/ext/jmol/JmolViewerTest.java b/test/jalview/ext/jmol/JmolViewerTest.java index e451ed2..7ef0d16 100644 --- a/test/jalview/ext/jmol/JmolViewerTest.java +++ b/test/jalview/ext/jmol/JmolViewerTest.java @@ -74,7 +74,7 @@ public class JmolViewerTest @AfterClass(alwaysRun = true) public static void tearDownAfterClass() throws Exception { - jalview.gui.Desktop.instance.closeAll_actionPerformed(null); + jalview.gui.Desktop.getInstance().closeAll_actionPerformed(null); } @Test(groups = { "Functional" }) diff --git a/test/jalview/ext/rbvi/chimera/FeatureRenderer.java b/test/jalview/ext/rbvi/chimera/FeatureRenderer.java new file mode 100644 index 0000000..8aa2858 --- /dev/null +++ b/test/jalview/ext/rbvi/chimera/FeatureRenderer.java @@ -0,0 +1,300 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.api; + +import jalview.datamodel.MappedFeatures; +import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceI; +import jalview.datamodel.features.FeatureMatcherSetI; + +import java.awt.Color; +import java.awt.Graphics; +import java.util.List; +import java.util.Map; + +/** + * Abstract feature renderer interface + * + * @author JimP + * + */ +public interface FeatureRenderer +{ + + /** + * Computes the feature colour for a given sequence and column position, + * taking into account sequence feature locations, feature colour schemes, + * render ordering, feature and feature group visibility, and transparency. + *

+ * The graphics argument should be provided if transparency is applied + * (getTransparency() < 1). With feature transparency, visible features are + * written to the graphics context and the composite colour may be read off + * from it. In this case, the returned feature colour is not the composite + * colour but that of the last feature drawn. + *

+ * If no transparency applies, then the graphics argument may be null, and the + * returned colour is the one that would be drawn for the feature. + *

+ * Returns null if there is no visible feature at the position. + *

+ * This is provided to support rendering of feature colours other than on the + * sequence alignment, including by structure viewers and the overview window. + * Note this method takes no account of whether the sequence or column is + * hidden. + * + * @param sequence + * @param column + * aligned column position (1..) + * @param g + * @return + */ + Color findFeatureColour(SequenceI sequence, int column, Graphics g); + + /** + * trigger the feature discovery process for a newly created feature renderer. + */ + void featuresAdded(); + + /** + * + * @param ft + * @return display style for a feature + */ + FeatureColourI getFeatureStyle(String ft); + + /** + * update the feature style for a particular feature + * + * @param ft + * @param ggc + */ + void setColour(String ft, FeatureColourI ggc); + + AlignViewportI getViewport(); + + /** + * + * @return container managing list of feature types and their visibility + */ + FeaturesDisplayedI getFeaturesDisplayed(); + + /** + * get display style for all features types - visible or invisible + * + * @return + */ + Map getFeatureColours(); + + /** + * query the alignment view to find all features + * + * @param newMadeVisible + * - when true, automatically make newly discovered types visible + */ + void findAllFeatures(boolean newMadeVisible); + + /** + * get display style for all features types currently visible + * + * @return + */ + Map getDisplayedFeatureCols(); + + /** + * get all registered groups + * + * @return + */ + List getFeatureGroups(); + + /** + * get groups that are visible/invisible + * + * @param visible + * @return + */ + List getGroups(boolean visible); + + /** + * Set visibility for a list of groups + * + * @param toset + * @param visible + */ + void setGroupVisibility(List toset, boolean visible); + + /** + * Set visibility of the given feature group + * + * @param group + * @param visible + */ + void setGroupVisibility(String group, boolean visible); + + /** + * Returns visible features at the specified aligned column on the given + * sequence. Non-positional features are not included. If the column has a gap, + * then enclosing features are included (but not contact features). + * + * @param sequence + * @param column + * aligned column position (1..) + * @return + */ + List findFeaturesAtColumn(SequenceI sequence, int column); + + /** + * Returns features at the specified residue positions on the given sequence. + * Non-positional features are not included. Features are returned in render + * order of their feature type (last is on top). Within feature type, ordering + * is undefined. + * + * @param sequence + * @param fromResNo + * @param toResNo + * @return + */ + List findFeaturesAtResidue(SequenceI sequence, + int fromResNo, int toResNo); + + /** + * get current displayed types, in ordering of rendering (on top last) + * + * @return a (possibly empty) list of feature types + */ + + List getDisplayedFeatureTypes(); + + /** + * Returns a (possibly empty) list of currently visible feature groups + * + * @return + */ + List getDisplayedFeatureGroups(); + + /** + * display all features of these types + * + * @param featureTypes + */ + void setAllVisible(List featureTypes); + + /** + * display featureType + * + * @param featureType + */ + void setVisible(String featureType); + + /** + * Sets the transparency value, between 0 (full transparency) and 1 (no + * transparency) + * + * @param value + */ + void setTransparency(float value); + + /** + * Returns the transparency value, between 0 (full transparency) and 1 (no + * transparency) + * + * @return + */ + float getTransparency(); + + /** + * Answers the filters applied to the given feature type, or null if none is + * set + * + * @param featureType + * @return + */ + FeatureMatcherSetI getFeatureFilter(String featureType); + + /** + * Answers the feature filters map + * + * @return + */ + public Map getFeatureFilters(); + + /** + * Sets the filters for the feature type, or removes them if a null or empty + * filter is passed + * + * @param featureType + * @param filter + */ + void setFeatureFilter(String featureType, FeatureMatcherSetI filter); + + /** + * Replaces all feature filters with the given map + * + * @param filters + */ + void setFeatureFilters(Map filters); + + /** + * Returns the colour for a particular feature instance. This includes + * calculation of 'colour by label', or of a graduated score colour, if + * applicable. + *

+ * Returns null if + *

    + *
  • feature group is not visible, or
  • + *
  • feature values lie outside any colour threshold, or
  • + *
  • feature is excluded by filter conditions
  • + *
+ * This method does not check feature type visibility. + * + * @param feature + * @return + */ + Color getColour(SequenceFeature feature); + + /** + * Answers true if feature would be shown, else false. A feature is shown if + *
    + *
  • its feature type is set to visible
  • + *
  • its feature group is either null, or set to visible
  • + *
  • it is not excluded by a colour threshold on score or other numeric + * attribute
  • + *
  • it is not excluded by a filter condition
  • + *
+ * + * @param feature + * @return + */ + boolean isVisible(SequenceFeature feature); + + /** + * Answers a bean containing a mapping, and a list of visible features in this + * alignment at a position (or range) which is mappable from the given sequence + * residue position in a mapped alignment. Features are returned in render order + * of feature type (on top last), with order within feature type undefined. If + * no features or mapping are found, answers null. + * + * @param sequence + * @param pos + * @return + */ + MappedFeatures findComplementFeaturesAtResidue(SequenceI sequence, int pos); +} diff --git a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java index 734f7eb..194d34a 100644 --- a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java +++ b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java @@ -95,7 +95,7 @@ public class JalviewChimeraView @AfterClass(alwaysRun = true) public static void tearDownAfterClass() throws Exception { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); } @AfterMethod(alwaysRun = true) diff --git a/test/jalview/gui/AlignFrameTest.java b/test/jalview/gui/AlignFrameTest.java index d2284f1..5778997 100644 --- a/test/jalview/gui/AlignFrameTest.java +++ b/test/jalview/gui/AlignFrameTest.java @@ -75,7 +75,7 @@ public class AlignFrameTest @AfterMethod(alwaysRun = true) public void tearDown() { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); } /** @@ -86,7 +86,7 @@ public class AlignFrameTest public void setUp() { Cache.loadProperties("test/jalview/io/testProps.jvprops"); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", + Cache.setPropertyNoSave("SHOW_IDENTITY", Boolean.TRUE.toString()); af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa", DataSourceType.FILE); diff --git a/test/jalview/gui/AlignViewportTest.java b/test/jalview/gui/AlignViewportTest.java index 4e15dba..be88166 100644 --- a/test/jalview/gui/AlignViewportTest.java +++ b/test/jalview/gui/AlignViewportTest.java @@ -280,15 +280,15 @@ public class AlignViewportTest @Test(groups = { "Functional" }, timeOut=2000) public void testUpdateConservation_qualityOnly() { - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", + Cache.setPropertyNoSave("SHOW_ANNOTATIONS", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("SHOW_QUALITY", + Cache.setPropertyNoSave("SHOW_QUALITY", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("SHOW_CONSERVATION", + Cache.setPropertyNoSave("SHOW_CONSERVATION", Boolean.FALSE.toString()); - Cache.applicationProperties.setProperty("SHOW_OCCUPANCY", + Cache.setPropertyNoSave("SHOW_OCCUPANCY", Boolean.FALSE.toString()); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", + Cache.setPropertyNoSave("SHOW_IDENTITY", Boolean.FALSE.toString()); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); @@ -327,8 +327,8 @@ public class AlignViewportTest /* * test for JAL-2283: don't inadvertently turn on colour by conservation */ - Cache.applicationProperties.setProperty("DEFAULT_COLOUR_PROT", "None"); - Cache.applicationProperties.setProperty("SHOW_CONSERVATION", + Cache.setPropertyNoSave("DEFAULT_COLOUR_PROT", "None"); + Cache.setPropertyNoSave("SHOW_CONSERVATION", Boolean.TRUE.toString()); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); diff --git a/test/jalview/gui/AlignmentPanelTest.java b/test/jalview/gui/AlignmentPanelTest.java index 3ec8b4d..62b8289 100644 --- a/test/jalview/gui/AlignmentPanelTest.java +++ b/test/jalview/gui/AlignmentPanelTest.java @@ -52,7 +52,7 @@ public class AlignmentPanelTest Jalview.main(new String[] { "-nonews", "-props", "test/jalview/testProps.jvprops" }); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", + Cache.setPropertyNoSave("SHOW_IDENTITY", Boolean.TRUE.toString()); af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa", DataSourceType.FILE); diff --git a/test/jalview/gui/AnnotationChooserTest.java b/test/jalview/gui/AnnotationChooserTest.java index fbdda09..f0c4632 100644 --- a/test/jalview/gui/AnnotationChooserTest.java +++ b/test/jalview/gui/AnnotationChooserTest.java @@ -88,14 +88,14 @@ public class AnnotationChooserTest { Cache.loadProperties("test/jalview/io/testProps.jvprops"); // pin down annotation sort order for test - Cache.applicationProperties.setProperty(Preferences.SORT_ANNOTATIONS, + Cache.setPropertyNoSave(Preferences.SORT_ANNOTATIONS, SequenceAnnotationOrder.NONE.name()); final String TRUE = Boolean.TRUE.toString(); - Cache.applicationProperties.setProperty( + Cache.setPropertyNoSave( Preferences.SHOW_AUTOCALC_ABOVE, TRUE); - Cache.applicationProperties.setProperty("SHOW_QUALITY", TRUE); - Cache.applicationProperties.setProperty("SHOW_CONSERVATION", TRUE); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", TRUE); + Cache.setPropertyNoSave("SHOW_QUALITY", TRUE); + Cache.setPropertyNoSave("SHOW_CONSERVATION", TRUE); + Cache.setPropertyNoSave("SHOW_IDENTITY", TRUE); AlignmentI al = new FormatAdapter().readFile(TEST_DATA, DataSourceType.PASTE, FileFormat.Fasta); diff --git a/test/jalview/gui/AnnotationColumnChooserTest.java b/test/jalview/gui/AnnotationColumnChooserTest.java index 912cd27..36d49dc 100644 --- a/test/jalview/gui/AnnotationColumnChooserTest.java +++ b/test/jalview/gui/AnnotationColumnChooserTest.java @@ -76,14 +76,14 @@ public class AnnotationColumnChooserTest { Cache.loadProperties("test/jalview/io/testProps.jvprops"); // pin down annotation sort order for test - Cache.applicationProperties.setProperty(Preferences.SORT_ANNOTATIONS, + Cache.setPropertyNoSave(Preferences.SORT_ANNOTATIONS, SequenceAnnotationOrder.NONE.name()); final String TRUE = Boolean.TRUE.toString(); - Cache.applicationProperties.setProperty(Preferences.SHOW_AUTOCALC_ABOVE, + Cache.setPropertyNoSave(Preferences.SHOW_AUTOCALC_ABOVE, TRUE); - Cache.applicationProperties.setProperty("SHOW_QUALITY", TRUE); - Cache.applicationProperties.setProperty("SHOW_CONSERVATION", TRUE); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", TRUE); + Cache.setPropertyNoSave("SHOW_QUALITY", TRUE); + Cache.setPropertyNoSave("SHOW_CONSERVATION", TRUE); + Cache.setPropertyNoSave("SHOW_IDENTITY", TRUE); AlignmentI al = new FormatAdapter().readFile(TEST_DATA, DataSourceType.PASTE, FileFormat.Fasta); diff --git a/test/jalview/gui/AnnotationRowFilterTest.java b/test/jalview/gui/AnnotationRowFilterTest.java index 69a41c5..47bd924 100644 --- a/test/jalview/gui/AnnotationRowFilterTest.java +++ b/test/jalview/gui/AnnotationRowFilterTest.java @@ -27,9 +27,9 @@ public class AnnotationRowFilterTest public void setUp() { Cache.loadProperties("test/jalview/io/testProps.jvprops"); - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", + Cache.setPropertyNoSave("SHOW_ANNOTATIONS", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty( + Cache.setPropertyNoSave( Preferences.SHOW_AUTOCALC_ABOVE, Boolean.TRUE.toString()); af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa", DataSourceType.FILE); diff --git a/test/jalview/gui/CalculationChooserTest.java b/test/jalview/gui/CalculationChooserTest.java index 6c2e777..595baef 100644 --- a/test/jalview/gui/CalculationChooserTest.java +++ b/test/jalview/gui/CalculationChooserTest.java @@ -19,7 +19,7 @@ public class CalculationChooserTest { // read-only Jalview properties Cache.loadProperties("test/jalview/io/testProps.jvprops"); - Cache.applicationProperties.setProperty("BLOSUM62_PCA_FOR_NUCLEOTIDE", + Cache.setPropertyNoSave("BLOSUM62_PCA_FOR_NUCLEOTIDE", Boolean.FALSE.toString()); } @@ -73,7 +73,7 @@ public class CalculationChooserTest /* * enable inclusion of BLOSUM62 for nucleotide PCA (JAL-2962) */ - Cache.applicationProperties.setProperty("BLOSUM62_PCA_FOR_NUCLEOTIDE", + Cache.setPropertyNoSave("BLOSUM62_PCA_FOR_NUCLEOTIDE", Boolean.TRUE.toString()); /* diff --git a/test/jalview/gui/FreeUpMemoryTest.java b/test/jalview/gui/FreeUpMemoryTest.java index 9b21274..18ff7f2 100644 --- a/test/jalview/gui/FreeUpMemoryTest.java +++ b/test/jalview/gui/FreeUpMemoryTest.java @@ -35,11 +35,11 @@ public class FreeUpMemoryTest Jalview.main(new String[] { "-nonews", "-props", "test/jalview/testProps.jvprops" }); String True = Boolean.TRUE.toString(); - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", True); - Cache.applicationProperties.setProperty("SHOW_QUALITY", True); - Cache.applicationProperties.setProperty("SHOW_CONSERVATION", True); - Cache.applicationProperties.setProperty("SHOW_OCCUPANCY", True); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", True); + Cache.setPropertyNoSave("SHOW_ANNOTATIONS", True); + Cache.setPropertyNoSave("SHOW_QUALITY", True); + Cache.setPropertyNoSave("SHOW_CONSERVATION", True); + Cache.setPropertyNoSave("SHOW_OCCUPANCY", True); + Cache.setPropertyNoSave("SHOW_IDENTITY", True); } /** @@ -70,7 +70,7 @@ public class FreeUpMemoryTest doStuffInJalview(f); - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); checkUsedMemory(35L); } @@ -109,7 +109,7 @@ public class FreeUpMemoryTest * sanity check - fails if any frame was added after * closeAll_actionPerformed */ - assertEquals(Desktop.instance.getAllFrames().length, 0); + assertEquals(Desktop.getInstance().getAllFrames().length, 0); /* * if this assertion fails diff --git a/test/jalview/gui/SeqPanelTest.java b/test/jalview/gui/SeqPanelTest.java index a03819d..01eec32 100644 --- a/test/jalview/gui/SeqPanelTest.java +++ b/test/jalview/gui/SeqPanelTest.java @@ -252,14 +252,14 @@ public class SeqPanelTest @AfterMethod(alwaysRun = true) public void tearDown() { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); } @Test(groups = "Functional") public void testFindMousePosition_wrapped_annotations() { - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true"); - Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); + Cache.setPropertyNoSave("SHOW_ANNOTATIONS", "true"); + Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true"); AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); AlignViewportI av = alignFrame.getViewport(); @@ -433,8 +433,8 @@ public class SeqPanelTest @Test(groups = "Functional") public void testFindMousePosition_wrapped_scaleAbove() { - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true"); - Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); + Cache.setPropertyNoSave("SHOW_ANNOTATIONS", "true"); + Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true"); AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); AlignViewportI av = alignFrame.getViewport(); @@ -633,8 +633,8 @@ public class SeqPanelTest @Test(groups = "Functional") public void testFindMousePosition_wrapped_noAnnotations() { - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false"); - Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); + Cache.setPropertyNoSave("SHOW_ANNOTATIONS", "false"); + Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true"); AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); AlignViewportI av = alignFrame.getViewport(); @@ -721,7 +721,7 @@ public class SeqPanelTest @Test(groups = "Functional") public void testFindColumn_unwrapped() { - Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "false"); + Cache.setPropertyNoSave("WRAP_ALIGNMENT", "false"); AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); SeqPanel testee = alignFrame.alignPanel.getSeqPanel(); @@ -790,7 +790,7 @@ public class SeqPanelTest @Test(groups = "Functional") public void testFindColumn_wrapped() { - Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); + Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true"); AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); AlignViewport av = alignFrame.getViewport(); diff --git a/test/jalview/io/AnnotatedPDBFileInputTest.java b/test/jalview/io/AnnotatedPDBFileInputTest.java index 8eb3796..beeb52f 100644 --- a/test/jalview/io/AnnotatedPDBFileInputTest.java +++ b/test/jalview/io/AnnotatedPDBFileInputTest.java @@ -68,9 +68,9 @@ public class AnnotatedPDBFileInputTest @BeforeMethod(alwaysRun = true) public void setup() throws Exception { - Cache.applicationProperties.setProperty("STRUCT_FROM_PDB", + Cache.setPropertyNoSave("STRUCT_FROM_PDB", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("ADD_SS_ANN", + Cache.setPropertyNoSave("ADD_SS_ANN", Boolean.TRUE.toString()); FileLoader loader = new FileLoader(false); AlignFrame af = loader.LoadFileWaitTillLoaded("examples/1gaq.txt", @@ -207,7 +207,7 @@ public class AnnotatedPDBFileInputTest @AfterClass(alwaysRun = true) public static void tearDownAfterClass() throws Exception { - jalview.gui.Desktop.instance.closeAll_actionPerformed(null); + jalview.gui.Desktop.getInstance().closeAll_actionPerformed(null); } diff --git a/test/jalview/io/CrossRef2xmlTests.java b/test/jalview/io/CrossRef2xmlTests.java index 3ca6ed8..4c5fbab 100644 --- a/test/jalview/io/CrossRef2xmlTests.java +++ b/test/jalview/io/CrossRef2xmlTests.java @@ -211,7 +211,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase } else { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); // recover stored project af = new FileLoader(false).LoadFileWaitTillLoaded( savedProjects.get(first).toString(), DataSourceType.FILE); @@ -278,7 +278,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase } else { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); pass3 = 0; // recover stored project File storedProject = savedProjects.get(nextxref); @@ -389,7 +389,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase } else { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); // recover stored project File storedProject = savedProjects.get(nextnextxref); if (storedProject == null) diff --git a/test/jalview/io/Jalview2xmlBase.java b/test/jalview/io/Jalview2xmlBase.java index fbdd782..089db93 100644 --- a/test/jalview/io/Jalview2xmlBase.java +++ b/test/jalview/io/Jalview2xmlBase.java @@ -70,7 +70,7 @@ public class Jalview2xmlBase @AfterClass(alwaysRun = true) public static void tearDownAfterClass() throws Exception { - jalview.gui.Desktop.instance.closeAll_actionPerformed(null); + jalview.gui.Desktop.getInstance().closeAll_actionPerformed(null); } @BeforeTest(alwaysRun = true) @@ -79,7 +79,7 @@ public class Jalview2xmlBase if (Desktop.instance != null && Desktop.getFrames() != null && Desktop.getFrames().length > 0) { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); } } diff --git a/test/jalview/io/JalviewExportPropertiesTests.java b/test/jalview/io/JalviewExportPropertiesTests.java index 06d177d..1614453 100644 --- a/test/jalview/io/JalviewExportPropertiesTests.java +++ b/test/jalview/io/JalviewExportPropertiesTests.java @@ -63,7 +63,7 @@ public class JalviewExportPropertiesTests @AfterClass(alwaysRun = true) public static void tearDownAfterClass() throws Exception { - jalview.gui.Desktop.instance.closeAll_actionPerformed(null); + jalview.gui.Desktop.getInstance().closeAll_actionPerformed(null); } diff --git a/test/jalview/project/Jalview2xmlTests.java b/test/jalview/project/Jalview2xmlTests.java index 80ed4c1..968e5ce 100644 --- a/test/jalview/project/Jalview2xmlTests.java +++ b/test/jalview/project/Jalview2xmlTests.java @@ -410,7 +410,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = { "Functional" }, enabled = true) public void testStoreAndRecoverExpandedviews() throws Exception { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/exampleFile_2_7.jar", DataSourceType.FILE); @@ -438,7 +438,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase { Assert.fail("Didn't save the expanded view state", e); } - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); if (Desktop.getAlignFrames() != null) { Assert.assertEquals(Desktop.getAlignFrames().length, 0); @@ -464,7 +464,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = { "Functional" }) public void testStoreAndRecoverReferenceSeqSettings() throws Exception { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/exampleFile_2_7.jar", DataSourceType.FILE); assertNotNull(af, "Didn't read in the example file correctly."); @@ -503,7 +503,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase { Assert.fail("Didn't save the expanded view state", e); } - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); if (Desktop.getAlignFrames() != null) { Assert.assertEquals(Desktop.getAlignFrames().length, 0); @@ -597,7 +597,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = { "Functional" }) public void testStoreAndRecoverGroupRepSeqs() throws Exception { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); assertNotNull(af, "Didn't read in the example file correctly."); @@ -672,7 +672,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase { Assert.fail("Didn't save the expanded view state", e); } - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); if (Desktop.getAlignFrames() != null) { Assert.assertEquals(Desktop.getAlignFrames().length, 0); @@ -717,7 +717,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = { "Functional" }) public void testStoreAndRecoverPDBEntry() throws Exception { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); String exampleFile = "examples/3W5V.pdb"; AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile, DataSourceType.FILE); @@ -766,7 +766,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase { Assert.fail("Didn't save the state", e); } - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); if (Desktop.getAlignFrames() != null) { Assert.assertEquals(Desktop.getAlignFrames().length, 0); @@ -817,7 +817,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = { "Functional" }) public void testStoreAndRecoverColourThresholds() throws IOException { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); @@ -880,7 +880,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase ".jvp"); tfile.deleteOnExit(); new Jalview2XML(false).saveState(tfile); - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(), DataSourceType.FILE); Assert.assertNotNull(af, "Failed to reload project"); @@ -1089,7 +1089,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = { "Functional" }) public void testMergeDatasetsforManyViews() throws IOException { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); // complex project - one dataset, several views on several alignments AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded( @@ -1133,7 +1133,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = "Functional") public void testPcaViewAssociation() throws IOException { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); final String PCAVIEWNAME = "With PCA"; // create a new tempfile File tempfile = File.createTempFile("jvPCAviewAssoc", "jvp"); @@ -1167,10 +1167,10 @@ public class Jalview2xmlTests extends Jalview2xmlBase } // load again. - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( tempfile.getCanonicalPath(), DataSourceType.FILE); - JInternalFrame[] frames = Desktop.instance.getAllFrames(); + JInternalFrame[] frames = Desktop.getInstance().getAllFrames(); // PCA and the tabbed alignment view should be the only two windows on the // desktop assertEquals(frames.length, 2, @@ -1200,7 +1200,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase @Test(groups = { "Functional" }) public void testStoreAndRecoverGeneLocus() throws Exception { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); String seqData = ">P30419\nACDE\n>X1235\nGCCTGTGACGAA"; AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData, DataSourceType.PASTE); @@ -1236,7 +1236,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase { Assert.fail("Didn't save the state", e); } - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(), DataSourceType.FILE); diff --git a/test/jalview/schemes/ColourSchemesTest.java b/test/jalview/schemes/ColourSchemesTest.java index 5db3743..06be31e 100644 --- a/test/jalview/schemes/ColourSchemesTest.java +++ b/test/jalview/schemes/ColourSchemesTest.java @@ -172,7 +172,7 @@ public class ColourSchemesTest @AfterClass(alwaysRun = true) public static void tearDownAfterClass() throws Exception { - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); } @Test(groups = "Functional") diff --git a/test/jalview/structure/StructureSelectionManagerTest.java b/test/jalview/structure/StructureSelectionManagerTest.java index e59648f..dab692f 100644 --- a/test/jalview/structure/StructureSelectionManagerTest.java +++ b/test/jalview/structure/StructureSelectionManagerTest.java @@ -199,7 +199,7 @@ public class StructureSelectionManagerTest extends Jalview2xmlBase { // for some reason 'BeforeMethod' (which should be inherited from // Jalview2XmlBase isn't always called)... - Desktop.instance.closeAll_actionPerformed(null); + Desktop.getInstance().closeAll_actionPerformed(null); try { Thread.sleep(200); } catch (Exception foo) {}; diff --git a/test/jalview/ws/PDBSequenceFetcherTest.java b/test/jalview/ws/PDBSequenceFetcherTest.java index d1e32b9..9992137 100644 --- a/test/jalview/ws/PDBSequenceFetcherTest.java +++ b/test/jalview/ws/PDBSequenceFetcherTest.java @@ -57,9 +57,9 @@ public class PDBSequenceFetcherTest { Cache.loadProperties("test/jalview/io/testProps.jvprops"); // ensure 'add annotation from structure' is selected - Cache.applicationProperties.setProperty("STRUCT_FROM_PDB", + Cache.setPropertyNoSave("STRUCT_FROM_PDB", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("ADD_SS_ANN", + Cache.setPropertyNoSave("ADD_SS_ANN", Boolean.TRUE.toString()); sf = new SequenceFetcher(); @@ -76,7 +76,7 @@ public class PDBSequenceFetcherTest @Test(groups = { "Network" }, enabled = true) public void testRnaSeqRetrieve() throws Exception { - Cache.applicationProperties.setProperty("PDB_DOWNLOAD_FORMAT", "PDB"); + Cache.setPropertyNoSave("PDB_DOWNLOAD_FORMAT", "PDB"); List sps = sf.getSourceProxy("PDB"); AlignmentI response = sps.get(0).getSequenceRecords("2GIS"); assertTrue(response != null); diff --git a/test/jalview/ws/dbsources/RemoteFormatTest.java b/test/jalview/ws/dbsources/RemoteFormatTest.java index 629bd8a..9d40624 100644 --- a/test/jalview/ws/dbsources/RemoteFormatTest.java +++ b/test/jalview/ws/dbsources/RemoteFormatTest.java @@ -46,9 +46,9 @@ public class RemoteFormatTest { Cache.loadProperties("test/jalview/io/testProps.jvprops"); // ensure 'add annotation from structure' is selected - Cache.applicationProperties.setProperty("STRUCT_FROM_PDB", + Cache.setPropertyNoSave("STRUCT_FROM_PDB", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("ADD_SS_ANN", + Cache.setPropertyNoSave("ADD_SS_ANN", Boolean.TRUE.toString()); sf = new SequenceFetcher(); diff --git a/test/mc_view/PDBfileTest.java b/test/mc_view/PDBfileTest.java index c99d185..0e34a24 100644 --- a/test/mc_view/PDBfileTest.java +++ b/test/mc_view/PDBfileTest.java @@ -325,11 +325,11 @@ public class PDBfileTest public void setUp() { Cache.loadProperties("test/jalview/io/testProps.jvprops"); - Cache.applicationProperties.setProperty("STRUCT_FROM_PDB", + Cache.setPropertyNoSave("STRUCT_FROM_PDB", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("ADD_TEMPFACT_ANN", + Cache.setPropertyNoSave("ADD_TEMPFACT_ANN", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("ADD_SS_ANN", + Cache.setPropertyNoSave("ADD_SS_ANN", Boolean.TRUE.toString()); StructureImportSettings.setDefaultStructureFileFormat("PDB"); } -- 1.7.10.2