From: tcofoegbu Date: Tue, 19 Jul 2016 11:49:48 +0000 (+0100) Subject: Merge branch 'develop' of https://source.jalview.org/git/jalview into develop X-Git-Tag: Release_2_10_0~138 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=f642f166c0eeb010c9f5006d8450f83390924b8a;hp=0555b298d22be533a0a67a3cd0ce2db883bae8bd;p=jalview.git Merge branch 'develop' of https://source.jalview.org/git/jalview into develop --- diff --git a/examples/groovy/featureCounter.groovy b/examples/groovy/featureCounter.groovy index 42d3187..a16d8bb 100644 --- a/examples/groovy/featureCounter.groovy +++ b/examples/groovy/featureCounter.groovy @@ -5,11 +5,15 @@ import jalview.workers.AlignmentAnnotationFactory; * Example script that registers two alignment annotation calculators * - one that counts residues in a column with Pfam annotation * - one that counts only charged residues with Pfam annotation - * To try this, first load uniref50.fa from the examples folder, then load features - * from examples/exampleFeatures.txt, before running this script from the Groovy console. + * + * To try: + * 1. load uniref50.fa from the examples folder + * 2. load features onto it from from examples/exampleFeatures.txt + * 3. Open this script in the Groovy console. + * 4. Either execute this script from the console, or via Calculate->Run Groovy Script - * Modify this example as required to count by column any desired value that can be - * derived from the residue and sequence features at each position of an alignment. + * To explore further, try changing this script to count other kinds of occurrences of + * residue and sequence features at columns in an alignment. */ /* @@ -45,7 +49,8 @@ def hasPfam = { features -> } /* - * Closure that counts residues with a Pfam feature annotation + * Closure that computes an annotation based on + * presence of particular residues and features * Parameters are * - the name (label) for the alignment annotation * - the description (tooltip) for the annotation @@ -74,12 +79,12 @@ def getColumnCounter = { name, desc, acceptResidue, acceptFeatures -> } /* - * Define an annotation that counts any residue with Pfam domain annotation + * Define an annotation row that counts any residue with Pfam domain annotation */ def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam) /* - * Define an annotation that counts charged residues with Pfam domain annotation + * Define an annotation row that counts charged residues with Pfam domain annotation */ def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam) diff --git a/resources/lang/Messages_es.properties b/resources/lang/Messages_es.properties index f814c97..618178d 100644 --- a/resources/lang/Messages_es.properties +++ b/resources/lang/Messages_es.properties @@ -1312,4 +1312,5 @@ status.obtaining_mapping_with_sifts=Obteniendo mapeo por SIFTS status.fetching_3d_structures_for=Buscando la estructura 3D para {0} status.fetching_3d_structures_for_selected_entries=Buscando las estructuras 3D para entradas seleccionadas... status.fetching_dbrefs_for_sequences_without_valid_refs=Buscando referencias para {0} secuencia(s) sin referencia válida necesaria para mapeado SIFTS -status.obtaining_mapping_with_nw_alignment=Obteniendo mapeo por alineamiento Needleman y Wunsch \ No newline at end of file +status.obtaining_mapping_with_nw_alignment=Obteniendo mapeo por alineamiento Needleman y Wunsch +status.exporting_alignment_as_x_file = Exportando alineamiento como fichero tipo {0} diff --git a/src/jalview/analysis/Conservation.java b/src/jalview/analysis/Conservation.java index 7b3ce25..21d990c 100755 --- a/src/jalview/analysis/Conservation.java +++ b/src/jalview/analysis/Conservation.java @@ -693,7 +693,7 @@ public class Conservation qmax = qualityRange[1].floatValue(); } - for (int i = 0; i < alWidth; i++) + for (int i = istart; i < alWidth; i++) { float value = 0; diff --git a/src/jalview/api/AlignCalcManagerI.java b/src/jalview/api/AlignCalcManagerI.java index 66f4036..9c7f9ab 100644 --- a/src/jalview/api/AlignCalcManagerI.java +++ b/src/jalview/api/AlignCalcManagerI.java @@ -35,14 +35,6 @@ public interface AlignCalcManagerI void notifyStart(AlignCalcWorkerI worker); /** - * check if a calculation of this type is already active - * - * @param worker - * @return - */ - boolean alreadyDoing(AlignCalcWorkerI worker); - - /** * tell manager that worker is now processing data * * @param worker @@ -63,7 +55,7 @@ public interface AlignCalcManagerI * * @param worker */ - void workerCannotRun(AlignCalcWorkerI worker); + void disableWorker(AlignCalcWorkerI worker); /** * indicate that a worker like this may be run on the platform. @@ -71,7 +63,15 @@ public interface AlignCalcManagerI * @param worker * of class to be removed from the execution blacklist */ - void workerMayRun(AlignCalcWorkerI worker); + void enableWorker(AlignCalcWorkerI worker); + + /** + * Answers true if the worker is disabled from running + * + * @param worker + * @return + */ + boolean isDisabled(AlignCalcWorkerI worker); /** * launch a new worker @@ -120,7 +120,7 @@ public interface AlignCalcManagerI * * @param workerClass */ - void updateAnnotationFor(Class workerClass); + void updateAnnotationFor(Class workerClass); /** * return any registered workers of the given class @@ -128,17 +128,8 @@ public interface AlignCalcManagerI * @param workerClass * @return null or one or more workers of the given class */ - List getRegisteredWorkersOfClass(Class workerClass); - - /** - * start any workers of the given class - * - * @param workerClass - * @return false if no workers of given class were registered (note - - * blacklisted classes cannot be restarted, so this method will return - * true for blacklisted workers) - */ - boolean startRegisteredWorkersOfClass(Class workerClass); + List getRegisteredWorkersOfClass( + Class workerClass); /** * work out if there is an instance of a worker that is *waiting* to start @@ -156,6 +147,15 @@ public interface AlignCalcManagerI * * @param typeToRemove */ - void removeRegisteredWorkersOfClass(Class typeToRemove); + void removeRegisteredWorkersOfClass( + Class typeToRemove); + /** + * Removes the worker that produces the given annotation, provided it is + * marked as 'deletable'. Some workers may need to continue to run as the + * results of their calculations are needed, e.g. for colour schemes. + * + * @param ann + */ + void removeWorkerForAnnotation(AlignmentAnnotation ann); } diff --git a/src/jalview/api/AlignCalcWorkerI.java b/src/jalview/api/AlignCalcWorkerI.java index 06dc054..85157c4 100644 --- a/src/jalview/api/AlignCalcWorkerI.java +++ b/src/jalview/api/AlignCalcWorkerI.java @@ -35,17 +35,26 @@ public interface AlignCalcWorkerI extends Runnable * @param annot * @return */ - public boolean involves(AlignmentAnnotation annot); + boolean involves(AlignmentAnnotation annot); /** * Updates the display of calculated annotation values (does not recalculate - * the values). This allows for quick redraw of annotations when display - * settings are changed. + * the values). This allows ßquick redraw of annotations when display settings + * are changed. */ - public void updateAnnotation(); + void updateAnnotation(); /** - * Removes any annotation managed by this worker from the alignment + * Removes any annotation(s) managed by this worker from the alignment */ void removeAnnotation(); + + /** + * Answers true if the worker should be deleted entirely when its annotation + * is deleted from the display, or false if it should continue to run. Some + * workers are required to run for their side-effects. + * + * @return + */ + boolean isDeletable(); } diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index 8f1f2fd..cbb5c99 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -219,6 +219,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, { viewport.setColumnSelection(columnSelection); } + viewport.setScaleAboveWrapped(scaleAbove.getState()); alignPanel = new AlignmentPanel(this, viewport); avc = new jalview.controller.AlignViewController(this, viewport, diff --git a/src/jalview/appletgui/FeatureRenderer.java b/src/jalview/appletgui/FeatureRenderer.java index 3f87549..81d8ef5 100644 --- a/src/jalview/appletgui/FeatureRenderer.java +++ b/src/jalview/appletgui/FeatureRenderer.java @@ -70,8 +70,8 @@ public class FeatureRenderer extends */ public FeatureRenderer(AlignmentViewport av) { - super(); - this.av = av; + super(av); + } static String lastFeatureAdded; diff --git a/src/jalview/appletgui/FeatureSettings.java b/src/jalview/appletgui/FeatureSettings.java index bfac241..9733c86 100755 --- a/src/jalview/appletgui/FeatureSettings.java +++ b/src/jalview/appletgui/FeatureSettings.java @@ -763,28 +763,31 @@ public class FeatureSettings extends Panel implements ItemListener, public void paint(Graphics g) { Dimension d = getSize(); - if (col.isColourByLabel()) + if (col != null) { - g.setColor(Color.white); - g.fillRect(d.width / 2, 0, d.width / 2, d.height); - /* - * g.setColor(Color.black); Font f=g.getFont().deriveFont(9); - * g.setFont(f); - * - * // g.setFont(g.getFont().deriveFont( // - * AffineTransform.getScaleInstance( // - * width/g.getFontMetrics().stringWidth("Label"), // - * height/g.getFontMetrics().getHeight()))); g.drawString("Label", - * width/2, 0); - */ + if (col.isColourByLabel()) + { + g.setColor(Color.white); + g.fillRect(d.width / 2, 0, d.width / 2, d.height); + /* + * g.setColor(Color.black); Font f=g.getFont().deriveFont(9); + * g.setFont(f); + * + * // g.setFont(g.getFont().deriveFont( // + * AffineTransform.getScaleInstance( // + * width/g.getFontMetrics().stringWidth("Label"), // + * height/g.getFontMetrics().getHeight()))); g.drawString("Label", + * width/2, 0); + */ - } - else if (col.isGraduatedColour()) - { - Color maxCol = col.getMaxColour(); - g.setColor(maxCol); - g.fillRect(d.width / 2, 0, d.width / 2, d.height); + } + else if (col.isGraduatedColour()) + { + Color maxCol = col.getMaxColour(); + g.setColor(maxCol); + g.fillRect(d.width / 2, 0, d.width / 2, d.height); + } } if (hasLink) diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index bc64728..5a1243a 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -265,7 +265,8 @@ public class OverviewPanel extends Panel implements Runnable, { miniMe = null; int alwidth = av.getAlignment().getWidth(); - int alheight = av.getAlignment().getHeight(); + int alheight = av.getAlignment().getHeight() + + av.getAlignment().getHiddenSequences().getSize(); if (av.isShowSequenceFeatures()) { diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index 71ecb13..0f71818 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -22,6 +22,8 @@ package jalview.appletgui; import jalview.datamodel.ColumnSelection; import jalview.datamodel.SequenceGroup; +import jalview.renderer.ScaleRenderer; +import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.util.MessageManager; import java.awt.Color; @@ -36,6 +38,7 @@ import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; +import java.util.List; public class ScalePanel extends Panel implements MouseMotionListener, MouseListener @@ -407,7 +410,8 @@ public class ScalePanel extends Panel implements MouseMotionListener, // Fill the selected columns ColumnSelection cs = av.getColumnSelection(); gg.setColor(new Color(220, 0, 0)); - int avcharWidth = av.getCharWidth(), avcharHeight = av.getCharHeight(); + int avCharWidth = av.getCharWidth(); + int avcharHeight = av.getCharHeight(); for (int sel : cs.getSelected()) { // TODO: JAL-2001 - provide a fast method to list visible selected in a @@ -419,7 +423,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, if ((sel >= startx) && (sel <= endx)) { - gg.fillRect((sel - startx) * avcharWidth, 0, avcharWidth, + gg.fillRect((sel - startx) * avCharWidth, 0, avCharWidth, getSize().height); } } @@ -427,43 +431,36 @@ public class ScalePanel extends Panel implements MouseMotionListener, // Draw the scale numbers gg.setColor(Color.black); - int scalestartx = (startx / 10) * 10; - int widthx = 1 + endx - startx; - - FontMetrics fm = gg.getFontMetrics(av.getFont()); - int y = avcharHeight - fm.getDescent(); - - if ((scalestartx % 10) == 0) - { - scalestartx += 5; - } - - String string; int maxX = 0; + List marks = new ScaleRenderer().calculateMarks(av, startx, + endx); - for (int i = scalestartx; i < endx; i += 5) + FontMetrics fm = gg.getFontMetrics(av.getFont()); + int y = avcharHeight; + int yOf = fm.getDescent(); + y -= yOf; + for (ScaleMark mark : marks) { - if ((i % 10) == 0) + boolean major = mark.major; + int mpos = mark.column; // (i - startx - 1) + String mstring = mark.text; + if (mstring != null) { - string = String.valueOf(av.getColumnSelection() - .adjustForHiddenColumns(i)); - if ((i - startx - 1) * avcharWidth > maxX) + if (mpos * avCharWidth > maxX) { - gg.drawString(string, (i - startx - 1) * avcharWidth, y); - maxX = (i - startx + 1) * avcharWidth + fm.stringWidth(string); + gg.drawString(mstring, mpos * avCharWidth, y); + maxX = (mpos + 2) * avCharWidth + fm.stringWidth(mstring); } - - gg.drawLine(((i - startx - 1) * avcharWidth) + (avcharWidth / 2), - y + 2, - ((i - startx - 1) * avcharWidth) + (avcharWidth / 2), y - + (fm.getDescent() * 2)); - + } + if (major) + { + gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + 2, + (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2)); } else { - gg.drawLine(((i - startx - 1) * avcharWidth) + (avcharWidth / 2), y - + fm.getDescent(), ((i - startx - 1) * avcharWidth) - + (avcharWidth / 2), y + (fm.getDescent() * 2)); + gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + yOf, + (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2)); } } @@ -473,6 +470,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, int res; if (av.getShowHiddenMarkers()) { + int widthx = 1 + endx - startx; for (int i = 0; i < av.getColumnSelection().getHiddenColumns() .size(); i++) { @@ -485,21 +483,14 @@ public class ScalePanel extends Panel implements MouseMotionListener, continue; } - gg.fillPolygon(new int[] { res * avcharWidth - avcharHeight / 4, - res * avcharWidth + avcharHeight / 4, res * avcharWidth }, - new int[] { y - avcharHeight / 2, y - avcharHeight / 2, - y + 8 }, 3); - + gg.fillPolygon(new int[] { + -1 + res * avCharWidth - avcharHeight / 4, + -1 + res * avCharWidth + avcharHeight / 4, + -1 + res * avCharWidth }, + new int[] { y, y, y + 2 * yOf }, 3); } } - - if (reveal != null && reveal[0] > startx && reveal[0] < endx) - { - gg.drawString(MessageManager.getString("label.reveal_columns"), - reveal[0] * avcharWidth, 0); - } } - } } diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index 024fdc7..22849f1 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -24,6 +24,8 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.SearchResults; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.renderer.ScaleRenderer; +import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.viewmodel.AlignmentViewport; import java.awt.Color; @@ -90,26 +92,30 @@ public class SeqCanvas extends Panel private void drawNorthScale(Graphics g, int startx, int endx, int ypos) { - int scalestartx = startx - startx % 10 + 10; - + updateViewport(); g.setColor(Color.black); - - // NORTH SCALE - for (int i = scalestartx; i < endx; i += 10) + for (ScaleMark mark : new ScaleRenderer().calculateMarks(av, startx, + endx)) { - int value = i; - if (av.hasHiddenColumns()) + int mpos = mark.column; // (i - startx - 1) + if (mpos < 0) { - value = av.getColumnSelection().adjustForHiddenColumns(value); + continue; } + String mstring = mark.text; - g.drawString(String.valueOf(value), (i - startx - 1) * avcharWidth, - ypos - (avcharHeight / 2)); - - g.drawLine(((i - startx - 1) * avcharWidth) + (avcharWidth / 2), - (ypos + 2) - (avcharHeight / 2), - ((i - startx - 1) * avcharWidth) + (avcharWidth / 2), - ypos - 2); + if (mark.major) + { + if (mstring != null) + { + g.drawString(mstring, mpos * avcharWidth, ypos + - (avcharHeight / 2)); + } + g.drawLine((mpos * avcharWidth) + (avcharWidth / 2), (ypos + 2) + - (avcharHeight / 2), (mpos * avcharWidth) + + (avcharWidth / 2), + ypos - 2); + } } } diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index d737bd5..32bb761 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -1721,6 +1721,7 @@ public class Alignment implements AlignmentI boolean preserveUnmappedGaps) { // TODO should this method signature be the one in the interface? + // JBPComment - yes - neither flag is used, so should be deleted. boolean thisIsNucleotide = this.isNucleotide(); boolean thatIsProtein = !al.isNucleotide(); if (!thatIsProtein && !thisIsNucleotide) diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index c15bb99..f1db4c0 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -41,7 +41,8 @@ public interface AlignmentI extends AnnotatedCollectionI * * Calculates the maximum width of the alignment, including gaps. * - * @return Greatest sequence length within alignment. + * @return Greatest sequence length within alignment, or -1 if no sequences + * present */ @Override int getWidth(); diff --git a/src/jalview/ext/ensembl/EnsemblInfo.java b/src/jalview/ext/ensembl/EnsemblInfo.java index 950b658..88b5ac4 100644 --- a/src/jalview/ext/ensembl/EnsemblInfo.java +++ b/src/jalview/ext/ensembl/EnsemblInfo.java @@ -33,7 +33,7 @@ class EnsemblInfo /* * true when http://rest.ensembl.org/info/ping/?content-type=application/json - * returns response code 200 + * returns response code 200 and not {"error":"Database is unavailable"} */ boolean restAvailable; diff --git a/src/jalview/ext/ensembl/EnsemblRestClient.java b/src/jalview/ext/ensembl/EnsemblRestClient.java index e651ddf..f9cfe05 100644 --- a/src/jalview/ext/ensembl/EnsemblRestClient.java +++ b/src/jalview/ext/ensembl/EnsemblRestClient.java @@ -155,30 +155,40 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher protected abstract String getResponseMimeType(); /** - * Tries to connect to Ensembl's REST 'ping' endpoint, and returns true if - * successful, else false + * Checks Ensembl's REST 'ping' endpoint, and returns true if response + * indicates available, else false * + * @see http://rest.ensembl.org/documentation/info/ping * @return */ private boolean checkEnsembl() { + HttpURLConnection conn = null; try { // note this format works for both ensembl and ensemblgenomes // info/ping.json works for ensembl only (March 2016) URL ping = new URL(getDomain() + "/info/ping?content-type=application/json"); - HttpURLConnection conn = (HttpURLConnection) ping.openConnection(); - int rc = conn.getResponseCode(); - conn.disconnect(); - if (rc >= 200 && rc < 300) - { - return true; - } + + /* + * expect {"ping":1} if ok + */ + BufferedReader br = getHttpResponse(ping, null); + JSONParser jp = new JSONParser(); + JSONObject val = (JSONObject) jp.parse(br); + String pingString = val.get("ping").toString(); + return pingString != null; } catch (Throwable t) { System.err.println("Error connecting to " + PING_URL + ": " + t.getMessage()); + } finally + { + if (conn != null) + { + conn.disconnect(); + } } return false; } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 891fdd6..3736791 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -4691,8 +4691,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * @param source * the database to show cross-references for */ - protected void showProductsFor(final SequenceI[] sel, final boolean _odna, - final String source) + protected void showProductsFor(final SequenceI[] sel, + final boolean _odna, final String source) { Runnable foo = new Runnable() { @@ -4711,7 +4711,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, AlignmentI dataset = alignment.getDataset() == null ? alignment : alignment.getDataset(); boolean dna = alignment.isNucleotide(); - if (_odna!=dna) + if (_odna != dna) { System.err .println("Conflict: showProducts for alignment originally " @@ -4720,8 +4720,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, + " now searching for " + (dna ? "DNA" : "Protein") + " Context."); } - AlignmentI xrefs = new CrossRef(sel, dataset) - .findXrefSequences(source, dna); + AlignmentI xrefs = new CrossRef(sel, dataset).findXrefSequences( + source, dna); if (xrefs == null) { return; @@ -4741,97 +4741,102 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, xrefsAlignment.alignAs(alignment); } - AlignFrame newFrame = new AlignFrame(xrefsAlignment, DEFAULT_WIDTH, - DEFAULT_HEIGHT); - if (Cache.getDefault("HIDE_INTRONS", true)) - { - newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false); - } - String newtitle = String.format("%s %s %s", MessageManager - .getString(dna ? "label.proteins" : "label.nucleotides"), - MessageManager.getString("label.for"), getTitle()); - newFrame.setTitle(newtitle); - - if (!Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true)) - { - /* - * split frame display is turned off in preferences file - */ - Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH, - DEFAULT_HEIGHT); - return; // via finally clause - } - /* - * Make a copy of this alignment (sharing the same dataset + * If we are opening a splitframe, make a copy of this alignment (sharing the same dataset * sequences). If we are DNA, drop introns and update mappings */ AlignmentI copyAlignment = null; - boolean copyAlignmentIsAligned = false; - if (dna) + + if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true)) { - copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset, - xrefsAlignment.getSequencesArray()); - if (copyAlignment.getHeight() == 0) + boolean copyAlignmentIsAligned = false; + if (dna) { - System.err.println("Failed to make CDS alignment"); - } + copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset, + xrefsAlignment.getSequencesArray()); + if (copyAlignment.getHeight() == 0) + { + System.err.println("Failed to make CDS alignment"); + } - /* - * pending getting Embl transcripts to 'align', - * we are only doing this for Ensembl - */ - // TODO proper criteria for 'can align as cdna' - if (DBRefSource.ENSEMBL.equalsIgnoreCase(source) - || AlignmentUtils.looksLikeEnsembl(alignment)) + /* + * pending getting Embl transcripts to 'align', + * we are only doing this for Ensembl + */ + // TODO proper criteria for 'can align as cdna' + if (DBRefSource.ENSEMBL.equalsIgnoreCase(source) + || AlignmentUtils.looksLikeEnsembl(alignment)) + { + copyAlignment.alignAs(alignment); + copyAlignmentIsAligned = true; + } + } + else { - copyAlignment.alignAs(alignment); - copyAlignmentIsAligned = true; + copyAlignment = AlignmentUtils.makeCopyAlignment(sel, + xrefs.getSequencesArray(), dataset); } - } - else - { - copyAlignment = AlignmentUtils.makeCopyAlignment(sel, - xrefs.getSequencesArray(), dataset); - } - copyAlignment.setGapCharacter(AlignFrame.this.viewport - .getGapCharacter()); + copyAlignment.setGapCharacter(AlignFrame.this.viewport + .getGapCharacter()); - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); + StructureSelectionManager ssm = StructureSelectionManager + .getStructureSelectionManager(Desktop.instance); - /* - * register any new mappings for sequence mouseover etc - * (will not duplicate any previously registered mappings) - */ - ssm.registerMappings(dataset.getCodonFrames()); + /* + * register any new mappings for sequence mouseover etc + * (will not duplicate any previously registered mappings) + */ + ssm.registerMappings(dataset.getCodonFrames()); - if (copyAlignment.getHeight() <= 0) - { - System.err.println("No Sequences generated for xRef type " - + source); - return; + if (copyAlignment.getHeight() <= 0) + { + System.err.println("No Sequences generated for xRef type " + + source); + return; + } + /* + * align protein to dna + */ + if (dna && copyAlignmentIsAligned) + { + xrefsAlignment.alignAs(copyAlignment); + } + else + { + /* + * align cdna to protein - currently only if + * fetching and aligning Ensembl transcripts! + */ + // TODO: generalise for other sources of locus/transcript/cds data + if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source)) + { + copyAlignment.alignAs(xrefsAlignment); + } + } } /* - * align protein to dna + * build AlignFrame(s) according to available alignment data */ - if (dna && copyAlignmentIsAligned) + AlignFrame newFrame = new AlignFrame(xrefsAlignment, + DEFAULT_WIDTH, DEFAULT_HEIGHT); + if (Cache.getDefault("HIDE_INTRONS", true)) { - xrefsAlignment.alignAs(copyAlignment); + newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false); } - else + String newtitle = String.format("%s %s %s", MessageManager + .getString(dna ? "label.proteins" : "label.nucleotides"), + MessageManager.getString("label.for"), getTitle()); + newFrame.setTitle(newtitle); + + if (copyAlignment == null) { /* - * align cdna to protein - currently only if - * fetching and aligning Ensembl transcripts! + * split frame display is turned off in preferences file */ - // TODO: generalise for other sources of locus/transcript/cds data - if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source)) - { - copyAlignment.alignAs(xrefsAlignment); - } + Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH, + DEFAULT_HEIGHT); + return; // via finally clause } - AlignFrame copyThis = new AlignFrame(copyAlignment, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); copyThis.setTitle(AlignFrame.this.getTitle()); diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index e27b919..5b01b9b 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -244,6 +244,7 @@ public class AnnotationLabels extends JPanel implements MouseListener, else if (evt.getActionCommand().equals(DELETE)) { ap.av.getAlignment().deleteAnnotation(aa[selectedRow]); + ap.av.getCalcManager().removeWorkerForAnnotation(aa[selectedRow]); } else if (evt.getActionCommand().equals(SHOWALL)) { diff --git a/src/jalview/gui/FeatureRenderer.java b/src/jalview/gui/FeatureRenderer.java index 1bf7453..727c13b 100644 --- a/src/jalview/gui/FeatureRenderer.java +++ b/src/jalview/gui/FeatureRenderer.java @@ -75,9 +75,8 @@ public class FeatureRenderer extends */ public FeatureRenderer(AlignmentPanel ap) { - super(); + super(ap.av); this.ap = ap; - this.av = ap.av; if (ap != null && ap.getSeqPanel() != null && ap.getSeqPanel().seqCanvas != null && ap.getSeqPanel().seqCanvas.fr != null) diff --git a/src/jalview/gui/ScalePanel.java b/src/jalview/gui/ScalePanel.java index 2165b2c..e231c6f 100755 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@ -23,6 +23,8 @@ package jalview.gui; import jalview.datamodel.ColumnSelection; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.renderer.ScaleRenderer; +import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.util.MessageManager; import java.awt.Color; @@ -497,7 +499,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener, int widthx = 1 + endx - startx; FontMetrics fm = gg.getFontMetrics(av.getFont()); - int y = avCharHeight, yOf = fm.getDescent(); + int y = avCharHeight; + int yOf = fm.getDescent(); y -= yOf; if (av.hasHiddenColumns()) { @@ -522,7 +525,6 @@ public class ScalePanel extends JPanel implements MouseMotionListener, -1 + res * avCharWidth - avCharHeight / 4, -1 + res * avCharWidth + avCharHeight / 4, -1 + res * avCharWidth }, new int[] { y, y, y + 2 * yOf }, 3); - } } } @@ -530,14 +532,14 @@ public class ScalePanel extends JPanel implements MouseMotionListener, gg.setColor(Color.black); int maxX = 0; - List marks = jalview.renderer.ScaleRenderer.calculateMarks( - av, startx, endx); + List marks = new ScaleRenderer().calculateMarks(av, startx, + endx); - for (Object[] mark : marks) + for (ScaleMark mark : marks) { - boolean major = Boolean.valueOf((Boolean) mark[0]); - int mpos = ((Integer) mark[1]).intValue(); // (i - startx - 1) - String mstring = (String) mark[2]; + boolean major = mark.major; + int mpos = mark.column; // (i - startx - 1) + String mstring = mark.text; if (mstring != null) { if (mpos * avCharWidth > maxX) @@ -557,15 +559,6 @@ public class ScalePanel extends JPanel implements MouseMotionListener, (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2)); } } - if (av.hasHiddenColumns()) - { - if (reveal != null && reveal[0] > startx && reveal[0] < endx) - { - gg.drawString(MessageManager.getString("label.reveal_columns"), - reveal[0] * avCharWidth, 0); - } - } - } } diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 2f7cd76..760ece0 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -24,6 +24,8 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.SearchResults; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.renderer.ScaleRenderer; +import jalview.renderer.ScaleRenderer.ScaleMark; import java.awt.BasicStroke; import java.awt.BorderLayout; @@ -122,17 +124,17 @@ public class SeqCanvas extends JComponent private void drawNorthScale(Graphics g, int startx, int endx, int ypos) { updateViewport(); - for (Object[] mark : jalview.renderer.ScaleRenderer.calculateMarks(av, - startx, endx)) + for (ScaleMark mark : new ScaleRenderer().calculateMarks(av, startx, + endx)) { - int mpos = ((Integer) mark[1]).intValue(); // (i - startx - 1) + int mpos = mark.column; // (i - startx - 1) if (mpos < 0) { continue; } - String mstring = (String) mark[2]; + String mstring = mark.text; - if (Boolean.valueOf((Boolean) mark[0])) + if (mark.major) { if (mstring != null) { diff --git a/src/jalview/renderer/ScaleRenderer.java b/src/jalview/renderer/ScaleRenderer.java index 7f1e074..164c7c7 100644 --- a/src/jalview/renderer/ScaleRenderer.java +++ b/src/jalview/renderer/ScaleRenderer.java @@ -34,6 +34,22 @@ import java.util.List; */ public class ScaleRenderer { + public class ScaleMark + { + public final boolean major; + + public final int column; + + public final String text; + + ScaleMark(boolean isMajor, int col, String txt) + { + major = isMajor; + column = col; + text = txt; + } + } + /** * calculate positions markers on the alignment ruler * @@ -42,15 +58,13 @@ public class ScaleRenderer * left-most column in visible view * @param endx * - right-most column in visible view - * @return List { Object { .. } } Boolean: true/false for major/minor mark, - * Integer: marker position in alignment column coords, String: null - * or a String to be rendered at the position. + * @return List of ScaleMark holding boolean: true/false for major/minor mark, + * marker position in alignment column coords, a String to be rendered + * at the position (or null) */ - public static List calculateMarks(AlignViewportI av, + public List calculateMarks(AlignViewportI av, int startx, int endx) { - new ArrayList(); - int scalestartx = (startx / 10) * 10; SequenceI refSeq = av.getAlignment().getSeqrep(); @@ -72,13 +86,12 @@ public class ScaleRenderer { scalestartx += 5; } - List marks = new ArrayList(); + List marks = new ArrayList(); String string; int refN, iadj; // todo: add a 'reference origin column' to set column number relative to for (int i = scalestartx; i < endx; i += 5) { - Object[] amark = new Object[3]; if (((i - refSp) % 10) == 0) { if (refSeq == null) @@ -106,18 +119,12 @@ public class ScaleRenderer string = String.valueOf(refN) + refSeq.getCharAt(iadj); } } - amark[0] = Boolean.TRUE; - amark[1] = Integer.valueOf(i - startx - 1); - amark[2] = string; - + marks.add(new ScaleMark(true, i - startx - 1, string)); } else { - amark[0] = Boolean.FALSE; - amark[1] = Integer.valueOf(i - startx - 1); - amark[2] = null; + marks.add(new ScaleMark(false, i - startx - 1, null)); } - marks.add(amark); } return marks; } diff --git a/src/jalview/renderer/seqfeatures/FeatureRenderer.java b/src/jalview/renderer/seqfeatures/FeatureRenderer.java index 5d3aa2d..b007365 100644 --- a/src/jalview/renderer/seqfeatures/FeatureRenderer.java +++ b/src/jalview/renderer/seqfeatures/FeatureRenderer.java @@ -20,6 +20,7 @@ */ package jalview.renderer.seqfeatures; +import jalview.api.AlignViewportI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.viewmodel.seqfeatures.FeatureRendererModel; @@ -52,6 +53,16 @@ public class FeatureRenderer extends FeatureRendererModel private Integer currentColour; + /** + * Constructor given a viewport + * + * @param viewport + */ + public FeatureRenderer(AlignViewportI viewport) + { + this.av = viewport; + } + protected void updateAvConfig() { av_charHeight = av.getCharHeight(); diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index a4e4348..d813fe2 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -29,7 +29,6 @@ import jalview.datamodel.SequenceI; import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.schemes.FeatureColour; import jalview.schemes.UserColourScheme; -import jalview.viewmodel.AlignmentViewport; import java.awt.Color; import java.beans.PropertyChangeListener; @@ -64,7 +63,7 @@ public abstract class FeatureRendererModel implements protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( this); - protected AlignmentViewport av; + protected AlignViewportI av; @Override public AlignViewportI getViewport() diff --git a/src/jalview/workers/AlignCalcManager.java b/src/jalview/workers/AlignCalcManager.java index 1063706..191e8c7 100644 --- a/src/jalview/workers/AlignCalcManager.java +++ b/src/jalview/workers/AlignCalcManager.java @@ -34,23 +34,48 @@ import java.util.Set; public class AlignCalcManager implements AlignCalcManagerI { - private volatile List restartable = Collections - .synchronizedList(new ArrayList()); + /* + * list of registered workers + */ + private volatile List restartable; - private volatile List blackList = Collections - .synchronizedList(new ArrayList()); + /* + * types of worker _not_ to run (for example, because they have + * previously thrown errors) + */ + private volatile List> blackList; - /** + /* * global record of calculations in progress */ - private volatile Map inProgress = Collections - .synchronizedMap(new Hashtable()); + private volatile List inProgress; - /** + /* * record of calculations pending or in progress in the current context */ - private volatile Map> updating = Collections - .synchronizedMap(new Hashtable>()); + private volatile Map, List> updating; + + /* + * workers that have run to completion so are candidates for visual-only + * update of their results + */ + private HashSet canUpdate; + + /** + * Constructor + */ + public AlignCalcManager() + { + restartable = Collections + .synchronizedList(new ArrayList()); + blackList = Collections + .synchronizedList(new ArrayList>()); + inProgress = Collections + .synchronizedList(new ArrayList()); + updating = Collections + .synchronizedMap(new Hashtable, List>()); + canUpdate = new HashSet(); + } @Override public void notifyStart(AlignCalcWorkerI worker) @@ -72,15 +97,6 @@ public class AlignCalcManager implements AlignCalcManagerI } } - @Override - public boolean alreadyDoing(AlignCalcWorkerI worker) - { - synchronized (inProgress) - { - return inProgress.containsKey(worker.getClass()); - } - } - /* * (non-Javadoc) * @@ -108,52 +124,31 @@ public class AlignCalcManager implements AlignCalcManagerI } } - // TODO make into api method if needed ? - public int numberLive(AlignCalcWorkerI worker) - { - synchronized (updating) - { - List upd = updating.get(worker.getClass()); - if (upd == null) - { - return 0; - } - ; - return upd.size(); - } - } - @Override public boolean notifyWorking(AlignCalcWorkerI worker) { synchronized (inProgress) { - // TODO: decide if we should throw exceptions here if multiple workers - // start to work - if (inProgress.get(worker.getClass()) != null) + if (inProgress.contains(worker)) { - if (false) - { - System.err - .println("Warning: Multiple workers are running of type " - + worker.getClass()); - } - return false; + System.err.println("Implementation error: duplicate run of worker " + + worker); + } + else + { + inProgress.add(worker); } - inProgress.put(worker.getClass(), worker); } return true; } - private final HashSet canUpdate = new HashSet(); - @Override public void workerComplete(AlignCalcWorkerI worker) { synchronized (inProgress) { - // System.err.println("Worker "+worker.getClass()+" marked as complete."); - inProgress.remove(worker.getClass()); + // System.err.println("Worker " + worker + " marked as complete."); + inProgress.remove(worker); List upd = updating.get(worker.getClass()); if (upd != null) { @@ -167,7 +162,7 @@ public class AlignCalcManager implements AlignCalcManagerI } @Override - public void workerCannotRun(AlignCalcWorkerI worker) + public void disableWorker(AlignCalcWorkerI worker) { synchronized (blackList) { @@ -175,22 +170,24 @@ public class AlignCalcManager implements AlignCalcManagerI } } - public boolean isBlackListed(Class workerType) + @Override + public boolean isDisabled(AlignCalcWorkerI worker) { synchronized (blackList) { - return blackList.contains(workerType); + return blackList.contains(worker.getClass()); } } @Override public void startWorker(AlignCalcWorkerI worker) { - // System.err.println("Starting "+worker.getClass()); - // new Exception("").printStackTrace(); - Thread tw = new Thread(worker); - tw.setName(worker.getClass().toString()); - tw.start(); + if (!isDisabled(worker)) + { + Thread tw = new Thread(worker); + tw.setName(worker.getClass().toString()); + tw.start(); + } } @Override @@ -199,7 +196,7 @@ public class AlignCalcManager implements AlignCalcManagerI synchronized (inProgress) {// System.err.println("isWorking : worker "+(worker!=null ? // worker.getClass():"null")+ " "+hashCode()); - return worker != null && inProgress.get(worker.getClass()) == worker; + return worker != null && inProgress.contains(worker); } } @@ -243,7 +240,7 @@ public class AlignCalcManager implements AlignCalcManagerI { synchronized (inProgress) { - for (AlignCalcWorkerI worker : inProgress.values()) + for (AlignCalcWorkerI worker : inProgress) { if (worker.involves(alignmentAnnotation)) { @@ -268,7 +265,8 @@ public class AlignCalcManager implements AlignCalcManagerI } @Override - public void updateAnnotationFor(Class workerClass) + public void updateAnnotationFor( + Class workerClass) { AlignCalcWorkerI[] workers; @@ -287,62 +285,35 @@ public class AlignCalcManager implements AlignCalcManagerI @Override public List getRegisteredWorkersOfClass( - Class workerClass) + Class workerClass) { List workingClass = new ArrayList(); - AlignCalcWorkerI[] workers; synchronized (canUpdate) { - workers = canUpdate.toArray(new AlignCalcWorkerI[canUpdate.size()]); - } - for (AlignCalcWorkerI worker : workers) - { - if (workerClass.equals(worker.getClass())) + for (AlignCalcWorkerI worker : canUpdate) { - workingClass.add(worker); + if (workerClass.equals(worker.getClass())) + { + workingClass.add(worker); + } } } return (workingClass.size() == 0) ? null : workingClass; } @Override - public boolean startRegisteredWorkersOfClass(Class workerClass) - { - List workers = getRegisteredWorkersOfClass(workerClass); - if (workers == null) - { - return false; - } - for (AlignCalcWorkerI worker : workers) - { - if (!isPending(worker)) - { - startWorker(worker); - } - else - { - System.err.println("Pending exists for " + workerClass); - } - } - return true; - } - - @Override - public void workerMayRun(AlignCalcWorkerI worker) + public void enableWorker(AlignCalcWorkerI worker) { synchronized (blackList) { - if (blackList.contains(worker.getClass())) - { - blackList.remove(worker.getClass()); - } + blackList.remove(worker.getClass()); } } @Override - public void removeRegisteredWorkersOfClass(Class typeToRemove) + public void removeRegisteredWorkersOfClass( + Class typeToRemove) { - List workers = getRegisteredWorkersOfClass(typeToRemove); List removable = new ArrayList(); Set toremovannot = new HashSet(); synchronized (restartable) @@ -382,4 +353,48 @@ public class AlignCalcManager implements AlignCalcManagerI * else { System.err.println("Pending exists for " + workerClass); } } */ } + + /** + * Deletes the worker that update the given annotation, provided it is marked + * as deletable. + */ + @Override + public void removeWorkerForAnnotation(AlignmentAnnotation ann) + { + /* + * first just find those to remove (to avoid + * ConcurrentModificationException) + */ + List toRemove = new ArrayList(); + for (AlignCalcWorkerI worker : restartable) + { + if (worker.involves(ann)) + { + if (worker.isDeletable()) + { + toRemove.add(worker); + } + } + } + + /* + * remove all references to deleted workers so any references + * they hold to annotation data can be garbage collected + */ + for (AlignCalcWorkerI worker : toRemove) + { + restartable.remove(worker); + blackList.remove(worker.getClass()); + inProgress.remove(worker); + canUpdate.remove(worker); + synchronized (updating) + { + List upd = updating.get(worker.getClass()); + if (upd != null) + { + upd.remove(worker); + } + } + } + } } diff --git a/src/jalview/workers/AlignCalcWorker.java b/src/jalview/workers/AlignCalcWorker.java index 48e3604..7719c88 100644 --- a/src/jalview/workers/AlignCalcWorker.java +++ b/src/jalview/workers/AlignCalcWorker.java @@ -97,4 +97,10 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI // TODO: allow GUI to query workers associated with annotation to add items to // annotation label panel popup menu + @Override + public boolean isDeletable() + { + return false; + } + } diff --git a/src/jalview/workers/AlignmentAnnotationFactory.java b/src/jalview/workers/AlignmentAnnotationFactory.java index 520b232..f804a19 100644 --- a/src/jalview/workers/AlignmentAnnotationFactory.java +++ b/src/jalview/workers/AlignmentAnnotationFactory.java @@ -1,5 +1,7 @@ package jalview.workers; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; import jalview.bin.Jalview; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; @@ -12,9 +14,9 @@ import java.awt.Color; * such as Groovy) to 'register and forget' an alignment annotation calculator.
* Currently supports two flavours of calculator: *
    - *
  • a 'feature counter' which can count any desired property derivable from + *
  • a simple 'feature counter' which counts any desired score derivable from * residue value and any sequence features at each position of the alignment
  • - *
  • a 'general purpose' calculator which computes one more complete + *
  • a 'general purpose' calculator which computes one or more complete * AlignmentAnnotation objects
  • *
