2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.controller;
23 import jalview.analysis.AlignmentSorter;
24 import jalview.api.AlignViewControllerGuiI;
25 import jalview.api.AlignViewControllerI;
26 import jalview.api.AlignViewportI;
27 import jalview.api.AlignmentViewPanel;
28 import jalview.api.FeatureRenderer;
29 import jalview.commands.OrderCommand;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.ColumnSelection;
32 import jalview.datamodel.SequenceCollectionI;
33 import jalview.datamodel.SequenceFeature;
34 import jalview.datamodel.SequenceGroup;
35 import jalview.datamodel.SequenceI;
36 import jalview.io.FeaturesFile;
37 import jalview.util.MessageManager;
39 import java.awt.Color;
40 import java.util.BitSet;
41 import java.util.List;
43 public class AlignViewController implements AlignViewControllerI
45 AlignViewportI viewport = null;
47 AlignmentViewPanel alignPanel = null;
50 * the GUI container that is handling interactions with the user
52 private AlignViewControllerGuiI avcg;
55 protected void finalize() throws Throwable
62 public AlignViewController(AlignViewControllerGuiI alignFrame,
63 AlignViewportI viewport, AlignmentViewPanel alignPanel)
65 this.avcg = alignFrame;
66 this.viewport = viewport;
67 this.alignPanel = alignPanel;
71 public void setViewportAndAlignmentPanel(AlignViewportI viewport,
72 AlignmentViewPanel alignPanel)
74 this.alignPanel = alignPanel;
75 this.viewport = viewport;
80 public boolean makeGroupsFromSelection()
82 SequenceGroup sg = viewport.getSelectionGroup();
83 ColumnSelection cs = viewport.getColumnSelection();
84 SequenceGroup[] gps = null;
85 if (sg != null && (cs == null || cs.isEmpty()))
87 gps = jalview.analysis.Grouping.makeGroupsFrom(viewport
88 .getSequenceSelection(), viewport.getAlignmentView(true)
89 .getSequenceStrings(viewport.getGapCharacter()), viewport
90 .getAlignment().getGroups());
96 gps = jalview.analysis.Grouping.makeGroupsFromCols(
97 (sg == null) ? viewport.getAlignment().getSequencesArray()
98 : sg.getSequences().toArray(new SequenceI[0]), cs,
99 viewport.getAlignment().getGroups());
104 viewport.getAlignment().deleteAllGroups();
105 viewport.clearSequenceColours();
106 viewport.setSelectionGroup(null);
107 // set view properties for each group
108 for (int g = 0; g < gps.length; g++)
110 // gps[g].setShowunconserved(viewport.getShowUnconserved());
111 gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
112 viewport.getAlignment().addGroup(gps[g]);
113 Color col = new Color((int) (Math.random() * 255),
114 (int) (Math.random() * 255), (int) (Math.random() * 255));
115 col = col.brighter();
116 for (SequenceI sq : gps[g].getSequences(null))
118 viewport.setSequenceColour(sq, col);
127 public boolean createGroup()
130 SequenceGroup sg = viewport.getSelectionGroup();
133 viewport.getAlignment().addGroup(sg);
140 public boolean unGroup()
142 SequenceGroup sg = viewport.getSelectionGroup();
145 viewport.getAlignment().deleteGroup(sg);
152 public boolean deleteGroups()
154 if (viewport.getAlignment().getGroups() != null
155 && viewport.getAlignment().getGroups().size() > 0)
157 viewport.getAlignment().deleteAllGroups();
158 viewport.clearSequenceColours();
159 viewport.setSelectionGroup(null);
166 public boolean markColumnsContainingFeatures(boolean invert,
167 boolean extendCurrent, boolean toggle, String featureType)
169 // JBPNote this routine could also mark rows, not just columns.
170 // need a decent query structure to allow all types of feature searches
171 BitSet bs = new BitSet();
172 SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null || extendCurrent) ? viewport
173 .getAlignment() : viewport.getSelectionGroup();
175 int nseq = findColumnsWithFeature(featureType, sqcol, bs);
177 ColumnSelection cs = viewport.getColumnSelection();
180 cs = new ColumnSelection();
183 if (bs.cardinality() > 0 || invert)
185 boolean changed = selectMarkedColumns(cs, invert, extendCurrent,
186 toggle, bs, sqcol.getStartRes(), sqcol.getEndRes());
189 viewport.setColumnSelection(cs);
190 alignPanel.paintAlignment(true);
191 int columnCount = invert ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
192 - bs.cardinality() : bs.cardinality();
193 avcg.setStatus(MessageManager.formatMessage(
194 "label.view_controller_toggled_marked",
196 MessageManager.getString(toggle ? "label.toggled"
198 String.valueOf(columnCount),
200 .getString(invert ? "label.not_containing"
201 : "label.containing"),
202 featureType, Integer.valueOf(nseq).toString() }));
208 avcg.setStatus(MessageManager.formatMessage(
209 "label.no_feature_of_type_found",
210 new String[] { featureType }));
211 if (!extendCurrent && cs != null)
214 alignPanel.paintAlignment(true);
221 * Updates the column selection depending on the parameters, and returns true
222 * if any change was made to the selection.
224 * @param columnSelection
225 * the current column selection
227 * if true, deselect marked columns and select unmarked
228 * @param extendCurrent
229 * if true, extend rather than replacing the current column selection
231 * if true, toggle the selection state of marked columns
232 * @param markedColumns
233 * a set identify marked columns
235 * the first column of the range to operate over
237 * the last column of the range to operate over
240 static boolean selectMarkedColumns(ColumnSelection columnSelection,
241 boolean invert, boolean extendCurrent, boolean toggle,
242 BitSet markedColumns, int startCol, int endCol)
244 boolean changed = false;
245 if (!extendCurrent && !toggle)
247 changed = !columnSelection.isEmpty();
248 columnSelection.clear();
252 // invert only in the currently selected sequence region
253 int i = markedColumns.nextClearBit(startCol);
254 int ibs = markedColumns.nextSetBit(startCol);
255 while (i >= startCol && i <= endCol)
257 if (ibs < 0 || i < ibs)
260 if (toggle && columnSelection.contains(i))
262 columnSelection.removeElement(i++);
266 columnSelection.addElement(i++);
271 i = markedColumns.nextClearBit(ibs);
272 ibs = markedColumns.nextSetBit(i);
278 int i = markedColumns.nextSetBit(startCol);
279 while (i >= startCol && i <= endCol)
282 if (toggle && columnSelection.contains(i))
284 columnSelection.removeElement(i);
288 columnSelection.addElement(i);
290 i = markedColumns.nextSetBit(i + 1);
297 * Sets a bit in the BitSet for each column in the sequence collection which
298 * includes the specified feature type. Returns the number of sequences which
299 * have the feature in the selected range.
306 static int findColumnsWithFeature(String featureType,
307 SequenceCollectionI sqcol,
310 final int startPosition = sqcol.getStartRes() + 1; // converted to base 1
311 final int endPosition = sqcol.getEndRes() + 1;
312 List<SequenceI> seqs = sqcol.getSequences();
314 for (SequenceI sq : seqs)
316 boolean sequenceHasFeature = false;
319 SequenceFeature[] sfs = sq.getSequenceFeatures();
322 int ist = sq.findIndex(sq.getStart());
323 int iend = sq.findIndex(sq.getEnd());
324 if (iend < startPosition || ist > endPosition)
326 // sequence not in region
329 for (SequenceFeature sf : sfs)
331 // future functionality - featureType == null means mark columns
332 // containing all displayed features
333 if (sf != null && (featureType.equals(sf.getType())))
335 // optimisation - could consider 'spos,apos' like cursor argument
336 // - findIndex wastes time by starting from first character and
339 int i = sq.findIndex(sf.getBegin());
340 int j = sq.findIndex(sf.getEnd());
341 if (j < startPosition || i > endPosition)
343 // feature is outside selected region
346 sequenceHasFeature = true;
347 if (i < startPosition)
367 if (sequenceHasFeature)
377 public void sortAlignmentByFeatureDensity(List<String> typ)
379 sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
382 protected void sortBy(List<String> typ, String methodText,
385 FeatureRenderer fr = alignPanel.getFeatureRenderer();
386 if (typ == null && fr != null)
388 typ = fr.getDisplayedFeatureTypes();
390 List<String> gps = null;
393 gps = fr.getDisplayedFeatureGroups();
395 AlignmentI al = viewport.getAlignment();
398 SequenceGroup sg = viewport.getSelectionGroup();
401 start = sg.getStartRes();
402 stop = sg.getEndRes();
407 stop = al.getWidth();
409 SequenceI[] oldOrder = al.getSequencesArray();
410 AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
411 avcg.addHistoryItem(new OrderCommand(methodText, oldOrder, viewport
413 alignPanel.paintAlignment(true);
418 public void sortAlignmentByFeatureScore(List<String> typ)
420 sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
424 public boolean parseFeaturesFile(String file, String protocol,
425 boolean relaxedIdMatching)
427 boolean featuresFile = false;
430 featuresFile = new FeaturesFile(false, file, protocol).parse(viewport
431 .getAlignment().getDataset(), alignPanel.getFeatureRenderer()
432 .getFeatureColours(), false, relaxedIdMatching);
433 } catch (Exception ex)
435 ex.printStackTrace();
440 avcg.refreshFeatureUI(true);
441 if (alignPanel.getFeatureRenderer() != null)
443 // update the min/max ranges where necessary
444 alignPanel.getFeatureRenderer().findAllFeatures(true);
446 if (avcg.getFeatureSettingsUI() != null)
448 avcg.getFeatureSettingsUI().discoverAllFeatureData();
450 alignPanel.paintAlignment(true);