Clover icon

Coverage Report

  1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.controller

File AlignViewController.java

 

Coverage histogram

../../img/srcFileCovDistChart5.png
43% of files have more coverage

Code metrics

98
182
15
1
537
421
74
0.41
12.13
15
4.93

Classes

Class Line # Actions
AlignViewController 47 182 74
0.4271186342.7%
 

Contributing tests

This file is covered by 181 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.controller;
22   
23    import java.awt.Color;
24    import java.util.BitSet;
25    import java.util.List;
26   
27    import jalview.analysis.AlignmentSorter;
28    import jalview.api.AlignViewControllerGuiI;
29    import jalview.api.AlignViewControllerI;
30    import jalview.api.AlignViewportI;
31    import jalview.api.AlignmentViewPanel;
32    import jalview.api.FeatureRenderer;
33    import jalview.commands.OrderCommand;
34    import jalview.datamodel.AlignmentI;
35    import jalview.datamodel.ColumnSelection;
36    import jalview.datamodel.SearchResultsI;
37    import jalview.datamodel.SequenceCollectionI;
38    import jalview.datamodel.SequenceFeature;
39    import jalview.datamodel.SequenceGroup;
40    import jalview.datamodel.SequenceI;
41    import jalview.gui.Desktop;
42    import jalview.io.DataSourceType;
43    import jalview.io.FeaturesFile;
44    import jalview.schemes.ColourSchemeI;
45    import jalview.util.MessageManager;
46   
 
