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