Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.controller

File AlignViewController.java

 

Coverage histogram

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

Code metrics

98
180
15
1
535
419
74
0.41
12
15
4.93

Classes

Class Line # Actions
AlignViewController 47 180 74
0.4300341343%
 

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.setSelectionGroup(null);
103  0 ColourSchemeI colours = viewport.getGlobalColourScheme();
104    // set view properties for each group
105  0 for (int g = 0; g < gps.length; g++)
106    {
107    // gps[g].setShowunconserved(viewport.getShowUnconserved());
108  0 gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
109  0 viewport.getAlignment().addGroup(gps[g]);
110  0 if (colours != null)
111    {
112  0 gps[g].setColourScheme(colours.getInstance(viewport, gps[g]));
113    }
114  0 Color col = new Color((int) (Math.random() * 255),
115    (int) (Math.random() * 255), (int) (Math.random() * 255));
116  0 gps[g].idColour = col;
117  0 viewport.setUpdateStructures(true);
118  0 viewport.addSequenceGroup(gps[g]);
119    }
120  0 return true;
121    }
122  0 return false;
123    }
124   
 
125  0 toggle @Override
126    public boolean createGroup()
127    {
128   
129  0 SequenceGroup sg = viewport.getSelectionGroup();
130  0 if (sg != null)
131    {
132  0 viewport.getAlignment().addGroup(sg);
133  0 return true;
134    }
135  0 return false;
136    }
137   
 
138  0 toggle @Override
139    public boolean unGroup()
140    {
141  0 SequenceGroup sg = viewport.getSelectionGroup();
142  0 if (sg != null)
143    {
144  0 viewport.getAlignment().deleteGroup(sg);
145  0 return true;
146    }
147  0 return false;
148    }
149   
 
150  0 toggle @Override
151    public boolean deleteGroups()
152    {
153  0 if (viewport.getAlignment().getGroups() != null
154    && viewport.getAlignment().getGroups().size() > 0)
155    {
156  0 viewport.getAlignment().deleteAllGroups();
157  0 viewport.clearSequenceColours();
158  0 viewport.setSelectionGroup(null);
159  0 return true;
160    }
161  0 return false;
162    }
163   
 
164  12 toggle @Override
165    public boolean markColumnsContainingFeatures(boolean invert,
166    boolean extendCurrent, boolean toggle, String featureType)
167    {
168    // JBPNote this routine could also mark rows, not just columns.
169    // need a decent query structure to allow all types of feature searches
170  12 BitSet bs = new BitSet();
171  12 boolean searchSelection = viewport.getSelectionGroup() != null
172    && !extendCurrent;
173  12 SequenceCollectionI sqcol = searchSelection
174    ? viewport.getSelectionGroup()
175    : viewport.getAlignment();
176   
177  12 int nseq = findColumnsWithFeature(featureType, sqcol, bs);
178   
179  12 ColumnSelection cs = viewport.getColumnSelection();
180  12 if (cs == null)
181    {
182  0 cs = new ColumnSelection();
183    }
184   
185  12 if (bs.cardinality() > 0 || invert)
186    {
187  10 boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
188    sqcol.getEndRes(), invert, extendCurrent, toggle);
189  10 if (changed)
190    {
191  9 viewport.setColumnSelection(cs);
192  9 alignPanel.paintAlignment(false, false);
193  9 int columnCount = invert
194    ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
195    - bs.cardinality()
196    : bs.cardinality();
197  9 avcg.setStatus(MessageManager.formatMessage(
198    "label.view_controller_toggled_marked", new String[]
199  9 { toggle ? MessageManager.getString("label.toggled")
200    : MessageManager.getString("label.marked"),
201    String.valueOf(columnCount),
202  9 invert ? MessageManager
203    .getString("label.not_containing")
204    : MessageManager.getString("label.containing"),
205    featureType, Integer.valueOf(nseq).toString() }));
206  9 return true;
207    }
208    }
209    else
210    {
211  2 String key = searchSelection ? "label.no_feature_found_selection"
212    : "label.no_feature_of_type_found";
213  2 avcg.setStatus(
214    MessageManager.formatMessage(key, new String[]
215    { featureType }));
216  2 if (!extendCurrent)
217    {
218  2 cs.clear();
219  2 alignPanel.paintAlignment(false, false);
220    }
221    }
222  3 return false;
223    }
224   
225    /**
226    * Sets a bit in the BitSet for each column (base 0) in the sequence
227    * collection which includes a visible feature of the specified feature type.
228    * Returns the number of sequences which have the feature visible in the
229    * selected range.
230    *
231    * @param featureType
232    * @param sqcol
233    * @param bs
234    * @return
235    */
 