47    public class AlignViewController implements AlignViewControllerI
48    {
49    AlignViewportI viewport = null;
50   
51    AlignmentViewPanel alignPanel = null;
52   
53    /**
54    * the GUI container that is handling interactions with the user
55    */
56    private AlignViewControllerGuiI avcg;
57   
 
58  954 toggle public AlignViewController(AlignViewControllerGuiI alignFrame,
59    AlignViewportI vp, AlignmentViewPanel ap)
60    {
61  954 this.avcg = alignFrame;
62  954 this.viewport = vp;
63  954 this.alignPanel = ap;
64    }
65   
 
66  105 toggle @Override
67    public void setViewportAndAlignmentPanel(AlignViewportI vp,
68    AlignmentViewPanel ap)
69    {
70  105 this.alignPanel = ap;
71  105 this.viewport = vp;
72    }
73   
 
74  0 toggle @Override
75    public boolean makeGroupsFromSelection()
76    {
77  0 SequenceGroup sg = viewport.getSelectionGroup();
78  0 ColumnSelection cs = viewport.getColumnSelection();
79  0 SequenceGroup[] gps = null;
80  0 if (sg != null && (cs == null || cs.isEmpty()))
81    {
82  0 gps = jalview.analysis.Grouping.makeGroupsFrom(
83    viewport.getSequenceSelection(),
84    viewport.getAlignmentView(true)
85    .getSequenceStrings(viewport.getGapCharacter()),
86    viewport.getAlignment().getGroups());
87    }
88    else
89    {
90  0 if (cs != null)
91    {
92  0 gps = jalview.analysis.Grouping.makeGroupsFromCols(
93  0 (sg == null) ? viewport.getAlignment().getSequencesArray()
94    : sg.getSequences().toArray(new SequenceI[0]),
95    cs, viewport.getAlignment().getGroups());
96    }
97    }
98  0 if (gps != null)
99    {
100  0 viewport.getAlignment().deleteAllGroups();
101  0 viewport.clearSequenceColours();
102  0 viewport.clearAnnotationColours();
103  0 viewport.setSelectionGroup(null);
104  0 ColourSchemeI colours = viewport.getGlobalColourScheme();
105    // set view properties for each group
106  0 for (int g = 0; g < gps.length; g++)
107    {
108    // gps[g].setShowunconserved(viewport.getShowUnconserved());
109  0 gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
110  0 viewport.getAlignment().addGroup(gps[g]);
111  0 if (colours != null)
112    {
113  0 gps[g].setColourScheme(colours.getInstance(viewport, gps[g]));
114    }
115  0 Color col = new Color((int) (Math.random() * 255),
116    (int) (Math.random() * 255), (int) (Math.random() * 255));
117  0 gps[g].idColour = col;
118  0 viewport.setUpdateStructures(true);
119  0 viewport.addSequenceGroup(gps[g]);
120    }
121  0 return true;
122    }
123  0 return false;
124    }
125   
 
126  0 toggle @Override
127    public boolean createGroup()
128    {
129   
130  0 SequenceGroup sg = viewport.getSelectionGroup();
131  0 if (sg != null)
132    {
133  0 viewport.getAlignment().addGroup(sg);
134  0 return true;
135    }
136  0 return false;
137    }
138   
 
139  0 toggle @Override
140    public boolean unGroup()
141    {
142  0 SequenceGroup sg = viewport.getSelectionGroup();
143  0 if (sg != null)
144    {
145  0 viewport.getAlignment().deleteGroup(sg);
146  0 return true;
147    }
148  0 return false;
149    }
150   
 
151  0 toggle @Override
152    public boolean deleteGroups()
153    {
154  0 if (viewport.getAlignment().getGroups() != null
155    && viewport.getAlignment().getGroups().size() > 0)
156    {
157  0 viewport.getAlignment().deleteAllGroups();
158  0 viewport.clearSequenceColours();
159  0 viewport.clearAnnotationColours();
160  0 viewport.setSelectionGroup(null);
161  0 return true;
162    }
163  0 return false;
164    }
165   
 
166  12 toggle @Override
167    public boolean markColumnsContainingFeatures(boolean invert,
168    boolean extendCurrent, boolean toggle, String featureType)
169    {
170    // JBPNote this routine could also mark rows, not just columns.
171    // need a decent query structure to allow all types of feature searches
172  12 BitSet bs = new BitSet();
173  12 boolean searchSelection = viewport.getSelectionGroup() != null
174    && !extendCurrent;
175  12 SequenceCollectionI sqcol = searchSelection
176    ? viewport.getSelectionGroup()
177    : viewport.getAlignment();
178   
179  12 int nseq = findColumnsWithFeature(featureType, sqcol, bs);
180   
181  12 ColumnSelection cs = viewport.getColumnSelection();
182  12 if (cs == null)
183    {
184  0 cs = new ColumnSelection();
185    }
186   
187  12 if (bs.cardinality() > 0 || invert)
188    {
189  10 boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
190    sqcol.getEndRes(), invert, extendCurrent, toggle);
191  10 if (changed)
192    {
193  9 viewport.setColumnSelection(cs);
194  9 alignPanel.paintAlignment(false, false);
195  9 int columnCount = invert
196    ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
197    - bs.cardinality()
198    : bs.cardinality();
199  9 avcg.setStatus(MessageManager.formatMessage(
200    "label.view_controller_toggled_marked", new String[]
201  9 { toggle ? MessageManager.getString("label.toggled")
202    : MessageManager.getString("label.marked"),
203    String.valueOf(columnCount),
204  9 invert ? MessageManager
205    .getString("label.not_containing")
206    : MessageManager.getString("label.containing"),
207    featureType, Integer.valueOf(nseq).toString() }));
208  9 return true;
209    }
210    }
211    else
212    {
213  2 String key = searchSelection ? "label.no_feature_found_selection"
214    : "label.no_feature_of_type_found";
215  2 avcg.setStatus(
216    MessageManager.formatMessage(key, new String[]
217    { featureType }));
218  2 if (!extendCurrent)
219    {
220  2 cs.clear();
221  2 alignPanel.paintAlignment(false, false);
222    }
223    }
224  3 return false;
225    }
226   
227    /**
228    * Sets a bit in the BitSet for each column (base 0) in the sequence
229    * collection which includes a visible feature of the specified feature type.
230    * Returns the number of sequences which have the feature visible in the
231    * selected range.
232    *
233    * @param featureType
234    * @param sqcol
235    * @param bs
236    * @return
237    */
 
