Feature rendering in groups
[jalview.git] / src / jalview / appletgui / FeatureSettings.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.appletgui;\r
20 \r
21 import jalview.datamodel.*;\r
22 import java.awt.*;\r
23 import java.util.*;\r
24 import java.awt.event.*;\r
25 \r
26 \r
27 public class FeatureSettings extends Panel implements ItemListener,\r
28     MouseListener, MouseMotionListener\r
29 {\r
30   FeatureRenderer fr;\r
31   AlignmentPanel ap;\r
32   AlignViewport av;\r
33   Frame frame;\r
34   Panel groupPanel;\r
35   Panel featurePanel = new Panel();\r
36   ScrollPane scrollPane;\r
37   boolean alignmentHasFeatures = false;\r
38 \r
39   public FeatureSettings(AlignViewport av, final AlignmentPanel ap)\r
40   {\r
41     this.ap = ap;\r
42     this.av = av;\r
43     fr = ap.seqPanel.seqCanvas.getFeatureRenderer();\r
44 \r
45     setTableData();\r
46 \r
47     this.setLayout(new BorderLayout());\r
48     scrollPane = new ScrollPane();\r
49     scrollPane.add(featurePanel);\r
50     if (alignmentHasFeatures)\r
51       add(scrollPane, BorderLayout.CENTER);\r
52 \r
53     if(groupPanel!=null)\r
54     {\r
55       groupPanel.setLayout(\r
56           new GridLayout( fr.featureGroups.size() / 4 + 1, 4));\r
57       groupPanel.validate();\r
58 \r
59       add(groupPanel, BorderLayout.NORTH);\r
60     }\r
61     frame = new Frame();\r
62     frame.add(this);\r
63     int height = featurePanel.getComponentCount()*50 +30;\r
64 \r
65     height = Math.max(100, height);\r
66     height = Math.min(400, height);\r
67 \r
68     jalview.bin.JalviewLite.addFrame(frame, "Feature Settings", 280,\r
69                                      height);\r
70   }\r
71 \r
72   public void paint(Graphics g)\r
73   {\r
74     g.setColor(Color.black);\r
75     g.drawString("No Features added to this alignment!!", 10, 20);\r
76   }\r
77 \r
78   void setTableData()\r
79   {\r
80     alignmentHasFeatures = false;\r
81 \r
82     if(fr.featureGroups==null)\r
83       fr.featureGroups = new Hashtable();\r
84 \r
85     Vector allFeatures = new Vector();\r
86     Vector allGroups = new Vector();\r
87     SequenceFeature[] tmpfeatures;\r
88     String group;\r
89 \r
90 \r
91     for (int i = 0; i < av.alignment.getHeight(); i++)\r
92     {\r
93       if (av.alignment.getSequenceAt(i).getSequenceFeatures() == null)\r
94         continue;\r
95 \r
96       alignmentHasFeatures = true;\r
97 \r
98       tmpfeatures = av.alignment.getSequenceAt(i).getSequenceFeatures();\r
99       int index = 0;\r
100       while (index < tmpfeatures.length)\r
101       {\r
102         if(tmpfeatures[index].getFeatureGroup()!=null)\r
103         {\r
104           group = tmpfeatures[index].featureGroup;\r
105           if(!allGroups.contains(group))\r
106            {\r
107              allGroups.addElement(group);\r
108 \r
109              boolean visible = true;\r
110              if (fr.featureGroups.containsKey(group))\r
111              {\r
112                visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();\r
113              }\r
114 \r
115              fr.featureGroups.put(group, new Boolean(visible));\r
116 \r
117              if (groupPanel == null)\r
118              {\r
119                groupPanel = new Panel();\r
120              }\r
121 \r
122              Checkbox check = new Checkbox(group, visible);\r
123              check.setFont(new Font("Serif", Font.BOLD, 12));\r
124              check.addItemListener(this);\r
125              groupPanel.add(check);\r
126            }\r
127         }\r
128 \r
129         if (!allFeatures.contains(tmpfeatures[index].getType()))\r
130         {\r
131             allFeatures.addElement(tmpfeatures[index].getType());\r
132         }\r
133          index ++;\r
134       }\r
135     }\r
136 \r
137     resetTable(false);\r
138   }\r
139 \r
140  //This routine adds and removes checkboxes depending on\r
141  //Group selection states\r
142   void resetTable(boolean groupsChanged)\r
143   {\r
144     SequenceFeature [] tmpfeatures;\r
145     String group=null, type;\r
146     Vector visibleChecks = new Vector();\r
147 \r
148      for (int i = 0; i < av.alignment.getHeight(); i++)\r
149      {\r
150          if (av.alignment.getSequenceAt(i).getSequenceFeatures() == null)\r
151            continue;\r
152 \r
153          tmpfeatures = av.alignment.getSequenceAt(i).getSequenceFeatures();\r
154          int index = 0;\r
155          while (index < tmpfeatures.length)\r
156          {\r
157            group = tmpfeatures[index].featureGroup;\r
158 \r
159            if (group==null || fr.featureGroups.get(group)==null ||\r
160                ((Boolean) fr.featureGroups.get(group)).booleanValue())\r
161            {\r
162              type = tmpfeatures[index].getType();\r
163              if(!visibleChecks.contains(type) )\r
164              {\r
165                visibleChecks.addElement(type);\r
166              }\r
167            }\r
168            index++;\r
169          }\r
170      }\r
171 \r
172        Component[] comps;\r
173        int cSize = featurePanel.getComponentCount();\r
174        Checkbox check;\r
175        //This will remove any checkboxes which shouldn't be\r
176        //visible\r
177        for (int i = 0; i < cSize; i++)\r
178        {\r
179          comps = featurePanel.getComponents();\r
180          check = (Checkbox) comps[i];\r
181          if (!visibleChecks.contains(check.getLabel()))\r
182          {\r
183            featurePanel.remove(i);\r
184            cSize --;\r
185            i--;\r
186          }\r
187        }\r
188 \r
189        if(fr.renderOrder!=null)\r
190        {\r
191          //First add the checks in the previous render order,\r
192          //in case the window has been closed and reopened\r
193          for(int ro=fr.renderOrder.length-1; ro>-1; ro--)\r
194          {\r
195               String item = fr.renderOrder[ro];\r
196 \r
197               if(!visibleChecks.contains(item))\r
198                 continue;\r
199 \r
200               visibleChecks.removeElement(item);\r
201 \r
202               addCheck(false, item);\r
203          }\r
204        }\r
205 \r
206        // now add checkboxes which should be visible,\r
207        // if they have not already been added\r
208        Enumeration en = visibleChecks.elements();\r
209        while(en.hasMoreElements())\r
210        {\r
211          addCheck(groupsChanged, en.nextElement().toString());\r
212        }\r
213 \r
214 \r
215    featurePanel.setLayout(new GridLayout(featurePanel.getComponentCount(), 1, 10,5));\r
216    featurePanel.validate();\r
217 \r
218 \r
219    if(scrollPane!=null)\r
220      scrollPane.validate();\r
221 \r
222    itemStateChanged(null);\r
223   }\r
224 \r
225   void addCheck(boolean groupsChanged, String type)\r
226   {\r
227     boolean addCheck;\r
228     Component [] comps = featurePanel.getComponents();\r
229     Checkbox check;\r
230     addCheck = true;\r
231     for (int i = 0; i < featurePanel.getComponentCount(); i++)\r
232     {\r
233       check = (Checkbox) comps[i];\r
234       if (check.getLabel().equals(type))\r
235       {\r
236         addCheck = false;\r
237         break;\r
238       }\r
239     }\r
240 \r
241     if (addCheck)\r
242     {\r
243       boolean selected = false;\r
244       if (groupsChanged || av.featuresDisplayed.containsKey(type))\r
245       {\r
246         selected = true;\r
247       }\r
248 \r
249       check = new Checkbox(type, selected);\r
250       check.addMouseListener(this);\r
251       check.addMouseMotionListener(this);\r
252       check.setBackground(fr.getColour(type));\r
253       check.addItemListener(this);\r
254       featurePanel.add(check);\r
255     }\r
256   }\r
257 \r
258   public void itemStateChanged(ItemEvent evt)\r
259   {\r
260     if (evt != null)\r
261     {\r
262       //Is the source a top level featureGroup?\r
263       Checkbox source = (Checkbox) evt.getSource();\r
264       if (fr.featureGroups.containsKey(source.getLabel()))\r
265       {\r
266         fr.featureGroups.put(source.getLabel(), new Boolean(source.getState()));\r
267         ap.seqPanel.seqCanvas.repaint();\r
268         if (ap.overviewPanel != null)\r
269           ap.overviewPanel.updateOverviewImage();\r
270 \r
271         resetTable(true);\r
272         return;\r
273       }\r
274     }\r
275 \r
276       Component[] comps = featurePanel.getComponents();\r
277       int cSize = comps.length;\r
278 \r
279       Object[][] tmp = new Object[cSize][3];\r
280       int tmpSize = 0;\r
281       for (int i = 0; i < cSize; i++)\r
282       {\r
283         Checkbox check = (Checkbox) comps[i];\r
284         tmp[tmpSize][0] = check.getLabel();\r
285         tmp[tmpSize][1] = fr.getColour(check.getLabel());\r
286         tmp[tmpSize][2] = new Boolean(check.getState());\r
287         tmpSize++;\r
288       }\r
289 \r
290       Object[][]data = new Object[tmpSize][3];\r
291       System.arraycopy(tmp, 0, data,0, tmpSize);\r
292 \r
293       fr.setFeaturePriority(data);\r
294       ap.seqPanel.seqCanvas.repaint();\r
295       if (ap.overviewPanel != null)\r
296         ap.overviewPanel.updateOverviewImage();\r
297   }\r
298 \r
299   Checkbox selectedCheck;\r
300   boolean dragging = false;\r
301 \r
302   public void mousePressed(MouseEvent evt)\r
303   {\r
304     selectedCheck = (Checkbox)evt.getSource();\r
305   }\r
306 \r
307   public void mouseDragged(MouseEvent evt)\r
308   {\r
309       dragging = true;\r
310   }\r
311 \r
312   public void mouseReleased(MouseEvent evt)\r
313   {\r
314     Component comp = null;\r
315     Checkbox  target = null;\r
316 \r
317     int height = evt.getY()+evt.getComponent().getLocation().y;\r
318 \r
319     if(height > this.getSize().height)\r
320      {\r
321        comp = featurePanel.getComponent(featurePanel.getComponentCount()-1);\r
322      }\r
323      else if(height < 0)\r
324      {\r
325        comp = featurePanel.getComponent(0);\r
326      }\r
327      else\r
328      {\r
329        comp = featurePanel.getComponentAt(evt.getX(),\r
330                                   evt.getY() +\r
331                                   evt.getComponent().getLocation().y);\r
332      }\r
333 \r
334     if(comp!=null && comp instanceof Checkbox)\r
335       target = (Checkbox)comp;\r
336 \r
337     if (   selectedCheck != null\r
338         && target != null\r
339         && selectedCheck != target)\r
340     {\r
341       int targetIndex = -1;\r
342       for(int i=0; i<featurePanel.getComponentCount(); i++)\r
343       {\r
344           if(target==featurePanel.getComponent(i))\r
345           { targetIndex = i; break; }\r
346       }\r
347 \r
348       featurePanel.remove(selectedCheck);\r
349       featurePanel.add(selectedCheck, targetIndex);\r
350       featurePanel.validate();\r
351       itemStateChanged(null);\r
352     }\r
353   }\r
354 \r
355   public void setUserColour(String feature, Color col)\r
356   {\r
357     fr.setColour(feature, col);\r
358     featurePanel.removeAll();\r
359     resetTable(false);\r
360     ap.repaint();\r
361   }\r
362 \r
363   public void mouseEntered(MouseEvent evt){}\r
364   public void mouseExited(MouseEvent evt){}\r
365   public void mouseClicked(MouseEvent evt)\r
366   {\r
367     Checkbox check = (Checkbox) evt.getSource();\r
368     if(evt.getClickCount()>1)\r
369     {\r
370        new UserDefinedColours(this, check.getLabel(),\r
371                               fr.getColour(check.getLabel()));\r
372     }\r
373   }\r
374   public void mouseMoved(MouseEvent evt){}\r
375 }\r