From c9f31322ad542be7fab91e0c9f2ff3638a25c5b1 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Fri, 6 Feb 2015 14:12:19 +0000 Subject: [PATCH] JAL-845 further code/tests/refactoring --- resources/lang/Messages.properties | 2 + src/jalview/datamodel/Alignment.java | 56 ++++++-- src/jalview/datamodel/AlignmentI.java | 14 ++ src/jalview/gui/AlignFrame.java | 216 +++++++++++++++++------------ src/jalview/gui/AlignViewport.java | 21 ++- src/jalview/gui/AlignmentPanel.java | 6 +- src/jalview/gui/Desktop.java | 35 ++--- src/jalview/gui/Jalview2XML.java | 41 +++--- src/jalview/gui/JvSwingUtils.java | 48 +++++++ src/jalview/gui/PaintRefresher.java | 100 ++++++------- src/jalview/gui/SplitFrame.java | 56 +++++++- src/jalview/jbgui/GAlignFrame.java | 6 +- src/jalview/util/StringUtils.java | 24 ++++ test/jalview/datamodel/AlignmentTest.java | 71 +++++----- test/jalview/gui/JvSwingUtilsTest.java | 41 ++++++ test/jalview/gui/PaintRefresherTest.java | 115 +++++++++++++++ test/jalview/util/StringUtilsTest.java | 15 ++ 17 files changed, 624 insertions(+), 243 deletions(-) create mode 100644 test/jalview/gui/JvSwingUtilsTest.java create mode 100644 test/jalview/gui/PaintRefresherTest.java diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 0d67dac..de4ceb5 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -380,6 +380,7 @@ label.automatically_associate_pdb_files_with_sequences_same_name = Do you want t label.automatically_associate_pdb_files_by_name = Automatically Associate PDB files by name label.ignore_unmatched_dropped_files_info = Do you want to ignore the {0} files whose names did not match any sequence IDs ? label.ignore_unmatched_dropped_files = Ignore unmatched dropped files? +label.view_name_original = Original label.enter_view_name = Enter View Name label.enter_label = Enter label label.enter_label_for_the_structure = Enter a label for the structure? @@ -699,6 +700,7 @@ label.align_cdna_tip = Any linked cDNA sequences will be realigned to match this label.cdna_aligned = {0} sequences in {1} alignments were realigned label.view_as_cdna = Show aligned cDNA label.view_as_cdna_tip = Open a new alignment of the related cDNA sequences +label.linked_view_title = {0} and {1} label.align = Align label.extract_scores = Extract Scores label.get_cross_refs = Get Cross References diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index f660697..5b41c1d 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -67,6 +67,8 @@ public class Alignment implements AlignmentI public Hashtable alignmentProperties; + private Set codonFrameList = new LinkedHashSet(); + private void initAlignment(SequenceI[] seqs) { int i = 0; @@ -101,6 +103,13 @@ public class Alignment implements AlignmentI { seqs[i] = new Sequence(seqs[i]); } + + /* + * Share the same dataset sequence mappings (if any). TODO: find a better + * place for these to live (alignment dataset?). + */ + this.codonFrameList = ((Alignment) al).codonFrameList; + initAlignment(seqs); } @@ -142,11 +151,6 @@ public class Alignment implements AlignmentI // this(compactAlignment.refCigars); } - /** - * DOCUMENT ME! - * - * @return DOCUMENT ME! - */ @Override public List getSequences() { @@ -749,6 +753,28 @@ public class Alignment implements AlignmentI return true; } + /** + * Delete all annotations, including auto-calculated if the flag is set true. + * Returns true if at least one annotation was deleted, else false. + * + * @param includingAutoCalculated + * @return + */ + @Override + public boolean deleteAllAnnotations(boolean includingAutoCalculated) + { + boolean result = false; + for (AlignmentAnnotation alan : getAlignmentAnnotation()) + { + if (!alan.autoCalculated || includingAutoCalculated) + { + deleteAnnotation(alan); + result = true; + } + } + return result; + } + /* * (non-Javadoc) * @@ -1234,10 +1260,6 @@ public class Alignment implements AlignmentI return alignmentProperties; } - // AlignedCodonFrame[] codonFrameList = null; - - LinkedHashSet codonFrameList = new LinkedHashSet(); - /* * (non-Javadoc) * @@ -1278,8 +1300,20 @@ public class Alignment implements AlignmentI return cframes; } - /* - * (non-Javadoc) + /** + * Sets the codon frame mappings (replacing any existing mappings). + * + * @see jalview.datamodel.AlignmentI#setCodonFrames() + */ + @Override + public void setCodonFrames(Set acfs) + { + this.codonFrameList = acfs; + } + + /** + * Returns the set of codon frame mappings. Any changes to the returned set + * will affect the alignment. * * @see jalview.datamodel.AlignmentI#getCodonFrames() */ diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index ac2596a..fe93683 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -219,6 +219,15 @@ public interface AlignmentI extends AnnotatedCollectionI void setAnnotationIndex(AlignmentAnnotation aa, int index); /** + * Delete all annotations, including auto-calculated if the flag is set true. + * Returns true if at least one annotation was deleted, else false. + * + * @param includingAutoCalculated + * @return + */ + boolean deleteAllAnnotations(boolean includingAutoCalculated); + + /** * Deletes a specific AlignmentAnnotation from the alignment, and removes its * reference from any SequenceI or SequenceGroup object's annotation if and * only if aa is contained within the alignment's annotation vector. @@ -369,6 +378,11 @@ public interface AlignmentI extends AnnotatedCollectionI Set getCodonFrames(); /** + * Set the codon frame mappings (replacing any existing set). + */ + void setCodonFrames(Set acfs); + + /** * get codon frames involving sequenceI */ List getCodonFrame(SequenceI seq); diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 14a5de3..47f1c2a 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -152,12 +152,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, IProgressIndicator, AlignViewControllerGuiI { - /** DOCUMENT ME!! */ public static final int DEFAULT_WIDTH = 700; - /** DOCUMENT ME!! */ public static final int DEFAULT_HEIGHT = 500; + /* + * The currently displayed panel (selected tabbed view if more than one) + */ public AlignmentPanel alignPanel; AlignViewport viewport; @@ -1663,16 +1664,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { EditCommand editCommand = (EditCommand) command; al = editCommand.getAlignment(); - Vector comps = (Vector) PaintRefresher.components.get(viewport + List comps = PaintRefresher.components.get(viewport .getSequenceSetId()); - for (int i = 0; i < comps.size(); i++) + for (Component comp : comps) { - if (comps.elementAt(i) instanceof AlignmentPanel) + if (comp instanceof AlignmentPanel) { - if (al == ((AlignmentPanel) comps.elementAt(i)).av.getAlignment()) + if (al == ((AlignmentPanel) comp).av.getAlignment()) { - originalSource = ((AlignmentPanel) comps.elementAt(i)).av; + originalSource = ((AlignmentPanel) comp).av; break; } } @@ -2705,71 +2706,99 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void newView_actionPerformed(ActionEvent e) { - newView(true); - } + /* + * Note if the current view has a protein/cdna complementary view + */ + AlignViewportI linkedView = this.viewport.getCodingComplement(); - /** - * - * @param copyAnnotation - * if true then duplicate all annnotation, groups and settings - * @return new alignment panel, already displayed. - */ - public AlignmentPanel newView(boolean copyAnnotation) - { - return newView(null, copyAnnotation); - } + AlignmentPanel newPanel = newView(null, true); - /** - * - * @param viewTitle - * title of newly created view - * @return new alignment panel, already displayed. - */ - public AlignmentPanel newView(String viewTitle) - { - return newView(viewTitle, true); + /* + * If the original view has a protein/cdna linked view, make and link a new + * view there also. + */ + // TODO refactor the hell out of this - move to a controller, lose the casts + // and direct member access, etc + if (linkedView != null) + { + AlignFrame linkedAlignFrame = ((AlignViewport) linkedView) + .getAlignPanel().alignFrame; + AlignmentPanel newLinkedPanel = linkedAlignFrame.newView(null, true); + newLinkedPanel.av.viewName = newPanel.av.viewName; + newPanel.av.setCodingComplement(newLinkedPanel.av); + final StructureSelectionManager ssm = StructureSelectionManager + .getStructureSelectionManager(Desktop.instance); + ssm.addCommandListener(newPanel.av); + ssm.addCommandListener(newLinkedPanel.av); + + } } /** + * Creates and shows a new view of the current alignment. * * @param viewTitle - * title of newly created view + * title of newly created view; if null, one will be generated * @param copyAnnotation * if true then duplicate all annnotation, groups and settings * @return new alignment panel, already displayed. */ public AlignmentPanel newView(String viewTitle, boolean copyAnnotation) { + /* + * Create a new AlignmentPanel (with its own, new Viewport) + */ AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel, true); if (!copyAnnotation) { - // just remove all the current annotation except for the automatic stuff + /* + * remove all groups and annotation except for the automatic stuff + */ newap.av.getAlignment().deleteAllGroups(); - for (AlignmentAnnotation alan : newap.av.getAlignment() - .getAlignmentAnnotation()) - { - if (!alan.autoCalculated) - { - newap.av.getAlignment().deleteAnnotation(alan); - } - ; - } + newap.av.getAlignment().deleteAllAnnotations(false); } newap.av.gatherViewsHere = false; if (viewport.viewName == null) { - viewport.viewName = "Original"; + viewport.viewName = MessageManager + .getString("label.view_name_original"); } + /* + * Views share the same edits, undo and redo stacks, mappings. + */ newap.av.setHistoryList(viewport.getHistoryList()); newap.av.setRedoList(viewport.getRedoList()); + newap.av.getAlignment().setCodonFrames( + viewport.getAlignment().getCodonFrames()); + + newap.av.viewName = getNewViewName(viewTitle); + + addAlignmentPanel(newap, true); + newap.alignmentChanged(); + + if (alignPanels.size() == 2) + { + viewport.gatherViewsHere = true; + } + tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); + return newap; + } + /** + * Make a new name for the view, ensuring it is unique within the current + * sequenceSetId. (This used to be essential for Jalview Project archives, but + * these now use viewId. Unique view names are still desirable for usability.) + * + * @param viewTitle + * @return + */ + protected String getNewViewName(String viewTitle) + { int index = Desktop.getViewCount(viewport.getSequenceSetId()); - // make sure the new view has a unique name - this is essential for Jalview - // 2 archives boolean addFirstIndex = false; if (viewTitle == null || viewTitle.trim().length() == 0) { @@ -2781,45 +2810,55 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, index = 1;// we count from 1 if given a specific name } String newViewName = viewTitle + ((addFirstIndex) ? " " + index : ""); - Vector comps = (Vector) PaintRefresher.components.get(viewport + + List comps = PaintRefresher.components.get(viewport .getSequenceSetId()); - Vector existingNames = new Vector(); - for (int i = 0; i < comps.size(); i++) - { - if (comps.elementAt(i) instanceof AlignmentPanel) - { - AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i); - if (!existingNames.contains(ap.av.viewName)) - { - existingNames.addElement(ap.av.viewName); - } - } - } + + List existingNames = getExistingViewNames(comps); while (existingNames.contains(newViewName)) { newViewName = viewTitle + " " + (++index); } + return newViewName; + } - newap.av.viewName = newViewName; - - addAlignmentPanel(newap, true); - newap.alignmentChanged(); - - if (alignPanels.size() == 2) + /** + * Returns a list of distinct view names found in the given list of + * components. View names are held on the viewport of an AlignmentPanel. + * + * @param comps + * @return + */ + protected List getExistingViewNames(List comps) + { + List existingNames = new ArrayList(); + for (Component comp : comps) { - viewport.gatherViewsHere = true; + if (comp instanceof AlignmentPanel) + { + AlignmentPanel ap = (AlignmentPanel) comp; + if (!existingNames.contains(ap.av.viewName)) + { + existingNames.add(ap.av.viewName); + } + } } - tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1); - return newap; + return existingNames; } + /** + * Explode tabbed views into separate windows. + */ @Override public void expandViews_actionPerformed(ActionEvent e) { Desktop.instance.explodeViews(this); } + /** + * Gather views in separate windows back into a tabbed presentation. + */ @Override public void gatherViews_actionPerformed(ActionEvent e) { @@ -3657,8 +3696,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { Component[] menuItems = colourMenu.getMenuComponents(); - int i, iSize = menuItems.length; - for (i = 0; i < iSize; i++) + int iSize = menuItems.length; + for (int i = 0; i < iSize; i++) { if (menuItems[i].getName() != null && menuItems[i].getName().equals("USER_DEFINED")) @@ -3919,7 +3958,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e) { - NewTreePanel("AV", "PID", "Average distance tree using PID"); + newTreePanel("AV", "PID", "Average distance tree using PID"); } /** @@ -3931,7 +3970,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void neighbourTreeMenuItem_actionPerformed(ActionEvent e) { - NewTreePanel("NJ", "PID", "Neighbour joining tree using PID"); + newTreePanel("NJ", "PID", "Neighbour joining tree using PID"); } /** @@ -3943,7 +3982,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e) { - NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62"); + newTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62"); } /** @@ -3955,7 +3994,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e) { - NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62"); + newTreePanel("AV", "BL", "Average distance tree using BLOSUM62"); } /** @@ -3968,7 +4007,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * @param title * DOCUMENT ME! */ - void NewTreePanel(String type, String pwType, String title) + void newTreePanel(String type, String pwType, String title) { TreePanel tp; @@ -4183,7 +4222,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { String treecalcnm = MessageManager.getString("label.tree_calc_" + type.toLowerCase()); - for (final Object pwtype : ResidueProperties.scoreMatrices.keySet()) + for (final String pwtype : ResidueProperties.scoreMatrices.keySet()) { JMenuItem tm = new JMenuItem(); ScoreModelI sm = ResidueProperties.scoreMatrices.get(pwtype); @@ -4199,7 +4238,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void actionPerformed(ActionEvent e) { - NewTreePanel(type, (String) pwtype, title); + newTreePanel(type, pwtype, title); } }); calculateTree.add(tm); @@ -4209,21 +4248,18 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } sortByTreeMenu.removeAll(); - Vector comps = (Vector) PaintRefresher.components.get(viewport + List comps = PaintRefresher.components.get(viewport .getSequenceSetId()); - Vector treePanels = new Vector(); - int i, iSize = comps.size(); - for (i = 0; i < iSize; i++) + List treePanels = new ArrayList(); + for (Component comp : comps) { - if (comps.elementAt(i) instanceof TreePanel) + if (comp instanceof TreePanel) { - treePanels.add(comps.elementAt(i)); + treePanels.add((TreePanel) comp); } } - iSize = treePanels.size(); - - if (iSize < 1) + if (treePanels.size() < 1) { sortByTreeMenu.setVisible(false); return; @@ -4231,9 +4267,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, sortByTreeMenu.setVisible(true); - for (i = 0; i < treePanels.size(); i++) + for (final TreePanel tp : treePanels) { - final TreePanel tp = (TreePanel) treePanels.elementAt(i); final JMenuItem item = new JMenuItem(tp.getTitle()); item.addActionListener(new java.awt.event.ActionListener() { @@ -5330,6 +5365,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } } + /** + * Method invoked by the ChangeListener on the tabbed pane, in other words + * when a different tabbed pane is selected by the user or programmatically. + */ @Override public void tabSelectionChanged(int index) { @@ -5342,19 +5381,22 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } } + /** + * On right mouse click on view tab, prompt for and set new view name. + */ @Override public void tabbedPane_mousePressed(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e)) { - String reply = JOptionPane.showInternalInputDialog(this, - MessageManager.getString("label.enter_view_name"), - MessageManager.getString("label.enter_view_name"), + String msg = MessageManager.getString("label.enter_view_name"); + String reply = JOptionPane.showInternalInputDialog(this, msg, msg, JOptionPane.QUESTION_MESSAGE); if (reply != null) { viewport.viewName = reply; + // TODO warn if reply is in getExistingViewNames()? tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply); } } diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 5a9fa6b..676d180 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -59,6 +59,7 @@ import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; import jalview.util.MessageManager; +import jalview.util.StringUtils; import jalview.viewmodel.AlignmentViewport; import jalview.ws.params.AutoCalcSetting; @@ -1146,7 +1147,6 @@ public class AlignViewport extends AlignmentViewport implements { AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(this .getSequenceSetId()); - AlignmentPanel ap = null; for (int p = 0; aps != null && p < aps.length; p++) { if (aps[p].av == this) @@ -1498,6 +1498,7 @@ public class AlignViewport extends AlignmentViewport implements */ AlignFrame newAlignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + newAlignFrame.setTitle(title); /* * Identify protein and dna alignments. Make a copy of this one if opening @@ -1570,27 +1571,35 @@ public class AlignViewport extends AlignmentViewport implements */ AlignFrame copyMe = new AlignFrame(thisAlignment, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - copyMe.setTitle(""); // TODO would like this AlignFrame.title here + copyMe.setTitle(getAlignPanel().alignFrame.getTitle()); final AlignFrame proteinFrame = al.isNucleotide() ? copyMe : newAlignFrame; final AlignFrame cdnaFrame = al.isNucleotide() ? newAlignFrame : copyMe; - newAlignFrame.setTitle(title); cdnaFrame.setVisible(true); proteinFrame.setVisible(true); + String proteinShortName = StringUtils.getLastToken( + proteinFrame.getTitle(), "/"); + String dnaShortName = StringUtils.getLastToken(cdnaFrame.getTitle(), + "/"); + String linkedTitle = MessageManager.formatMessage( + "label.linked_view_title", dnaShortName, proteinShortName); JInternalFrame splitFrame = new SplitFrame(cdnaFrame, proteinFrame); - Desktop.addInternalFrame(splitFrame, title, AlignFrame.DEFAULT_WIDTH, + Desktop.addInternalFrame(splitFrame, linkedTitle, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); /* - * Set the frames to list for each other's edit and sort commands. + * Set the frames to listen for each other's edit and sort commands. */ ssm.addCommandListener(cdnaFrame.getViewport()); ssm.addCommandListener(proteinFrame.getViewport()); /* - * cDNA view will mirror edits, selection, sorting, show/hide on protein + * 'Coding complement' (dna/protein) views will mirror each others' edits, + * selections, sorting etc as decided from time to time by the relevant + * authorities. */ proteinFrame.getViewport().setCodingComplement(cdnaFrame.getViewport()); } diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index fc36ebb..4bf350b 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -92,9 +92,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * Creates a new AlignmentPanel object. * * @param af - * DOCUMENT ME! * @param av - * DOCUMENT ME! */ public AlignmentPanel(AlignFrame af, final AlignViewport av) { @@ -650,7 +648,6 @@ public class AlignmentPanel extends GAlignmentPanel implements */ public void adjustmentValueChanged(AdjustmentEvent evt) { - int oldX = av.getStartRes(); int oldY = av.getStartSeq(); @@ -1147,8 +1144,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (alignFrame != null && !headless) { alignFrame.setProgressBar(MessageManager.formatMessage( - "status.saving_file", - new String[] + "status.saving_file", new Object[] { type.getLabel() }), progress); } try diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 512c418..c0f4949 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -1687,41 +1687,34 @@ public class Desktop extends jalview.jbgui.GDesktop implements */ public static AlignmentViewport[] getViewports(String sequenceSetId) { - Vector viewp = new Vector(); + List viewp = new ArrayList(); if (desktop != null) { - javax.swing.JInternalFrame[] frames = instance.getAllFrames(); + AlignFrame[] frames = Desktop.getAlignFrames(); - for (int t = 0; t < frames.length; t++) + for (AlignFrame afr : frames) { - if (frames[t] instanceof AlignFrame) + if (afr.getViewport().getSequenceSetId().equals(sequenceSetId)) { - AlignFrame afr = ((AlignFrame) frames[t]); - if (afr.getViewport().getSequenceSetId().equals(sequenceSetId)) + if (afr.alignPanels != null) { - if (afr.alignPanels != null) + for (AlignmentPanel ap : afr.alignPanels) { - for (int a = 0; a < afr.alignPanels.size(); a++) + if (sequenceSetId.equals(ap.av.getSequenceSetId())) { - if (sequenceSetId.equals(afr.alignPanels.get(a).av - .getSequenceSetId())) - { - viewp.addElement(afr.alignPanels.get(a).av); - } + viewp.add(ap.av); } } - else - { - viewp.addElement(((AlignFrame) frames[t]).getViewport()); - } + } + else + { + viewp.add(afr.getViewport()); } } } if (viewp.size() > 0) { - AlignmentViewport[] vp = new AlignmentViewport[viewp.size()]; - viewp.copyInto(vp); - return vp; + return viewp.toArray(new AlignmentViewport[viewp.size()]); } } return null; @@ -2279,6 +2272,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements /** * Accessor method to quickly get all the AlignmentFrames loaded. + * + * @return an array of AlignFrame, or null if none found */ public static AlignFrame[] getAlignFrames() { diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index f08306a..4fb0fe8 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -92,11 +92,13 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.StringTokenizer; @@ -182,7 +184,7 @@ public class Jalview2XML } if (seqRefIds == null) { - seqRefIds = new Hashtable(); + seqRefIds = new HashMap(); } } @@ -197,8 +199,12 @@ public class Jalview2XML * and alignment sequences. Populated as XML reps of sequence objects are * created.) */ - java.util.Hashtable seqRefIds = null; // key->SequenceI resolution + Map seqRefIds = null; // key->SequenceI resolution + /* + * Forward referenced sequences - a holding place for cross-references pending + * resolution. + */ Vector frefedSequence = null; boolean raiseGUI = true; // whether errors are raised in dialog boxes or not @@ -227,7 +233,7 @@ public class Jalview2XML { if (ref[1] instanceof jalview.datamodel.Mapping) { - SequenceI seq = (SequenceI) seqRefIds.get(sref); + SequenceI seq = seqRefIds.get(sref); while (seq.getDatasetSequence() != null) { seq = seq.getDatasetSequence(); @@ -238,7 +244,7 @@ public class Jalview2XML { if (ref[1] instanceof jalview.datamodel.AlignedCodonFrame) { - SequenceI seq = (SequenceI) seqRefIds.get(sref); + SequenceI seq = seqRefIds.get(sref); while (seq.getDatasetSequence() != null) { seq = seq.getDatasetSequence(); @@ -1944,7 +1950,7 @@ public class Jalview2XML } if (seqRefIds == null) { - seqRefIds = new Hashtable(); + seqRefIds = new HashMap(); } if (viewportsAdded == null) { @@ -2384,7 +2390,7 @@ public class Jalview2XML AlcodMap[] maps = alc[i].getAlcodMap(); for (int m = 0; m < maps.length; m++) { - SequenceI dnaseq = (SequenceI) seqRefIds + SequenceI dnaseq = seqRefIds .get(maps[m].getDnasq()); // Load Mapping jalview.datamodel.Mapping mapping = null; @@ -2662,7 +2668,7 @@ public class Jalview2XML for (int s = 0; s < groups[i].getSeqCount(); s++) { String seqId = groups[i].getSeq(s) + ""; - jalview.datamodel.SequenceI ts = (jalview.datamodel.SequenceI) seqRefIds + jalview.datamodel.SequenceI ts = seqRefIds .get(seqId); if (ts != null) @@ -2952,7 +2958,7 @@ public class Jalview2XML // Desktop.desktop.getComponentAt(x, y); // TODO: NOW: check that this recovers the PDB file correctly. String pdbFile = loadPDBFile(jprovider, ids[p].getId()); - jalview.datamodel.SequenceI seq = (jalview.datamodel.SequenceI) seqRefIds + jalview.datamodel.SequenceI seq = seqRefIds .get(JSEQ[i].getId() + ""); if (sviewid == null) { @@ -3994,9 +4000,8 @@ public class Jalview2XML { // JBP TODO: Check this is called for AlCodonFrames to support recovery of // xRef Codon Maps - jalview.datamodel.Sequence sq = (jalview.datamodel.Sequence) seqRefIds - .get(vamsasSeq.getId()); - jalview.datamodel.SequenceI dsq = null; + SequenceI sq = seqRefIds.get(vamsasSeq.getId()); + SequenceI dsq = null; if (sq != null && sq.getDatasetSequence() != null) { dsq = sq.getDatasetSequence(); @@ -4011,7 +4016,7 @@ public class Jalview2XML // need to create or add a new dataset sequence reference to this sequence if (sqid != null) { - dsq = (jalview.datamodel.SequenceI) seqRefIds.get(sqid); + dsq = seqRefIds.get(sqid); } // check again if (dsq == null) @@ -4207,7 +4212,7 @@ public class Jalview2XML /** * recover from hash */ - jmap.setTo((SequenceI) seqRefIds.get(dsfor)); + jmap.setTo(seqRefIds.get(dsfor)); } else { @@ -4221,14 +4226,14 @@ public class Jalview2XML * local sequence definition */ Sequence ms = mc.getSequence(); - jalview.datamodel.Sequence djs = null; + SequenceI djs = null; String sqid = ms.getDsseqid(); if (sqid != null && sqid.length() > 0) { /* * recover dataset sequence */ - djs = (jalview.datamodel.Sequence) seqRefIds.get(sqid); + djs = seqRefIds.get(sqid); } else { @@ -4290,6 +4295,8 @@ public class Jalview2XML viewportsAdded = new Hashtable(); AlignFrame af = LoadFromObject(jm, null, false, null); + // next line added in an attempt to copy AlignedCodonFrame list but failed + // resolveFrefedSequences(); af.alignPanels.clear(); af.closeMenuItem_actionPerformed(true); @@ -4423,13 +4430,13 @@ public class Jalview2XML // register sequence object so the XML parser can recover it. if (seqRefIds == null) { - seqRefIds = new Hashtable(); + seqRefIds = new HashMap(); } if (seqsToIds == null) { seqsToIds = new IdentityHashMap(); } - seqRefIds.put(jv2vobj.get(jvobj).toString(), jvobj); + seqRefIds.put(jv2vobj.get(jvobj).toString(), (SequenceI) jvobj); seqsToIds.put(jvobj, id); } else if (jvobj instanceof jalview.datamodel.AlignmentAnnotation) diff --git a/src/jalview/gui/JvSwingUtils.java b/src/jalview/gui/JvSwingUtils.java index e433243..37f5d27 100644 --- a/src/jalview/gui/JvSwingUtils.java +++ b/src/jalview/gui/JvSwingUtils.java @@ -31,6 +31,7 @@ import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.JScrollBar; import javax.swing.SwingConstants; /** @@ -209,4 +210,51 @@ public final class JvSwingUtils } } + /** + * Returns the proportion of its range that a scrollbar's position represents, + * as a value between 0 and 1. For example if the whole range is from 0 to + * 200, then a position of 40 gives proportion = 0.2. + * + * @see http://www.javalobby.org/java/forums/t33050.html#91885334 + * + * @param scroll + * @return + */ + public static float getScrollBarProportion(JScrollBar scroll) + { + /* + * The extent (scroll handle width) deduction gives the true operating range + * of possible positions. + */ + int possibleRange = scroll.getMaximum() - scroll.getMinimum() + - scroll.getModel().getExtent(); + float valueInRange = scroll.getValue() + - (scroll.getModel().getExtent() / 2f); + float proportion = valueInRange / possibleRange; + return proportion; + } + + /** + * Returns the scroll bar position in its range that would match the given + * proportion (between 0 and 1) of the whole. For example if the whole range + * is from 0 to 200, then a proportion of 0.25 gives position 50. + * + * @param scrollbar + * @param proportion + * @return + */ + public static int getScrollValueForProportion(JScrollBar scrollbar, + float proportion) + { + /* + * The extent (scroll handle width) deduction gives the true operating range + * of possible positions. + */ + float fraction = proportion + * (scrollbar.getMaximum() - scrollbar.getMinimum() - scrollbar + .getModel().getExtent()) + + (scrollbar.getModel().getExtent() / 2f); + return Math.min(Math.round(fraction), scrollbar.getMaximum()); + } + } diff --git a/src/jalview/gui/PaintRefresher.java b/src/jalview/gui/PaintRefresher.java index 01dfa3b..215090b 100755 --- a/src/jalview/gui/PaintRefresher.java +++ b/src/jalview/gui/PaintRefresher.java @@ -20,12 +20,15 @@ */ package jalview.gui; -import java.util.*; -import java.util.List; - -import java.awt.*; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceI; -import jalview.datamodel.*; +import java.awt.Component; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; /** * Route datamodel/view update events for a sequence set to any display @@ -36,57 +39,61 @@ import jalview.datamodel.*; */ public class PaintRefresher { - static Hashtable components; + static Map> components = new HashMap>(); /** - * DOCUMENT ME! + * Add the given component to those registered under the given sequence set + * id. Does nothing if already added. * * @param comp - * DOCUMENT ME! * @param al - * DOCUMENT ME! */ public static void Register(Component comp, String seqSetId) { - if (components == null) - { - components = new Hashtable(); - } - if (components.containsKey(seqSetId)) { - Vector comps = (Vector) components.get(seqSetId); + List comps = components.get(seqSetId); if (!comps.contains(comp)) { - comps.addElement(comp); + comps.add(comp); } } else { - Vector vcoms = new Vector(); - vcoms.addElement(comp); + List vcoms = new ArrayList(); + vcoms.add(comp); components.put(seqSetId, vcoms); } } + /** + * Remove this component from all registrations. Also removes a registered + * sequence set id if there are no remaining components registered against it. + * + * @param comp + */ public static void RemoveComponent(Component comp) { - if (components == null) - { - return; - } - - Enumeration en = components.keys(); - while (en.hasMoreElements()) + List emptied = new ArrayList(); + for (Entry> registered : components.entrySet()) { - String id = en.nextElement().toString(); - Vector comps = (Vector) components.get(id); + String id = registered.getKey(); + List comps = components.get(id); comps.remove(comp); - if (comps.size() == 0) + if (comps.isEmpty()) { - components.remove(id); + emptied.add(id); } } + + /* + * Remove now empty ids after the above (to avoid + * ConcurrentModificationException). + */ + for (String id : emptied) + { + components.remove(id); + } } public static void Refresh(Component source, String id) @@ -97,24 +104,15 @@ public class PaintRefresher public static void Refresh(Component source, String id, boolean alignmentChanged, boolean validateSequences) { - if (components == null) - { - return; - } - - Component comp; - Vector comps = (Vector) components.get(id); + List comps = components.get(id); if (comps == null) { return; } - Enumeration e = comps.elements(); - while (e.hasMoreElements()) + for (Component comp : comps) { - comp = (Component) e.nextElement(); - if (comp == source) { continue; @@ -242,30 +240,20 @@ public class PaintRefresher static AlignmentPanel[] getAssociatedPanels(String id) { - if (components == null) - { - return new AlignmentPanel[0]; - } - ; - Vector comps = (Vector) components.get(id); + List comps = components.get(id); if (comps == null) { return new AlignmentPanel[0]; } - ; - Vector tmp = new Vector(); - int i, iSize = comps.size(); - for (i = 0; i < iSize; i++) + List tmp = new ArrayList(); + for (Component comp : comps) { - if (comps.elementAt(i) instanceof AlignmentPanel) + if (comp instanceof AlignmentPanel) { - tmp.addElement(comps.elementAt(i)); + tmp.add((AlignmentPanel) comp); } } - AlignmentPanel[] result = new AlignmentPanel[tmp.size()]; - tmp.toArray(result); - - return result; + return tmp.toArray(new AlignmentPanel[tmp.size()]); } } diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index 24babda..f98eea7 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -15,6 +15,7 @@ import java.util.Map.Entry; import javax.swing.AbstractAction; import javax.swing.JComponent; +import javax.swing.JMenuItem; import javax.swing.KeyStroke; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; @@ -142,7 +143,7 @@ public class SplitFrame extends GSplitFrame { if (getTopComponent() instanceof AlignFrame) { - for (Entry acc : ((AlignFrame) getTopComponent()) + for (Entry acc : ((AlignFrame) getTopComponent()) .getAccelerators().entrySet()) { @@ -156,8 +157,12 @@ public class SplitFrame extends GSplitFrame Component c = getComponentAtMouse(); if (c instanceof AlignFrame) { - ((AlignFrame) c).getAccelerators().get(ks) - .actionPerformed(null); + for (ActionListener a : ((AlignFrame) c).getAccelerators() + .get(ks).getActionListeners()) + { + + a.actionPerformed(null); + } } } }); @@ -166,8 +171,49 @@ public class SplitFrame extends GSplitFrame * Disable unwanted here */ // X expand views - wrecks the split pane view - this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove( - KeyStroke.getKeyStroke(KeyEvent.VK_X, 0, false)); + KeyStroke key_X = KeyStroke.getKeyStroke(KeyEvent.VK_X, 0, false); + disableAccelerator(key_X); + } + } + + /** + * Ugly hack for Proof of Concept that disables the key binding in this frame + * _and_ disables the bound menu item _and_ removes the key accelerator in the + * child frames. + * + * @param key + */ + protected void disableAccelerator(KeyStroke key) + { + disableAccelerator(key, getTopComponent()); + disableAccelerator(key, getBottomComponent()); + this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(key); + } + + /** + * Disable the menu item for which this key is the accelerator, also removes + * its action listeners to prevent key accelerator working. + * + * @param key + * @param comp + */ + private void disableAccelerator(KeyStroke key, JComponent comp) + { + // HACKED ONLY FOR PROOF OF CONCEPT + // Proper solution might involve explicit 'configure menu' method on + // AlignFrame, or + // changing key listeners to key bindings in AlignFrame, or both + if (comp instanceof AlignFrame) + { + JMenuItem mi = ((AlignFrame) comp).getAccelerators().get(key); + if (mi != null) + { + mi.setEnabled(false); + for (ActionListener al : mi.getActionListeners()) + { + mi.removeActionListener(al); + } + } } } } diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index 6f963a5..fdb7641 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -390,7 +390,7 @@ public class GAlignFrame extends JInternalFrame private boolean showAutoCalculatedAbove = false; - private Map accelerators = new HashMap(); + private Map accelerators = new HashMap(); public GAlignFrame() { @@ -2476,7 +2476,7 @@ public class GAlignFrame extends JInternalFrame JMenuItem menuItem, ActionListener actionListener) { menuItem.setAccelerator(keyStroke); - accelerators.put(keyStroke, actionListener); + accelerators.put(keyStroke, menuItem); menuItem.addActionListener(actionListener); } @@ -3210,7 +3210,7 @@ public class GAlignFrame extends JInternalFrame this.annotationSortOrder = annotationSortOrder; } - public Map getAccelerators() + public Map getAccelerators() { return this.accelerators; } diff --git a/src/jalview/util/StringUtils.java b/src/jalview/util/StringUtils.java index c1e050f..0544864 100644 --- a/src/jalview/util/StringUtils.java +++ b/src/jalview/util/StringUtils.java @@ -1,5 +1,6 @@ package jalview.util; + public class StringUtils { @@ -79,4 +80,27 @@ public class StringUtils } return tmp; } + + /** + * Returns the last part of 'input' after the last occurrence of 'token'. For + * example to extract only the filename from a full path or URL. + * + * @param input + * @param token + * a delimiter which must be in regular expression format + * @return + */ + public static String getLastToken(String input, String token) + { + if (input == null) + { + return null; + } + if (token == null) + { + return input; + } + String[] st = input.split(token); + return st[st.length - 1]; + } } diff --git a/test/jalview/datamodel/AlignmentTest.java b/test/jalview/datamodel/AlignmentTest.java index dbd063c..3b3d926 100644 --- a/test/jalview/datamodel/AlignmentTest.java +++ b/test/jalview/datamodel/AlignmentTest.java @@ -105,6 +105,35 @@ public class AlignmentTest assertFalse(iter.hasNext()); } + @Test + public void testDeleteAllAnnotations_includingAutocalculated() + { + AlignmentAnnotation aa = new AlignmentAnnotation("Consensus", + "Consensus", 0.5); + aa.autoCalculated = true; + al.addAnnotation(aa); + AlignmentAnnotation[] anns = al.getAlignmentAnnotation(); + assertEquals("Wrong number of annotations before deleting", 4, + anns.length); + al.deleteAllAnnotations(true); + assertEquals("Not all deleted", 0, al.getAlignmentAnnotation().length); + } + + @Test + public void testDeleteAllAnnotations_excludingAutocalculated() + { + AlignmentAnnotation aa = new AlignmentAnnotation("Consensus", + "Consensus", 0.5); + aa.autoCalculated = true; + al.addAnnotation(aa); + AlignmentAnnotation[] anns = al.getAlignmentAnnotation(); + assertEquals("Wrong number of annotations before deleting", 4, + anns.length); + al.deleteAllAnnotations(false); + assertEquals("Not just one annotation left", 1, + al.getAlignmentAnnotation().length); + } + /** * Tests for realigning as per a supplied alignment: Dna as Dna. * @@ -134,7 +163,7 @@ public class AlignmentTest acf.addMap(al2.getSequenceAt(1), al1.getSequenceAt(1), ml); al1.addCodonFrame(acf); - al2.alignAs(al1); + ((Alignment) al2).alignAs(al1, false, true); assertEquals("GC-TC--GUC-GTA-CT", al2.getSequenceAt(0) .getSequenceAsString()); assertEquals("-GG-GTC--AGG---CAGT", al2.getSequenceAt(1) @@ -154,7 +183,7 @@ public class AlignmentTest String before0 = al2.getSequenceAt(0).getSequenceAsString(); String before1 = al2.getSequenceAt(1).getSequenceAsString(); - al2.alignAs(al1); + ((Alignment) al2).alignAs(al1, false, true); assertEquals(before0, al2.getSequenceAt(0).getSequenceAsString()); assertEquals(before1, al2.getSequenceAt(1).getSequenceAsString()); } @@ -180,38 +209,13 @@ public class AlignmentTest acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml); al2.addCodonFrame(acf); - al1.alignAs(al2); - assertEquals("AC-G---G--CUC-CA------A-CT", al1.getSequenceAt(0) - .getSequenceAsString()); - assertEquals("---CG-T---TA--ACG---A---AGT", al1.getSequenceAt(1) - .getSequenceAsString()); - } - - /** - * Test aligning cdna (with introns) as per protein alignment. - * - * @throws IOException - */ - @Test - public void testAlignAs_cdnaAsProteinWithIntrons() throws IOException - { /* - * Load alignments and add mappings for cDNA to protein + * Realign DNA; currently keeping existing gaps in introns only */ - AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA"); - AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA"); - AlignedCodonFrame acf = new AlignedCodonFrame(); - MapList ml = new MapList(new int[] - { 1, 12 }, new int[] - { 1, 4 }, 3, 1); - acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml); - acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml); - al2.addCodonFrame(acf); - - al1.alignAs(al2); - assertEquals("AC-G---G--CUC-CA------A-CT", al1.getSequenceAt(0) + ((Alignment) al1).alignAs(al2, false, true); + assertEquals("ACG---GCUCCA------ACT", al1.getSequenceAt(0) .getSequenceAsString()); - assertEquals("---CG-T---TA--ACG---A---AGT", al1.getSequenceAt(1) + assertEquals("---CGT---TAACGA---AGT", al1.getSequenceAt(1) .getSequenceAsString()); } @@ -252,7 +256,8 @@ public class AlignmentTest ((Alignment) al1).alignAs(al2, false, false); assertEquals("---AAagG------GCCcTTT", al1.getSequenceAt(0) .getSequenceAsString()); - assertEquals("cCCGgg---TTT------AAA", al1.getSequenceAt(1) + // note 1 gap in protein corresponds to 'gg-' in DNA (3 positions) + assertEquals("cCCGgg-TTT------AAA", al1.getSequenceAt(1) .getSequenceAsString()); /* @@ -266,7 +271,7 @@ public class AlignmentTest // assumption: we include 'the greater of' protein/dna gap lengths, not both assertEquals("---A-Aa-gG------GCC-cT-TT", al1.getSequenceAt(0) .getSequenceAsString()); - assertEquals("c--CCGgg---TT--T------AA-A", al1.getSequenceAt(1) + assertEquals("c--CCGgg-TT--T------AA-A", al1.getSequenceAt(1) .getSequenceAsString()); } } diff --git a/test/jalview/gui/JvSwingUtilsTest.java b/test/jalview/gui/JvSwingUtilsTest.java new file mode 100644 index 0000000..11e6ea5 --- /dev/null +++ b/test/jalview/gui/JvSwingUtilsTest.java @@ -0,0 +1,41 @@ +package jalview.gui; + +import static org.junit.Assert.assertEquals; + +import javax.swing.JScrollBar; + +import org.junit.Test; + +public class JvSwingUtilsTest +{ + + @Test + public void testGetScrollBarProportion() + { + /* + * orientation, value, extent (width), min, max + */ + JScrollBar sb = new JScrollBar(0, 125, 50, 0, 450); + + /* + * operating range is 25 - 425 (400 wide) so value 125 is 100/400ths of this + * range + */ + assertEquals(0.25f, JvSwingUtils.getScrollBarProportion(sb), 0.001f); + } + + @Test + public void testGetScrollValueForProportion() + { + /* + * orientation, value, extent (width), min, max + */ + JScrollBar sb = new JScrollBar(0, 125, 50, 0, 450); + + /* + * operating range is 25 - 425 (400 wide) so value 125 is a quarter of this + * range + */ + assertEquals(125, JvSwingUtils.getScrollValueForProportion(sb, 0.25f)); + } +} diff --git a/test/jalview/gui/PaintRefresherTest.java b/test/jalview/gui/PaintRefresherTest.java new file mode 100644 index 0000000..2737dd0 --- /dev/null +++ b/test/jalview/gui/PaintRefresherTest.java @@ -0,0 +1,115 @@ +package jalview.gui; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import jalview.datamodel.Alignment; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; + +import java.awt.Component; +import java.util.List; +import java.util.Map; + +import javax.swing.JPanel; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PaintRefresherTest +{ + // TODO would prefer PaintRefresher to be a single rather than static + @Before + public void setUp() + { + PaintRefresher.components.clear(); + } + + @After + public void tearDown() + { + PaintRefresher.components.clear(); + } + + @Test + public void testRegister() + { + JPanel jp = new JPanel(); + JPanel jp2 = new JPanel(); + JPanel jp3 = new JPanel(); + JPanel jp4 = new JPanel(); + PaintRefresher.Register(jp, "22"); + PaintRefresher.Register(jp, "22"); + PaintRefresher.Register(jp2, "22"); + PaintRefresher.Register(jp3, "33"); + PaintRefresher.Register(jp3, "44"); + PaintRefresher.Register(jp4, "44"); + + Map> registered = PaintRefresher.components; + assertEquals(3, registered.size()); + assertEquals(2, registered.get("22").size()); + assertEquals(1, registered.get("33").size()); + assertEquals(2, registered.get("44").size()); + assertTrue(registered.get("22").contains(jp)); + assertTrue(registered.get("22").contains(jp2)); + assertTrue(registered.get("33").contains(jp3)); + assertTrue(registered.get("44").contains(jp3)); + assertTrue(registered.get("44").contains(jp4)); + } + + @Test + public void testRemoveComponent() + { + Map> registered = PaintRefresher.components; + + // no error with an empty PaintRefresher + JPanel jp = new JPanel(); + JPanel jp2 = new JPanel(); + PaintRefresher.RemoveComponent(jp); + assertTrue(registered.isEmpty()); + + /* + * Add then remove one item + */ + PaintRefresher.Register(jp, "11"); + PaintRefresher.RemoveComponent(jp); + assertTrue(registered.isEmpty()); + + /* + * Add one item under two ids, then remove it. It is removed from both ids, + * and the now empty id is removed. + */ + PaintRefresher.Register(jp, "11"); + PaintRefresher.Register(jp, "22"); + PaintRefresher.Register(jp2, "22"); + PaintRefresher.RemoveComponent(jp); + // "11" is removed as now empty, only 22/jp2 left + assertEquals(1, registered.size()); + assertEquals(1, registered.get("22").size()); + assertTrue(registered.get("22").contains(jp2)); + } + + @Test + public void testGetAssociatedPanels() + { + SequenceI [] seqs = new SequenceI[]{new Sequence("", "ABC")}; + Alignment al = new Alignment(seqs); + + /* + * AlignFrame constructor has side-effects: AlignmentPanel is constructed, + * and SeqCanvas, IdPanel, AlignmentPanel are all registered under the + * sequence set id of the viewport. + */ + AlignViewport av = new AlignViewport(al); + AlignFrame af = new AlignFrame(al, 4, 1); + AlignmentPanel ap1 = af.alignPanel; + AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(av + .getSequenceSetId()); + assertEquals(1, panels.length); + assertSame(ap1, panels[0]); + + panels = PaintRefresher.getAssociatedPanels(av.getSequenceSetId() + 1); + assertEquals(0, panels.length); + } +} diff --git a/test/jalview/util/StringUtilsTest.java b/test/jalview/util/StringUtilsTest.java index eba2da4..22a4130 100644 --- a/test/jalview/util/StringUtilsTest.java +++ b/test/jalview/util/StringUtilsTest.java @@ -1,5 +1,7 @@ package jalview.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Arrays; @@ -53,4 +55,17 @@ public class StringUtilsTest // out of range deletion is ignore assertTrue(Arrays.equals(c1, StringUtils.deleteChars(c1, 3, 4))); } + + @Test + public void testGetLastToken() + { + assertNull(StringUtils.getLastToken(null, null)); + assertNull(StringUtils.getLastToken(null, "/")); + assertEquals("a", StringUtils.getLastToken("a", null)); + + assertEquals("abc", StringUtils.getLastToken("abc", "/")); + assertEquals("c", StringUtils.getLastToken("abc", "b")); + assertEquals("file1.dat", StringUtils.getLastToken( + "file://localhost:8080/data/examples/file1.dat", "/")); + } } -- 1.7.10.2