238  20 toggle int findColumnsWithFeature(String featureType, SequenceCollectionI sqcol,
239    BitSet bs)
240    {
241  20 FeatureRenderer fr = alignPanel == null ? null
242    : alignPanel.getFeatureRenderer();
243   
244  20 final int startColumn = sqcol.getStartRes() + 1; // converted to base 1
245  20 final int endColumn = sqcol.getEndRes() + 1;
246  20 List<SequenceI> seqs = sqcol.getSequences();
247  20 int nseq = 0;
248  20 for (SequenceI sq : seqs)
249    {
250  92 if (sq != null)
251    {
252    // int ist = sq.findPosition(sqcol.getStartRes());
253  92 List<SequenceFeature> sfs = sq.findFeatures(startColumn, endColumn,
254    featureType);
255   
256  92 boolean found = false;
257  92 for (SequenceFeature sf : sfs)
258    {
259  545 if (fr.getColour(sf) == null)
260    {
261  3 continue;
262    }
263  542 if (!found)
264    {
265  58 nseq++;
266    }
267  542 found = true;
268   
269  542 int sfStartCol = sq.findIndex(sf.getBegin());
270  542 int sfEndCol = sq.findIndex(sf.getEnd());
271   
272  542 if (sf.isContactFeature())
273    {
274    /*
275    * 'contact' feature - check for 'start' or 'end'
276    * position within the selected region
277    */
278  1 if (sfStartCol >= startColumn && sfStartCol <= endColumn)
279    {
280  1 bs.set(sfStartCol - 1);
281    }
282  1 if (sfEndCol >= startColumn && sfEndCol <= endColumn)
283    {
284  1 bs.set(sfEndCol - 1);
285    }
286  1 continue;
287    }
288   
289    /*
290    * contiguous feature - select feature positions (if any)
291    * within the selected region
292    */
293  541 if (sfStartCol < startColumn)
294    {
295  1 sfStartCol = startColumn;
296    }
297    // not sure what the point of this is
298    // if (sfStartCol < ist)
299    // {
300    // sfStartCol = ist;
301    // }
302  541 if (sfEndCol > endColumn)
303    {
304  4 sfEndCol = endColumn;
305    }
306  25219 for (; sfStartCol <= sfEndCol; sfStartCol++)
307    {
308  24678 bs.set(sfStartCol - 1); // convert to base 0
309    }
310    }
311    }
312    }
313  20 return nseq;
314    }
315   
 
316  0 toggle @Override
317    public void sortAlignmentByFeatureDensity(List<String> typ)
318    {
319  0 String methodText = MessageManager.getString("label.sort_by_density");
320  0 sortByFeatures(typ, methodText, AlignmentSorter.FEATURE_DENSITY);
321    }
322   
323    /**
324    * Sorts the alignment (or current selection) by either average score or
325    * density of the specified feature types, and adds to the command history. If
326    * {@code types} is null, all visible feature types are used for the sort. If
327    * no feature types apply, does nothing.
328    *
329    * @param types
330    * @param methodText
331    * - text shown in Undo/Redo command
332    * @param method
333    * - passed to jalview.analysis.AlignmentSorter.sortByFeatures()
334    */
 
335  0 toggle protected void sortByFeatures(List<String> types, String methodText,
336    final String method)
337    {
338  0 FeatureRenderer fr = alignPanel.getFeatureRenderer();
339  0 if (types == null && fr != null)
340    {
341  0 types = fr.getDisplayedFeatureTypes();
342    }
343  0 if (types.isEmpty())
344    {
345  0 return; // nothing to do
346    }
347  0 List<String> gps = null;
348  0 if (fr != null)
349    {
350  0 gps = fr.getDisplayedFeatureGroups();
351    }
352  0 AlignmentI al = viewport.getAlignment();
353   
354  0 int start, stop;
355  0 SequenceGroup sg = viewport.getSelectionGroup();
356  0 if (sg != null)
357    {
358  0 start = sg.getStartRes();
359  0 stop = sg.getEndRes();
360    }
361    else
362    {
363  0 start = 0;
364  0 stop = al.getWidth();
365    }
366  0 SequenceI[] oldOrder = al.getSequencesArray();
367  0 AlignmentSorter.sortByFeature(types, gps, start, stop, al, method);
368  0 avcg.addHistoryItem(new OrderCommand(methodText, oldOrder,
369    viewport.getAlignment()));
370  0 alignPanel.paintAlignment(true, false);
371   
372    }
373   
 
374  0 toggle @Override
375    public void sortAlignmentByFeatureScore(List<String> typ)
376    {
377  0 String methodText = MessageManager.getString("label.sort_by_score");
378  0 sortByFeatures(typ, methodText, AlignmentSorter.FEATURE_SCORE);
379    }
380   
 
381  4 toggle @Override
382    public boolean parseFeaturesFile(Object file, DataSourceType protocol,
383    boolean relaxedIdMatching)
384    {
385  4 boolean featuresAdded = false;
386  4 FeatureRenderer fr = alignPanel.getFeatureRenderer();
387  4 try
388    {
389  4 featuresAdded = new FeaturesFile(false, file, protocol).parse(
390    viewport.getAlignment().getDataset(), fr.getFeatureColours(),
391    fr.getFeatureFilters(), false, relaxedIdMatching);
392    } catch (Exception ex)
393    {
394  0 ex.printStackTrace();
395    }
396   
397  4 if (featuresAdded)
398    {
399  4 avcg.refreshFeatureUI(true);
400  4 if (fr != null)
401    {
402    // update the min/max ranges where necessary
403  4 fr.findAllFeatures(true);
404    }
405  4 if (avcg.getFeatureSettingsUI() != null)
406    {
407  0 avcg.getFeatureSettingsUI().discoverAllFeatureData();
408    }
409  4 alignPanel.paintAlignment(true, true);
410    }
411   
412  4 return featuresAdded;
413   
414    }
415   
 