236  20 toggle int findColumnsWithFeature(String featureType, SequenceCollectionI sqcol,
237    BitSet bs)
238    {
239  20 FeatureRenderer fr = alignPanel == null ? null
240    : alignPanel.getFeatureRenderer();
241   
242  20 final int startColumn = sqcol.getStartRes() + 1; // converted to base 1
243  20 final int endColumn = sqcol.getEndRes() + 1;
244  20 List<SequenceI> seqs = sqcol.getSequences();
245  20 int nseq = 0;
246  20 for (SequenceI sq : seqs)
247    {
248  92 if (sq != null)
249    {
250    // int ist = sq.findPosition(sqcol.getStartRes());
251  92 List<SequenceFeature> sfs = sq.findFeatures(startColumn, endColumn,
252    featureType);
253   
254  92 boolean found = false;
255  92 for (SequenceFeature sf : sfs)
256    {
257  545 if (fr.getColour(sf) == null)
258    {
259  3 continue;
260    }
261  542 if (!found)
262    {
263  58 nseq++;
264    }
265  542 found = true;
266   
267  542 int sfStartCol = sq.findIndex(sf.getBegin());
268  542 int sfEndCol = sq.findIndex(sf.getEnd());
269   
270  542 if (sf.isContactFeature())
271    {
272    /*
273    * 'contact' feature - check for 'start' or 'end'
274    * position within the selected region
275    */
276  1 if (sfStartCol >= startColumn && sfStartCol <= endColumn)
277    {
278  1 bs.set(sfStartCol - 1);
279    }
280  1 if (sfEndCol >= startColumn && sfEndCol <= endColumn)
281    {
282  1 bs.set(sfEndCol - 1);
283    }
284  1 continue;
285    }
286   
287    /*
288    * contiguous feature - select feature positions (if any)
289    * within the selected region
290    */
291  541 if (sfStartCol < startColumn)
292    {
293  1 sfStartCol = startColumn;
294    }
295    // not sure what the point of this is
296    // if (sfStartCol < ist)
297    // {
298    // sfStartCol = ist;
299    // }
300  541 if (sfEndCol > endColumn)
301    {
302  4 sfEndCol = endColumn;
303    }
304  25219 for (; sfStartCol <= sfEndCol; sfStartCol++)
305    {
306  24678 bs.set(sfStartCol - 1); // convert to base 0
307    }
308    }
309    }
310    }
311  20 return nseq;
312    }
313   
 
314  0 toggle @Override
315    public void sortAlignmentByFeatureDensity(List<String> typ)
316    {
317  0 String methodText = MessageManager.getString("label.sort_by_density");
318  0 sortByFeatures(typ, methodText, AlignmentSorter.FEATURE_DENSITY);
319    }
320   
321    /**
322    * Sorts the alignment (or current selection) by either average score or
323    * density of the specified feature types, and adds to the command history. If
324    * {@code types} is null, all visible feature types are used for the sort. If
325    * no feature types apply, does nothing.
326    *
327    * @param types
328    * @param methodText
329    * - text shown in Undo/Redo command
330    * @param method
331    * - passed to jalview.analysis.AlignmentSorter.sortByFeatures()
332    */
 
333  0 toggle protected void sortByFeatures(List<String> types, String methodText,
334    final String method)
335    {
336  0 FeatureRenderer fr = alignPanel.getFeatureRenderer();
337  0 if (types == null && fr != null)
338    {
339  0 types = fr.getDisplayedFeatureTypes();
340    }
341  0 if (types.isEmpty())
342    {
343  0 return; // nothing to do
344    }
345  0 List<String> gps = null;
346  0 if (fr != null)
347    {
348  0 gps = fr.getDisplayedFeatureGroups();
349    }
350  0 AlignmentI al = viewport.getAlignment();
351   
352  0 int start, stop;
353  0 SequenceGroup sg = viewport.getSelectionGroup();
354  0 if (sg != null)
355    {
356  0 start = sg.getStartRes();
357  0 stop = sg.getEndRes();
358    }
359    else
360    {
361  0 start = 0;
362  0 stop = al.getWidth();
363    }
364  0 SequenceI[] oldOrder = al.getSequencesArray();
365  0 AlignmentSorter.sortByFeature(types, gps, start, stop, al, method);
366  0 avcg.addHistoryItem(new OrderCommand(methodText, oldOrder,
367    viewport.getAlignment()));
368  0 alignPanel.paintAlignment(true, false);
369   
370    }
371   
 
372  0 toggle @Override
373    public void sortAlignmentByFeatureScore(List<String> typ)
374    {
375  0 String methodText = MessageManager.getString("label.sort_by_score");
376  0 sortByFeatures(typ, methodText, AlignmentSorter.FEATURE_SCORE);
377    }
378   
 