*/ @@ -28,9 +30,13 @@ public class AlignmentAnnotationFactory */ public static void newCalculator(FeatureCounterI counter) { - if (Jalview.getCurrentAlignFrame() != null) + // TODO need an interface for AlignFrame by which to access + // its AlignViewportI and AlignmentViewPanel + AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame() ; + if (currentAlignFrame != null) { - newCalculator(Jalview.getCurrentAlignFrame(), counter); + newCalculator(currentAlignFrame.getViewport(), currentAlignFrame + .getAlignPanels().get(0), counter); } else { @@ -42,14 +48,15 @@ public class AlignmentAnnotationFactory /** * Constructs and registers a new alignment annotation worker * - * @param af - * the AlignFrame for which the annotation is to be calculated + * @param viewport + * @param panel * @param counter * provider of feature counts per alignment position */ - public static void newCalculator(AlignFrame af, FeatureCounterI counter) + public static void newCalculator(AlignViewportI viewport, + AlignmentViewPanel panel, FeatureCounterI counter) { - new ColumnCounterWorker(af, counter); + new ColumnCounterWorker(viewport, panel, counter); } /** @@ -60,9 +67,13 @@ public class AlignmentAnnotationFactory */ public static void newCalculator(AnnotationProviderI calculator) { - if (Jalview.getCurrentAlignFrame() != null) + // TODO need an interface for AlignFrame by which to access + // its AlignViewportI and AlignmentViewPanel + AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame() ; + if (currentAlignFrame != null) { - newCalculator(Jalview.getCurrentAlignFrame(), calculator); + newCalculator(currentAlignFrame.getViewport(), currentAlignFrame + .getAlignPanels().get(0), calculator); } else { @@ -74,15 +85,16 @@ public class AlignmentAnnotationFactory /** * Constructs and registers a new alignment annotation worker * - * @param af - * the AlignFrame for which the annotation is to be calculated + * @param viewport + * @param panel * @param calculator * provider of AlignmentAnnotation for the alignment */ - public static void newCalculator(AlignFrame af, + public static void newCalculator(AlignViewportI viewport, + AlignmentViewPanel panel, AnnotationProviderI calculator) { - new AnnotationWorker(af, calculator); + new AnnotationWorker(viewport, panel, calculator); } /** diff --git a/src/jalview/workers/AnnotationProviderI.java b/src/jalview/workers/AnnotationProviderI.java index 653ff04..bd24461 100644 --- a/src/jalview/workers/AnnotationProviderI.java +++ b/src/jalview/workers/AnnotationProviderI.java @@ -1,8 +1,8 @@ package jalview.workers; +import jalview.api.FeatureRenderer; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; -import jalview.gui.FeatureRenderer; import java.util.List; diff --git a/src/jalview/workers/AnnotationWorker.java b/src/jalview/workers/AnnotationWorker.java index fbf7531..efe707a 100644 --- a/src/jalview/workers/AnnotationWorker.java +++ b/src/jalview/workers/AnnotationWorker.java @@ -20,19 +20,19 @@ */ package jalview.workers; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; -import jalview.gui.AlignFrame; -import jalview.gui.AlignmentPanel; -import jalview.gui.FeatureRenderer; +import jalview.renderer.seqfeatures.FeatureRenderer; import java.util.ArrayList; import java.util.List; /** * A class to create and update one or more alignment annotations, given a - * 'calculator'. - * + * 'calculator'. Intended to support a 'plug-in' annotation worker which + * implements the AnnotationProviderI interface. */ class AnnotationWorker extends AlignCalcWorker { @@ -47,9 +47,10 @@ class AnnotationWorker extends AlignCalcWorker * @param af * @param counter */ - public AnnotationWorker(AlignFrame af, AnnotationProviderI counter) + public AnnotationWorker(AlignViewportI viewport, + AlignmentViewPanel panel, AnnotationProviderI counter) { - super(af.getViewport(), af.alignPanel); + super(viewport, panel); ourAnnots = new ArrayList(); this.counter = counter; calcMan.registerWorker(this); @@ -85,7 +86,7 @@ class AnnotationWorker extends AlignCalcWorker try { List anns = counter.calculateAnnotation( - alignment, new FeatureRenderer((AlignmentPanel) ap)); + alignment, new FeatureRenderer(alignViewport)); for (AlignmentAnnotation ann : anns) { ann.showAllColLabels = true; @@ -102,7 +103,7 @@ class AnnotationWorker extends AlignCalcWorker } catch (OutOfMemoryError error) { ap.raiseOOMWarning("calculating annotations", error); - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); } finally { calcMan.workerComplete(this); @@ -133,4 +134,15 @@ class AnnotationWorker extends AlignCalcWorker { // do nothing } + + /** + * Answers true to indicate that if this worker's annotation is deleted from + * the display, the worker should also be removed. This prevents it running + * and recreating the annotation when the alignment changes. + */ + @Override + public boolean isDeletable() + { + return true; + } } diff --git a/src/jalview/workers/ColumnCounterWorker.java b/src/jalview/workers/ColumnCounterWorker.java index 6f4a4f3..5f61525 100644 --- a/src/jalview/workers/ColumnCounterWorker.java +++ b/src/jalview/workers/ColumnCounterWorker.java @@ -20,14 +20,14 @@ */ package jalview.workers; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; -import jalview.gui.AlignFrame; -import jalview.gui.AlignmentPanel; -import jalview.gui.FeatureRenderer; +import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.util.ColorUtils; import jalview.util.Comparison; @@ -53,9 +53,10 @@ class ColumnCounterWorker extends AlignCalcWorker * @param af * @param counter */ - public ColumnCounterWorker(AlignFrame af, FeatureCounterI counter) + public ColumnCounterWorker(AlignViewportI viewport, + AlignmentViewPanel panel, FeatureCounterI counter) { - super(af.getViewport(), af.alignPanel); + super(viewport, panel); ourAnnots = new ArrayList(); this.counter = counter; calcMan.registerWorker(this); @@ -103,7 +104,7 @@ class ColumnCounterWorker extends AlignCalcWorker } catch (OutOfMemoryError error) { ap.raiseOOMWarning("calculating feature counts", error); - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); } finally { calcMan.workerComplete(this); @@ -123,7 +124,7 @@ class ColumnCounterWorker extends AlignCalcWorker */ void computeAnnotations() { - FeatureRenderer fr = new FeatureRenderer((AlignmentPanel) ap); + FeatureRenderer fr = new FeatureRenderer(alignViewport); // TODO use the commented out code once JAL-2075 is fixed // to get adequate performance on genomic length sequence AlignmentI alignment = alignViewport.getAlignment(); @@ -169,6 +170,7 @@ class ColumnCounterWorker extends AlignCalcWorker AlignmentAnnotation ann = new AlignmentAnnotation(counter.getName(), counter.getDescription(), anns); ann.showAllColLabels = true; + ann.scaleColLabel = true; ann.graph = AlignmentAnnotation.BAR_GRAPH; ourAnnots.add(ann); alignViewport.getAlignment().addAnnotation(ann); @@ -222,4 +224,15 @@ class ColumnCounterWorker extends AlignCalcWorker { // do nothing } + + /** + * Answers true to indicate that if this worker's annotation is deleted from + * the display, the worker should also be removed. This prevents it running + * and recreating the annotation when the alignment changes. + */ + @Override + public boolean isDeletable() + { + return true; + } } diff --git a/src/jalview/workers/ConsensusThread.java b/src/jalview/workers/ConsensusThread.java index 14e2a31..5f0ec84 100644 --- a/src/jalview/workers/ConsensusThread.java +++ b/src/jalview/workers/ConsensusThread.java @@ -96,7 +96,7 @@ public class ConsensusThread extends AlignCalcWorker } } catch (OutOfMemoryError error) { - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); ap.raiseOOMWarning("calculating consensus", error); } finally { diff --git a/src/jalview/workers/ConservationThread.java b/src/jalview/workers/ConservationThread.java index 1075e4d..5c303fd 100644 --- a/src/jalview/workers/ConservationThread.java +++ b/src/jalview/workers/ConservationThread.java @@ -108,7 +108,7 @@ public class ConservationThread extends AlignCalcWorker } catch (OutOfMemoryError error) { ap.raiseOOMWarning("calculating conservation", error); - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); // alignViewport.conservation = null; // this.alignViewport.quality = null; diff --git a/src/jalview/workers/StrucConsensusThread.java b/src/jalview/workers/StrucConsensusThread.java index 4249112..5ed2885 100644 --- a/src/jalview/workers/StrucConsensusThread.java +++ b/src/jalview/workers/StrucConsensusThread.java @@ -129,7 +129,7 @@ public class StrucConsensusThread extends AlignCalcWorker updateResultAnnotation(true); } catch (OutOfMemoryError error) { - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); // consensus = null; // hconsensus = null; diff --git a/src/jalview/ws/jws2/AbstractJabaCalcWorker.java b/src/jalview/ws/jws2/AbstractJabaCalcWorker.java index 897aa1e..b33df0c 100644 --- a/src/jalview/ws/jws2/AbstractJabaCalcWorker.java +++ b/src/jalview/ws/jws2/AbstractJabaCalcWorker.java @@ -331,23 +331,23 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker System.err.println("submission error with " + getServiceActionText() + " :"); x.printStackTrace(); - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); } catch (ResultNotAvailableException x) { System.err.println("collection error:\nJob ID: " + rslt); x.printStackTrace(); - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); } catch (OutOfMemoryError error) { - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); // consensus = null; // hconsensus = null; ap.raiseOOMWarning(getServiceActionText(), error); } catch (Exception x) { - calcMan.workerCannotRun(this); + calcMan.disableWorker(this); // consensus = null; // hconsensus = null; diff --git a/src/jalview/ws/jws2/SequenceAnnotationWSClient.java b/src/jalview/ws/jws2/SequenceAnnotationWSClient.java index 187540c..2af31bb 100644 --- a/src/jalview/ws/jws2/SequenceAnnotationWSClient.java +++ b/src/jalview/ws/jws2/SequenceAnnotationWSClient.java @@ -122,7 +122,7 @@ public class SequenceAnnotationWSClient extends Jws2Client } // reinstate worker if it was blacklisted (might have happened due to // invalid parameters) - alignFrame.getViewport().getCalcManager().workerMayRun(worker); + alignFrame.getViewport().getCalcManager().enableWorker(worker); worker.updateParameters(this.preset, paramset); } } diff --git a/test/jalview/datamodel/AlignmentTest.java b/test/jalview/datamodel/AlignmentTest.java index 07b8abf..b75ef50 100644 --- a/test/jalview/datamodel/AlignmentTest.java +++ b/test/jalview/datamodel/AlignmentTest.java @@ -232,7 +232,7 @@ public class AlignmentTest * Realign DNA; currently keeping existing gaps in introns only */ ((Alignment) al1).alignAs(al2, false, true); - assertEquals("ACG---GCUCCA------ACT", al1.getSequenceAt(0) + assertEquals("ACG---GCUCCA------ACT---", al1.getSequenceAt(0) .getSequenceAsString()); assertEquals("---CGT---TAACGA---AGT---", al1.getSequenceAt(1) .getSequenceAsString()); diff --git a/test/jalview/workers/AlignCalcManagerTest.java b/test/jalview/workers/AlignCalcManagerTest.java new file mode 100644 index 0000000..735c75d --- /dev/null +++ b/test/jalview/workers/AlignCalcManagerTest.java @@ -0,0 +1,147 @@ +package jalview.workers; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import jalview.api.AlignCalcManagerI; +import jalview.api.AlignCalcWorkerI; +import jalview.api.FeatureRenderer; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Annotation; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; + +import java.util.Collections; +import java.util.List; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class AlignCalcManagerTest +{ + private AlignFrame alignFrame; + + /** + * Test the method that removes a worker associated with an annotation, + * provided the worker is marked as 'deletable' (some workers should continue + * to run even when their results are no longer displayed) + */ + @Test(groups = "Functional") + public void testRemoveWorkerForAnnotation() + { + AlignCalcManagerI acm = alignFrame.getViewport().getCalcManager(); + final AlignmentAnnotation ann1 = new AlignmentAnnotation("Ann1", + "desc", + new Annotation[] {}); + final AlignmentAnnotation ann2 = new AlignmentAnnotation("Ann2", + "desc", + new Annotation[] {}); + + /* + * make two workers for ann1, one deletable, one not + * and no worker for ann2 + */ + AlignCalcWorkerI worker1 = makeWorker(ann1, true); + AlignCalcWorkerI worker2 = makeWorker(ann1, false); + + /* + * The new workers will get run each in their own thread. + * We can't tell here whether they have finished, or not yet started. + * They have to finish to be 'seen' by getRegisteredWorkersOfClass() + * registerWorker adds to the 'restartable' list but + * getRegisteredWorkers reads from the 'canUpdate' list + * (which is only updated after a worker has run) - why? + * So just give workers time to start and finish + */ + synchronized (this) + { + try + { + wait(100); + } catch (InterruptedException e) + { + // + } + } + + List workers = acm.getRegisteredWorkersOfClass(worker1.getClass()); + assertEquals(2, workers.size()); + assertTrue(workers.contains(worker1)); + assertTrue(workers.contains(worker2)); + assertFalse(acm.isDisabled(worker1)); + assertFalse(acm.isDisabled(worker2)); + + /* + * remove workers for ann2 (there aren't any) + */ + acm.removeWorkerForAnnotation(ann2); + assertTrue(acm.getRegisteredWorkersOfClass(worker1.getClass()) + .contains(worker1)); + assertTrue(acm.getRegisteredWorkersOfClass(worker1.getClass()) + .contains(worker2)); + assertFalse(acm.isDisabled(worker1)); + assertFalse(acm.isDisabled(worker2)); + + /* + * remove worker2 for ann1 + * - should delete worker1 but not worker2 + */ + acm.removeWorkerForAnnotation(ann1); + assertEquals(1, acm.getRegisteredWorkersOfClass(worker1.getClass()) + .size()); + assertTrue(acm.getRegisteredWorkersOfClass(worker1.getClass()) + .contains(worker2)); + assertFalse(acm.isDisabled(worker1)); + assertFalse(acm.isDisabled(worker2)); + } + + /** + * Make a worker linked to the given annotation + * + * @param ann + * @param deletable + * @return + */ + AnnotationWorker makeWorker(final AlignmentAnnotation ann, + final boolean deletable) + { + AnnotationProviderI annotationProvider = new AnnotationProviderI() + { + @Override + public List calculateAnnotation(AlignmentI al, + FeatureRenderer fr) + { + return Collections.singletonList(ann); + } + }; + return new AnnotationWorker(alignFrame.getViewport(), + alignFrame.alignPanel, + annotationProvider) + { + @Override + public boolean isDeletable() + { + return deletable; + } + + @Override + public boolean involves(AlignmentAnnotation ann1) + { + return ann == ann1; + } + }; + } + + @BeforeMethod(alwaysRun = true) + public void setUp() + { + AlignmentI al = new Alignment(new SequenceI[] { new Sequence("Seq1", + "ABC") }); + al.setDataset(null); + alignFrame = new AlignFrame(al, 3, 1); + } +}