416  2 toggle @Override
417    public boolean markHighlightedColumns(boolean invert,
418    boolean extendCurrent, boolean toggle)
419    {
420  2 if (!viewport.hasSearchResults())
421    {
422    // do nothing if no selection exists
423  0 return false;
424    }
425    // JBPNote this routine could also mark rows, not just columns.
426  2 BitSet bs = new BitSet();
427  2 SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null
428    || extendCurrent) ? viewport.getAlignment()
429    : viewport.getSelectionGroup();
430   
431    // this could be a lambda... - the remains of the method is boilerplate,
432    // except for the different messages for reporting selection.
433  2 int nseq = viewport.getSearchResults().markColumns(sqcol, bs);
434   
435  2 ColumnSelection cs = viewport.getColumnSelection();
436  2 if (cs == null)
437    {
438  0 cs = new ColumnSelection();
439    }
440   
441  2 if (bs.cardinality() > 0 || invert)
442    {
443  2 boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
444    sqcol.getEndRes(), invert, extendCurrent, toggle);
445  2 if (changed)
446    {
447  2 viewport.setColumnSelection(cs);
448  2 alignPanel.paintAlignment(false, false);
449  2 int columnCount = invert
450    ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
451    - bs.cardinality()
452    : bs.cardinality();
453  2 avcg.setStatus(MessageManager.formatMessage(
454    "label.view_controller_toggled_marked", new String[]
455  2 { toggle ? MessageManager.getString("label.toggled")
456    : MessageManager.getString("label.marked"),
457    String.valueOf(columnCount),
458  2 invert ? MessageManager
459    .getString("label.not_containing")
460    : MessageManager.getString("label.containing"),
461    "Highlight", Integer.valueOf(nseq).toString() }));
462  2 return true;
463    }
464    }
465    else
466    {
467  0 avcg.setStatus(MessageManager
468    .getString("label.no_highlighted_regions_marked"));
469  0 if (!extendCurrent)
470    {
471  0 cs.clear();
472  0 alignPanel.paintAlignment(false, false);
473    }
474    }
475  0 return false;
476    }
477   
 
478  0 toggle @Override
479    public boolean copyHighlightedRegionsToClipboard()
480    {
481  0 if (!viewport.hasSearchResults())
482    {
483    // do nothing if no selection exists
484  0 return false;
485    }
486   
487  0 SearchResultsI searchResults = viewport.getSearchResults();
488  0 if (searchResults.isEmpty())
489    {
490  0 return false; // shouldn't happen
491    }
492  0 List<SequenceI> seqs = searchResults.getMatchingSubSequences();
493   
494    // TODO: pass in hiddenColumns according to intersection of searchResults
495    // and visible columns. Currently this isn't done, since each contig becomes
496    // a single subsequence
497  0 Desktop.jalviewClipboard = new Object[] {
498    seqs.toArray(new SequenceI[0]),
499    alignPanel.getAlignment().getDataset(), null };
500  0 avcg.setStatus(MessageManager.formatMessage(
501    "label.copied_sequences_to_clipboard", seqs.size()));
502    // Technically we should return false, since view has not changed
503  0 return false;
504    }
505   
 
506  0 toggle @Override
507    public boolean justify_Region(boolean left)
508    {
509  0 AlignmentI al = viewport.getAlignment();
510  0 SequenceGroup reg = viewport.getSelectionGroup();
511  0 int from, to;
512  0 List<SequenceI> seqs;
513   
514  0 from = 0;
515  0 to = al.getWidth() - 1;
516  0 seqs = al.getSequences();
517  0 if (reg != null)
518    {
519  0 seqs = reg.getSequences();
520  0 from = reg.getStartRes();
521  0 to = reg.getEndRes();
522    }
523   
524  0 if ((to - from) < 1)
525    {
526  0 return false;
527    }
528   
529  0 al.padGaps();
530  0 jalview.commands.JustifyLeftOrRightCommand finalEdit = new jalview.commands.JustifyLeftOrRightCommand(
531  0 "Justify " + (left ? "Left" : "Right"), left, seqs, from, to,
532    al);
533  0 avcg.addHistoryItem(finalEdit);
534  0 viewport.notifyAlignmentChanged();
535  0 return true;
536    }
537    }