379  4 toggle @Override
380    public boolean parseFeaturesFile(Object file, DataSourceType protocol,
381    boolean relaxedIdMatching)
382    {
383  4 boolean featuresAdded = false;
384  4 FeatureRenderer fr = alignPanel.getFeatureRenderer();
385  4 try
386    {
387  4 featuresAdded = new FeaturesFile(false, file, protocol).parse(
388    viewport.getAlignment().getDataset(), fr.getFeatureColours(),
389    fr.getFeatureFilters(), false, relaxedIdMatching);
390    } catch (Exception ex)
391    {
392  0 ex.printStackTrace();
393    }
394   
395  4 if (featuresAdded)
396    {
397  4 avcg.refreshFeatureUI(true);
398  4 if (fr != null)
399    {
400    // update the min/max ranges where necessary
401  4 fr.findAllFeatures(true);
402    }
403  4 if (avcg.getFeatureSettingsUI() != null)
404    {
405  0 avcg.getFeatureSettingsUI().discoverAllFeatureData();
406    }
407  4 alignPanel.paintAlignment(true, true);
408    }
409   
410  4 return featuresAdded;
411   
412    }
413   
 
414  2 toggle @Override
415    public boolean markHighlightedColumns(boolean invert,
416    boolean extendCurrent, boolean toggle)
417    {
418  2 if (!viewport.hasSearchResults())
419    {
420    // do nothing if no selection exists
421  0 return false;
422    }
423    // JBPNote this routine could also mark rows, not just columns.
424  2 BitSet bs = new BitSet();
425  2 SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null
426    || extendCurrent) ? viewport.getAlignment()
427    : viewport.getSelectionGroup();
428   
429    // this could be a lambda... - the remains of the method is boilerplate,
430    // except for the different messages for reporting selection.
431  2 int nseq = viewport.getSearchResults().markColumns(sqcol, bs);
432   
433  2 ColumnSelection cs = viewport.getColumnSelection();
434  2 if (cs == null)
435    {
436  0 cs = new ColumnSelection();
437    }
438   
439  2 if (bs.cardinality() > 0 || invert)
440    {
441  2 boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
442    sqcol.getEndRes(), invert, extendCurrent, toggle);
443  2 if (changed)
444    {
445  2 viewport.setColumnSelection(cs);
446  2 alignPanel.paintAlignment(false, false);
447  2 int columnCount = invert
448    ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
449    - bs.cardinality()
450    : bs.cardinality();
451  2 avcg.setStatus(MessageManager.formatMessage(
452    "label.view_controller_toggled_marked", new String[]
453  2 { toggle ? MessageManager.getString("label.toggled")
454    : MessageManager.getString("label.marked"),
455    String.valueOf(columnCount),
456  2 invert ? MessageManager
457    .getString("label.not_containing")
458    : MessageManager.getString("label.containing"),
459    "Highlight", Integer.valueOf(nseq).toString() }));
460  2 return true;
461    }
462    }
463    else
464    {
465  0 avcg.setStatus(MessageManager
466    .getString("label.no_highlighted_regions_marked"));
467  0 if (!extendCurrent)
468    {
469  0 cs.clear();
470  0 alignPanel.paintAlignment(false, false);
471    }
472    }
473  0 return false;
474    }
475   
 
476  0 toggle @Override
477    public boolean copyHighlightedRegionsToClipboard()
478    {
479  0 if (!viewport.hasSearchResults())
480    {
481    // do nothing if no selection exists
482  0 return false;
483    }
484   
485  0 SearchResultsI searchResults = viewport.getSearchResults();
486  0 if (searchResults.isEmpty())
487    {
488  0 return false; // shouldn't happen
489    }
490  0 List<SequenceI> seqs = searchResults.getMatchingSubSequences();
491   
492    // TODO: pass in hiddenColumns according to intersection of searchResults
493    // and visible columns. Currently this isn't done, since each contig becomes
494    // a single subsequence
495  0 Desktop.jalviewClipboard = new Object[] {
496    seqs.toArray(new SequenceI[0]),
497    alignPanel.getAlignment().getDataset(), null };
498  0 avcg.setStatus(MessageManager.formatMessage(
499    "label.copied_sequences_to_clipboard", seqs.size()));
500    // Technically we should return false, since view has not changed
501  0 return false;
502    }
503   
 
504  0 toggle @Override
505    public boolean justify_Region(boolean left)
506    {
507  0 AlignmentI al = viewport.getAlignment();
508  0 SequenceGroup reg = viewport.getSelectionGroup();
509  0 int from, to;
510  0 List<SequenceI> seqs;
511   
512  0 from = 0;
513  0 to = al.getWidth() - 1;
514  0 seqs = al.getSequences();
515  0 if (reg != null)
516    {
517  0 seqs = reg.getSequences();
518  0 from = reg.getStartRes();
519  0 to = reg.getEndRes();
520    }
521   
522  0 if ((to - from) < 1)
523    {
524  0 return false;
525    }
526   
527  0 al.padGaps();
528  0 jalview.commands.JustifyLeftOrRightCommand finalEdit = new jalview.commands.JustifyLeftOrRightCommand(
529  0 "Justify " + (left ? "Left" : "Right"), left, seqs, from, to,
530    al);
531  0 avcg.addHistoryItem(finalEdit);
532  0 viewport.notifyAlignmentChanged();
533  0 return true;
534    }
535    }