JAL-1807 test3 bob changes "twice"
[jalviewjs.git] / unused / appletgui / OverviewPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)\r
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3\r
10  * of the License, or (at your option) any later version.\r
11  *  \r
12  * Jalview is distributed in the hope that it will be useful, but \r
13  * WITHOUT ANY WARRANTY; without even the implied warranty \r
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
15  * PURPOSE.  See the GNU General Public License for more details.\r
16  * \r
17  * You should have received a copy of the GNU General Public License\r
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
19  * The Jalview Authors are detailed in the 'AUTHORS' file.\r
20  */\r
21 package jalview.appletgui;\r
22 \r
23 import jalview.datamodel.AlignmentI;\r
24 import jalview.datamodel.SequenceI;\r
25 \r
26 import java.awt.Color;\r
27 import java.awt.Dimension;\r
28 import java.awt.Frame;\r
29 import java.awt.Graphics;\r
30 import java.awt.Image;\r
31 import java.awt.Panel;\r
32 import java.awt.event.ComponentAdapter;\r
33 import java.awt.event.ComponentEvent;\r
34 import java.awt.event.MouseEvent;\r
35 import java.awt.event.MouseListener;\r
36 import java.awt.event.MouseMotionListener;\r
37 \r
38 public class OverviewPanel extends Panel implements Runnable,\r
39         MouseMotionListener, MouseListener\r
40 {\r
41   Image miniMe;\r
42 \r
43   Image offscreen;\r
44 \r
45   AlignViewport av;\r
46 \r
47   AlignmentPanel ap;\r
48 \r
49   float scalew = 1f;\r
50 \r
51   float scaleh = 1f;\r
52 \r
53   public int width, sequencesHeight;\r
54 \r
55   int graphHeight = 20;\r
56 \r
57   int boxX = -1, boxY = -1, boxWidth = -1, boxHeight = -1;\r
58 \r
59   boolean resizing = false;\r
60 \r
61   // Can set different properties in this seqCanvas than\r
62   // main visible SeqCanvas\r
63   SequenceRenderer sr;\r
64 \r
65   FeatureRenderer fr;\r
66 \r
67   Frame nullFrame;\r
68 \r
69   public OverviewPanel(AlignmentPanel ap)\r
70   {\r
71     this.av = ap.av;\r
72     this.ap = ap;\r
73     setLayout(null);\r
74     nullFrame = new Frame();\r
75     nullFrame.addNotify();\r
76 \r
77     sr = new SequenceRenderer(av);\r
78     sr.graphics = nullFrame.getGraphics();\r
79     sr.renderGaps = false;\r
80     sr.forOverview = true;\r
81     fr = new FeatureRenderer(av);\r
82 \r
83     // scale the initial size of overviewpanel to shape of alignment\r
84     float initialScale = (float) av.getAlignment().getWidth()\r
85             / (float) av.getAlignment().getHeight();\r
86 \r
87     if (av.getSequenceConsensusHash() == null)\r
88     {\r
89       graphHeight = 0;\r
90     }\r
91 \r
92     if (av.getAlignment().getWidth() > av.getAlignment().getHeight())\r
93     {\r
94       // wider\r
95       width = 400;\r
96       sequencesHeight = (int) (400f / initialScale);\r
97       if (sequencesHeight < 40)\r
98       {\r
99         sequencesHeight = 40;\r
100       }\r
101     }\r
102     else\r
103     {\r
104       // taller\r
105       width = (int) (400f * initialScale);\r
106       sequencesHeight = 300;\r
107       if (width < 120)\r
108       {\r
109         width = 120;\r
110       }\r
111     }\r
112 \r
113     setSize(new Dimension(width, sequencesHeight + graphHeight));\r
114     addComponentListener(new ComponentAdapter()\r
115     {\r
116 \r
117       @Override\r
118       public void componentResized(ComponentEvent evt)\r
119       {\r
120         if (getSize().width != width\r
121                 || getSize().height != sequencesHeight + graphHeight)\r
122         {\r
123           updateOverviewImage();\r
124         }\r
125       }\r
126     });\r
127 \r
128     addMouseMotionListener(this);\r
129 \r
130     addMouseListener(this);\r
131 \r
132     updateOverviewImage();\r
133 \r
134   }\r
135 \r
136   @Override\r
137   public void mouseEntered(MouseEvent evt)\r
138   {\r
139   }\r
140 \r
141   @Override\r
142   public void mouseExited(MouseEvent evt)\r
143   {\r
144   }\r
145 \r
146   @Override\r
147   public void mouseClicked(MouseEvent evt)\r
148   {\r
149   }\r
150 \r
151   @Override\r
152   public void mouseMoved(MouseEvent evt)\r
153   {\r
154   }\r
155 \r
156   @Override\r
157   public void mousePressed(MouseEvent evt)\r
158   {\r
159     boxX = evt.getX();\r
160     boxY = evt.getY();\r
161     checkValid();\r
162   }\r
163 \r
164   @Override\r
165   public void mouseReleased(MouseEvent evt)\r
166   {\r
167     boxX = evt.getX();\r
168     boxY = evt.getY();\r
169     checkValid();\r
170   }\r
171 \r
172   @Override\r
173   public void mouseDragged(MouseEvent evt)\r
174   {\r
175     boxX = evt.getX();\r
176     boxY = evt.getY();\r
177     checkValid();\r
178   }\r
179 \r
180   void checkValid()\r
181   {\r
182     if (boxY < 0)\r
183     {\r
184       boxY = 0;\r
185     }\r
186 \r
187     if (boxY > (sequencesHeight - boxHeight))\r
188     {\r
189       boxY = sequencesHeight - boxHeight + 1;\r
190     }\r
191 \r
192     if (boxX < 0)\r
193     {\r
194       boxX = 0;\r
195     }\r
196 \r
197     if (boxX > (width - boxWidth))\r
198     {\r
199       if (av.hasHiddenColumns())\r
200       {\r
201         // Try smallest possible box\r
202         boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew);\r
203       }\r
204       boxX = width - boxWidth;\r
205     }\r
206 \r
207     int col = (int) (boxX / scalew / av.getCharWidth());\r
208     int row = (int) (boxY / scaleh / av.getCharHeight());\r
209 \r
210     if (av.hasHiddenColumns())\r
211     {\r
212       if (!av.getColumnSelection().isVisible(col))\r
213       {\r
214         return;\r
215       }\r
216 \r
217       col = av.getColumnSelection().findColumnPosition(col);\r
218     }\r
219 \r
220     if (av.hasHiddenRows())\r
221     {\r
222       row = av.getAlignment().getHiddenSequences()\r
223               .findIndexWithoutHiddenSeqs(row);\r
224     }\r
225 \r
226     ap.setScrollValues(col, row);\r
227     ap.paintAlignment(false);\r
228   }\r
229 \r
230   /**\r
231    * DOCUMENT ME!\r
232    */\r
233   public void updateOverviewImage()\r
234   {\r
235     if (resizing)\r
236     {\r
237       resizeAgain = true;\r
238       return;\r
239     }\r
240 \r
241     if (av.isShowSequenceFeatures())\r
242     {\r
243       fr.transferSettings(ap.seqPanel.seqCanvas.fr);\r
244     }\r
245 \r
246     resizing = true;\r
247 \r
248     if ((getSize().width > 0) && (getSize().height > 0))\r
249     {\r
250       width = getSize().width;\r
251       sequencesHeight = getSize().height - graphHeight;\r
252     }\r
253     setSize(new Dimension(width, sequencesHeight + graphHeight));\r
254 \r
255     Thread thread = new Thread(this);\r
256     thread.start();\r
257     repaint();\r
258   }\r
259 \r
260   // This is set true if the user resizes whilst\r
261   // the overview is being calculated\r
262   boolean resizeAgain = false;\r
263 \r
264   @Override\r
265   public void run()\r
266   {\r
267     miniMe = null;\r
268     int alwidth = av.getAlignment().getWidth();\r
269     int alheight = av.getAlignment().getHeight();\r
270 \r
271     if (av.isShowSequenceFeatures())\r
272     {\r
273       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());\r
274     }\r
275 \r
276     if (getSize().width > 0 && getSize().height > 0)\r
277     {\r
278       width = getSize().width;\r
279       sequencesHeight = getSize().height - graphHeight;\r
280     }\r
281 \r
282     setSize(new Dimension(width, sequencesHeight + graphHeight));\r
283 \r
284     int fullsizeWidth = alwidth * av.getCharWidth();\r
285     int fullsizeHeight = alheight * av.getCharHeight();\r
286 \r
287     scalew = (float) width / (float) fullsizeWidth;\r
288     scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
289 \r
290     miniMe = nullFrame.createImage(width, sequencesHeight + graphHeight);\r
291     offscreen = nullFrame.createImage(width, sequencesHeight + graphHeight);\r
292 \r
293     Graphics mg = miniMe.getGraphics();\r
294     float sampleCol = (float) alwidth / (float) width;\r
295     float sampleRow = (float) alheight / (float) sequencesHeight;\r
296 \r
297     int lastcol = 0, lastrow = 0;\r
298     int xstart = 0, ystart = 0;\r
299     Color color = Color.yellow;\r
300     int row, col, sameRow = 0, sameCol = 0;\r
301     SequenceI seq;\r
302     final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av\r
303             .hasHiddenColumns();\r
304     boolean hiddenRow = false;\r
305     AlignmentI alignment = av.getAlignment();\r
306     for (row = 0; row <= sequencesHeight; row++)\r
307     {\r
308       if ((int) (row * sampleRow) == lastrow)\r
309       {\r
310         sameRow++;\r
311         continue;\r
312       }\r
313 \r
314       hiddenRow = false;\r
315       if (hasHiddenRows)\r
316       {\r
317         seq = alignment.getHiddenSequences().getHiddenSequence(lastrow);\r
318         if (seq == null)\r
319         {\r
320           int index = alignment.getHiddenSequences()\r
321                   .findIndexWithoutHiddenSeqs(lastrow);\r
322 \r
323           seq = alignment.getSequenceAt(index);\r
324         }\r
325         else\r
326         {\r
327           hiddenRow = true;\r
328         }\r
329       }\r
330       else\r
331       {\r
332         seq = alignment.getSequenceAt(lastrow);\r
333       }\r
334 \r
335       for (col = 0; col < width; col++)\r
336       {\r
337         if ((int) (col * sampleCol) == lastcol\r
338                 && (int) (row * sampleRow) == lastrow)\r
339         {\r
340           sameCol++;\r
341           continue;\r
342         }\r
343 \r
344         lastcol = (int) (col * sampleCol);\r
345 \r
346         if (seq.getLength() > lastcol)\r
347         {\r
348           color = sr.getResidueBoxColour(seq, lastcol);\r
349 \r
350           if (av.isShowSequenceFeatures())\r
351           {\r
352             color = fr.findFeatureColour(color, seq, lastcol);\r
353           }\r
354         }\r
355         else\r
356         {\r
357           color = Color.white; // White\r
358         }\r
359 \r
360         if (hiddenRow\r
361                 || (hasHiddenCols && !av.getColumnSelection()\r
362                         .isVisible(lastcol)))\r
363         {\r
364           color = color.darker().darker();\r
365         }\r
366 \r
367         mg.setColor(color);\r
368         if (sameCol == 1 && sameRow == 1)\r
369         {\r
370           mg.drawLine(xstart, ystart, xstart, ystart);\r
371         }\r
372         else\r
373         {\r
374           mg.fillRect(xstart, ystart, sameCol, sameRow);\r
375         }\r
376 \r
377         xstart = col;\r
378         sameCol = 1;\r
379       }\r
380       lastrow = (int) (row * sampleRow);\r
381       ystart = row;\r
382       sameRow = 1;\r
383     }\r
384 \r
385     if (av.getAlignmentConservationAnnotation() != null)\r
386     {\r
387       for (col = 0; col < width; col++)\r
388       {\r
389         lastcol = (int) (col * sampleCol);\r
390         {\r
391           mg.translate(col, sequencesHeight);\r
392           ap.annotationPanel.renderer.drawGraph(mg,\r
393                   av.getAlignmentConservationAnnotation(),\r
394                   av.getAlignmentConservationAnnotation().annotations,\r
395                   (int) (sampleCol) + 1, graphHeight,\r
396                   (int) (col * sampleCol), (int) (col * sampleCol) + 1);\r
397           mg.translate(-col, -sequencesHeight);\r
398         }\r
399       }\r
400     }\r
401     System.gc();\r
402 \r
403     resizing = false;\r
404 \r
405     setBoxPosition();\r
406 \r
407     if (resizeAgain)\r
408     {\r
409       resizeAgain = false;\r
410       updateOverviewImage();\r
411     }\r
412   }\r
413 \r
414   public void setBoxPosition()\r
415   {\r
416     int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth();\r
417     int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment()\r
418             .getHiddenSequences().getSize())\r
419             * av.getCharHeight();\r
420 \r
421     int startRes = av.getStartRes();\r
422     int endRes = av.getEndRes();\r
423 \r
424     if (av.hasHiddenColumns())\r
425     {\r
426       startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);\r
427       endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);\r
428     }\r
429 \r
430     int startSeq = av.startSeq;\r
431     int endSeq = av.endSeq;\r
432 \r
433     if (av.hasHiddenRows())\r
434     {\r
435       startSeq = av.getAlignment().getHiddenSequences()\r
436               .adjustForHiddenSeqs(startSeq);\r
437 \r
438       endSeq = av.getAlignment().getHiddenSequences()\r
439               .adjustForHiddenSeqs(endSeq);\r
440 \r
441     }\r
442 \r
443     scalew = (float) width / (float) fullsizeWidth;\r
444     scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
445 \r
446     boxX = (int) (startRes * av.getCharWidth() * scalew);\r
447     boxY = (int) (startSeq * av.getCharHeight() * scaleh);\r
448 \r
449     if (av.hasHiddenColumns())\r
450     {\r
451       boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);\r
452     }\r
453     else\r
454     {\r
455       boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);\r
456     }\r
457 \r
458     boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);\r
459 \r
460     repaint();\r
461   }\r
462 \r
463   @Override\r
464   public void update(Graphics g)\r
465   {\r
466     paint(g);\r
467   }\r
468 \r
469   @Override\r
470   public void paint(Graphics g)\r
471   {\r
472     Graphics og = offscreen.getGraphics();\r
473     if (miniMe != null)\r
474     {\r
475       og.drawImage(miniMe, 0, 0, this);\r
476       og.setColor(Color.red);\r
477       og.drawRect(boxX, boxY, boxWidth, boxHeight);\r
478       og.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);\r
479       g.drawImage(offscreen, 0, 0, this);\r
480     }\r
481   }\r
482 \r
483 }\r