4d734c7b179cce6d778760ba1e7b70b18d46c3e6
[jalview.git] / src / jalview / controller / AlignViewController.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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 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.util.MessageManager;
37
38 import java.awt.Color;
39 import java.util.ArrayList;
40 import java.util.BitSet;
41 import java.util.List;
42
43 public class AlignViewController implements AlignViewControllerI
44 {
45   AlignViewportI viewport = null;
46
47   AlignmentViewPanel alignPanel = null;
48
49   /**
50    * the GUI container that is handling interactions with the user
51    */
52   private AlignViewControllerGuiI avcg;
53
54   @Override
55   protected void finalize() throws Throwable
56   {
57     viewport = null;
58     alignPanel = null;
59     avcg = null;
60   };
61
62   public AlignViewController(AlignViewControllerGuiI alignFrame,
63           AlignViewportI viewport, AlignmentViewPanel alignPanel)
64   {
65     this.avcg = alignFrame;
66     this.viewport = viewport;
67     this.alignPanel = alignPanel;
68   }
69
70   @Override
71   public void setViewportAndAlignmentPanel(AlignViewportI viewport,
72           AlignmentViewPanel alignPanel)
73   {
74     this.alignPanel = alignPanel;
75     this.viewport = viewport;
76
77   }
78
79   @Override
80   public boolean makeGroupsFromSelection()
81   {
82
83     if (viewport.getSelectionGroup() != null)
84     {
85       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
86               viewport.getSequenceSelection(),
87               viewport.getAlignmentView(true).getSequenceStrings(
88                       viewport.getGapCharacter()), viewport.getAlignment()
89                       .getGroups());
90       viewport.getAlignment().deleteAllGroups();
91       viewport.clearSequenceColours();
92       viewport.setSelectionGroup(null);
93       // set view properties for each group
94       for (int g = 0; g < gps.length; g++)
95       {
96         // gps[g].setShowunconserved(viewport.getShowUnconserved());
97         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
98         viewport.getAlignment().addGroup(gps[g]);
99         Color col = new Color((int) (Math.random() * 255),
100                 (int) (Math.random() * 255), (int) (Math.random() * 255));
101         col = col.brighter();
102         for (SequenceI sq : gps[g].getSequences(null))
103         {
104           viewport.setSequenceColour(sq, col);
105         }
106       }
107       return true;
108     }
109     return false;
110   }
111
112   @Override
113   public boolean createGroup()
114   {
115
116     SequenceGroup sg = viewport.getSelectionGroup();
117     if (sg != null)
118     {
119       viewport.getAlignment().addGroup(sg);
120       return true;
121     }
122     return false;
123   }
124
125   @Override
126   public boolean unGroup()
127   {
128     SequenceGroup sg = viewport.getSelectionGroup();
129     if (sg != null)
130     {
131       viewport.getAlignment().deleteGroup(sg);
132       return true;
133     }
134     return false;
135   }
136
137   @Override
138   public boolean deleteGroups()
139   {
140     if (viewport.getAlignment().getGroups() != null
141             && viewport.getAlignment().getGroups().size() > 0)
142     {
143       viewport.getAlignment().deleteAllGroups();
144       viewport.clearSequenceColours();
145       viewport.setSelectionGroup(null);
146       return true;
147     }
148     return false;
149   }
150
151   @Override
152   public boolean markColumnsContainingFeatures(boolean invert,
153           boolean extendCurrent, boolean toggle, String featureType)
154   {
155     // JBPNote this routine could also mark rows, not just columns.
156     // need a decent query structure to allow all types of feature searches
157     BitSet bs = new BitSet();
158     int alw, alStart;
159     SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null ? viewport
160             .getAlignment() : viewport.getSelectionGroup());
161     alStart = sqcol.getStartRes();
162     alw = sqcol.getEndRes() + 1;
163     List<SequenceI> seqs = sqcol.getSequences();
164     int nseq = 0;
165     for (SequenceI sq : seqs)
166     {
167       int tfeat = 0;
168       if (sq != null)
169       {
170         SequenceI dsq = sq.getDatasetSequence();
171         while (dsq.getDatasetSequence() != null)
172         {
173           dsq = dsq.getDatasetSequence();
174         }
175         ;
176         SequenceFeature[] sf = dsq.getSequenceFeatures();
177         if (sf != null)
178         {
179           int ist = sq.findIndex(sq.getStart());
180           int iend = sq.findIndex(sq.getEnd());
181           if (iend < alStart || ist > alw)
182           {
183             // sequence not in region
184             continue;
185           }
186           for (SequenceFeature sfpos : sf)
187           {
188             // future functionalty - featureType == null means mark columns
189             // containing all displayed features
190             if (sfpos != null && (featureType.equals(sfpos.getType())))
191             {
192               tfeat++;
193               // optimisation - could consider 'spos,apos' like cursor argument
194               // - findIndex wastes time by starting from first character and
195               // counting
196
197               int i = sq.findIndex(sfpos.getBegin());
198               int j = sq.findIndex(sfpos.getEnd());
199               if (j < alStart || i > alw)
200               {
201                 // feature is outside selected region
202                 continue;
203               }
204               if (i < alStart)
205               {
206                 i = alStart;
207               }
208               if (i < ist)
209               {
210                 i = ist;
211               }
212               if (j > alw)
213               {
214                 j = alw;
215               }
216               for (; i <= j; i++)
217               {
218                 bs.set(i - 1);
219               }
220             }
221           }
222         }
223
224         if (tfeat > 0)
225         {
226           nseq++;
227         }
228       }
229     }
230     ColumnSelection cs = viewport.getColumnSelection();
231     if (bs.cardinality() > 0 || invert)
232     {
233       if (cs == null)
234       {
235         cs = new ColumnSelection();
236       }
237       else
238       {
239         if (!extendCurrent)
240         {
241           cs.clear();
242         }
243       }
244       if (invert)
245       {
246         // invert only in the currently selected sequence region
247         for (int i = bs.nextClearBit(alStart), ibs = bs.nextSetBit(alStart); i >= alStart
248                 && i < (alw);)
249         {
250           if (ibs < 0 || i < ibs)
251           {
252             if (toggle && cs.contains(i))
253             {
254               cs.removeElement(i++);
255             }
256             else
257             {
258               cs.addElement(i++);
259             }
260           }
261           else
262           {
263             i = bs.nextClearBit(ibs);
264             ibs = bs.nextSetBit(i);
265           }
266         }
267       }
268       else
269       {
270         for (int i = bs.nextSetBit(alStart); i >= alStart; i = bs
271                 .nextSetBit(i + 1))
272         {
273           if (toggle && cs.contains(i))
274           {
275             cs.removeElement(i);
276           }
277           else
278           {
279             cs.addElement(i);
280           }
281         }
282       }
283       viewport.setColumnSelection(cs);
284       alignPanel.paintAlignment(true);
285       avcg.setStatus(MessageManager.formatMessage("label.view_controller_toggled_marked",
286                   new String[]{
287                                 (toggle ? MessageManager.getString("label.toggled") : MessageManager.getString("label.marked")),
288                                 (invert ? (Integer.valueOf((alw - alStart) - bs.cardinality()).toString()):(Integer.valueOf(bs.cardinality()).toString())),
289                                 featureType, Integer.valueOf(nseq).toString()
290                         }));
291       return true;
292     }
293     else
294     {
295       avcg.setStatus(MessageManager.formatMessage("label.no_feature_of_type_found", new String[]{featureType}));
296       if (!extendCurrent && cs != null)
297       {
298         cs.clear();
299         alignPanel.paintAlignment(true);
300       }
301       return false;
302     }
303   }
304
305
306
307   @Override
308   public void sortAlignmentByFeatureDensity(String[] typ)
309   {
310     sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
311   }
312
313   protected void sortBy(String[] typ, String methodText, final String method)
314   {
315     FeatureRenderer fr = alignPanel.getFeatureRenderer();
316     if (typ == null)
317     {
318       typ = fr==null ? null : fr.getDisplayedFeatureTypes();
319     }
320     String gps[] = null;
321     gps = fr==null ? null : fr.getDisplayedFeatureGroups();
322     if (typ != null)
323     {
324       ArrayList types = new ArrayList();
325       for (int i = 0; i < typ.length; i++)
326       {
327         if (typ[i] != null)
328         {
329           types.add(typ[i]);
330         }
331         typ = new String[types.size()];
332         types.toArray(typ);
333       }
334     }
335     if (gps != null)
336     {
337       ArrayList grps = new ArrayList();
338
339       for (int i = 0; i < gps.length; i++)
340       {
341         if (gps[i] != null)
342         {
343           grps.add(gps[i]);
344         }
345       }
346       gps = new String[grps.size()];
347       grps.toArray(gps);
348     }
349     AlignmentI al = viewport.getAlignment();
350
351     int start, stop;
352     SequenceGroup sg = viewport.getSelectionGroup();
353     if (sg != null)
354     {
355       start = sg.getStartRes();
356       stop = sg.getEndRes();
357     }
358     else
359     {
360       start = 0;
361       stop = al.getWidth();
362     }
363     SequenceI[] oldOrder = al.getSequencesArray();
364     AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
365     avcg.addHistoryItem(new OrderCommand(methodText, oldOrder, viewport
366             .getAlignment()));
367     alignPanel.paintAlignment(true);
368
369   }
370
371   @Override
372   public void sortAlignmentByFeatureScore(String[] typ)
373   {
374     sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
375   }
376 }