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