Merge branch 'releases/Release_2_11_4_Branch'
[jalview.git] / 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 java.awt.Color;
24 import java.util.BitSet;
25 import java.util.List;
26
27 import jalview.api.AlignViewControllerGuiI;
28 import jalview.api.AlignViewControllerI;
29 import jalview.api.AlignViewportI;
30 import jalview.api.AlignmentViewPanel;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.AnnotatedCollectionI;
33 import jalview.datamodel.ColumnSelection;
34 import jalview.datamodel.SequenceCollectionI;
35 import jalview.datamodel.SequenceFeature;
36 import jalview.datamodel.SequenceGroup;
37 import jalview.datamodel.SequenceI;
38 import jalview.util.MessageManager;
39
40 public class AlignViewController implements AlignViewControllerI
41 {
42   AlignViewportI viewport = null;
43
44   AlignmentViewPanel alignPanel = null;
45
46   /**
47    * the GUI container that is handling interactions with the user
48    */
49   private AlignViewControllerGuiI avcg;
50
51   @Override
52   protected void finalize() throws Throwable
53   {
54     viewport = null;
55     alignPanel = null;
56     avcg = null;
57   };
58
59   public AlignViewController(AlignViewControllerGuiI alignFrame,
60           AlignViewportI viewport, AlignmentViewPanel alignPanel)
61   {
62     this.avcg = alignFrame;
63     this.viewport = viewport;
64     this.alignPanel = alignPanel;
65   }
66
67   @Override
68   public void setViewportAndAlignmentPanel(AlignViewportI viewport,
69           AlignmentViewPanel alignPanel)
70   {
71     this.alignPanel = alignPanel;
72     this.viewport = viewport;
73
74   }
75
76   @Override
77   public boolean makeGroupsFromSelection()
78   {
79
80     if (viewport.getSelectionGroup() != null)
81     {
82       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
83               viewport.getSequenceSelection(),
84               viewport.getAlignmentView(true).getSequenceStrings(
85                       viewport.getGapCharacter()), viewport.getAlignment()
86                       .getGroups());
87       viewport.getAlignment().deleteAllGroups();
88       viewport.clearSequenceColours();
89       viewport.setSelectionGroup(null);
90       // set view properties for each group
91       for (int g = 0; g < gps.length; g++)
92       {
93         // gps[g].setShowunconserved(viewport.getShowUnconserved());
94         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
95         viewport.getAlignment().addGroup(gps[g]);
96         Color col = new Color((int) (Math.random() * 255),
97                 (int) (Math.random() * 255), (int) (Math.random() * 255));
98         col = col.brighter();
99         for (SequenceI sq : gps[g].getSequences(null))
100           viewport.setSequenceColour(sq, col);
101       }
102       return true;
103     }
104     return false;
105   }
106
107   @Override
108   public boolean createGroup()
109   {
110
111     SequenceGroup sg = viewport.getSelectionGroup();
112     if (sg != null)
113     {
114       viewport.getAlignment().addGroup(sg);
115       return true;
116     }
117     return false;
118   }
119
120   @Override
121   public boolean unGroup()
122   {
123     SequenceGroup sg = viewport.getSelectionGroup();
124     if (sg != null)
125     {
126       viewport.getAlignment().deleteGroup(sg);
127       return true;
128     }
129     return false;
130   }
131
132   @Override
133   public boolean deleteGroups()
134   {
135     if (viewport.getAlignment().getGroups() != null
136             && viewport.getAlignment().getGroups().size() > 0)
137     {
138       viewport.getAlignment().deleteAllGroups();
139       viewport.clearSequenceColours();
140       viewport.setSelectionGroup(null);
141       return true;
142     }
143     return false;
144   }
145
146   @Override
147   public boolean markColumnsContainingFeatures(boolean invert,
148           boolean extendCurrent, boolean toggle, String featureType)
149   {
150     // JBPNote this routine could also mark rows, not just columns.
151     // need a decent query structure to allow all types of feature searches
152     BitSet bs = new BitSet();
153     int alw, alStart;
154     SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null ? viewport
155             .getAlignment() : viewport.getSelectionGroup());
156     alStart = sqcol.getStartRes();
157     alw = sqcol.getEndRes() + 1;
158     List<SequenceI> seqs = sqcol.getSequences();
159     int nseq = 0;
160     for (SequenceI sq : seqs)
161     {
162       int tfeat = 0;
163       if (sq != null)
164       {
165         SequenceI dsq = sq.getDatasetSequence();
166         while (dsq.getDatasetSequence() != null)
167         {
168           dsq = dsq.getDatasetSequence();
169         }
170         ;
171         SequenceFeature[] sf = dsq.getSequenceFeatures();
172         if (sf != null)
173         {
174           int ist = sq.findIndex(sq.getStart());
175           int iend = sq.findIndex(sq.getEnd());
176           if (iend < alStart || ist > alw)
177           {
178             // sequence not in region
179             continue;
180           }
181           for (SequenceFeature sfpos : sf)
182           {
183             // future functionalty - featureType == null means mark columns
184             // containing all displayed features
185             if (sfpos != null && (featureType.equals(sfpos.getType())))
186             {
187               tfeat++;
188               // optimisation - could consider 'spos,apos' like cursor argument
189               // - findIndex wastes time by starting from first character and
190               // counting
191
192               int i = sq.findIndex(sfpos.getBegin());
193               int j = sq.findIndex(sfpos.getEnd());
194               if (j < alStart || i > alw)
195               {
196                 // feature is outside selected region
197                 continue;
198               }
199               if (i < alStart)
200               {
201                 i = alStart;
202               }
203               if (i < ist)
204               {
205                 i = ist;
206               }
207               if (j > alw)
208               {
209                 j = alw;
210               }
211               for (; i <= j; i++)
212               {
213                 bs.set(i - 1);
214               }
215             }
216           }
217         }
218
219         if (tfeat > 0)
220         {
221           nseq++;
222         }
223       }
224     }
225     ColumnSelection cs = viewport.getColumnSelection();
226     if (bs.cardinality() > 0 || invert)
227     {
228       if (cs == null)
229       {
230         cs = new ColumnSelection();
231       }
232       else
233       {
234         if (!extendCurrent)
235         {
236           cs.clear();
237         }
238       }
239       if (invert)
240       {
241         // invert only in the currently selected sequence region
242         for (int i = bs.nextClearBit(alStart), ibs = bs.nextSetBit(alStart); i >= alStart
243                 && i < (alw);)
244         {
245           if (ibs < 0 || i < ibs)
246           {
247             if (toggle && cs.contains(i))
248             {
249               cs.removeElement(i++);
250             }
251             else
252             {
253               cs.addElement(i++);
254             }
255           }
256           else
257           {
258             i = bs.nextClearBit(ibs);
259             ibs = bs.nextSetBit(i);
260           }
261         }
262       }
263       else
264       {
265         for (int i = bs.nextSetBit(alStart); i >= alStart; i = bs
266                 .nextSetBit(i + 1))
267         {
268           if (toggle && cs.contains(i))
269           {
270             cs.removeElement(i);
271           }
272           else
273           {
274             cs.addElement(i);
275           }
276         }
277       }
278       viewport.setColumnSelection(cs);
279       alignPanel.paintAlignment(true);
280       avcg.setStatus(MessageManager.formatMessage("label.view_controller_toggled_marked",
281                   new String[]{
282                                 (toggle ? MessageManager.getString("label.toggled") : MessageManager.getString("label.marked")),
283                                 (invert ? (Integer.valueOf((alw - alStart) - bs.cardinality()).toString()):(Integer.valueOf(bs.cardinality()).toString())),
284                                 featureType, Integer.valueOf(nseq).toString()
285                         }));
286       return true;
287     }
288     else
289     {
290       avcg.setStatus(MessageManager.formatMessage("label.no_feature_of_type_found", new String[]{featureType}));
291       if (!extendCurrent && cs != null)
292       {
293         cs.clear();
294         alignPanel.paintAlignment(true);
295       }
296       return false;
297     }
298   }
299 }