updated to jalview 2.1 and begun ArchiveClient/VamsasClient/VamsasStore updates.
[jalview.git] / src / jalview / gui / 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 package jalview.gui;
20
21 import java.awt.*;
22 import java.awt.event.*;
23 import java.awt.image.*;
24
25 import javax.swing.*;
26
27
28 /**
29  * DOCUMENT ME!
30  *
31  * @author $author$
32  * @version $Revision$
33  */
34 public class OverviewPanel extends JPanel implements Runnable
35 {
36     BufferedImage miniMe;
37     AlignViewport av;
38     AlignmentPanel ap;
39     float scalew = 1f;
40     float scaleh = 1f;
41     int width;
42     int sequencesHeight;
43     int graphHeight = 20;
44     int boxX = -1;
45     int boxY = -1;
46     int boxWidth = -1;
47     int boxHeight = -1;
48     boolean resizing = false;
49
50     // Can set different properties in this seqCanvas than
51     // main visible SeqCanvas
52     SequenceRenderer sr;
53     FeatureRenderer fr;
54
55     /**
56      * Creates a new OverviewPanel object.
57      *
58      * @param ap DOCUMENT ME!
59      */
60     public OverviewPanel(AlignmentPanel ap)
61     {
62         this.av = ap.av;
63         this.ap = ap;
64         setLayout(null);
65
66         sr = new SequenceRenderer(av);
67         sr.renderGaps = false;
68         sr.forOverview = true;
69         fr = new FeatureRenderer(av);
70
71         // scale the initial size of overviewpanel to shape of alignment
72         float initialScale = (float) av.alignment.getWidth() / (float) av.alignment.getHeight();
73
74         if(av.conservation==null)
75           graphHeight = 0;
76
77
78         if (av.alignment.getWidth() > av.alignment.getHeight())
79         {
80             // wider
81             width = 400;
82             sequencesHeight = (int) (400f / initialScale);
83             if(sequencesHeight<40)
84               sequencesHeight = 40;
85         }
86         else
87         {
88             // taller
89             width = (int) (400f * initialScale);
90             sequencesHeight = 300;
91
92             if (width < 120)
93             {
94                 width = 120;
95             }
96         }
97
98         addComponentListener(new ComponentAdapter()
99             {
100                 public void componentResized(ComponentEvent evt)
101                 {
102                     if ((getWidth() != width) ||
103                             (getHeight() != (sequencesHeight + graphHeight)))
104                     {
105                         updateOverviewImage();
106                     }
107                 }
108             });
109
110         addMouseMotionListener(new MouseMotionAdapter()
111             {
112                 public void mouseDragged(MouseEvent evt)
113                 {
114                   if (!av.wrapAlignment)
115                   {
116                     boxX = evt.getX();
117                     boxY = evt.getY();
118                     checkValid();
119                   }
120                 }
121             });
122
123         addMouseListener(new MouseAdapter()
124             {
125                 public void mousePressed(MouseEvent evt)
126                 {
127                   if(!av.wrapAlignment)
128                   {
129                     boxX = evt.getX();
130                     boxY = evt.getY();
131                     checkValid();
132                   }
133                 }
134             });
135
136         updateOverviewImage();
137     }
138
139
140     /**
141      * DOCUMENT ME!
142      */
143     void checkValid()
144     {
145         if (boxY < 0)
146         {
147             boxY = 0;
148         }
149
150         if (boxY > (sequencesHeight - boxHeight))
151         {
152             boxY = sequencesHeight - boxHeight + 1;
153         }
154
155         if (boxX < 0)
156         {
157             boxX = 0;
158         }
159
160         if (boxX > (width - boxWidth))
161         {
162           if(av.hasHiddenColumns)
163           {
164             //Try smallest possible box
165             boxWidth = (int) ( (av.endRes - av.startRes + 1) *
166                                    av.getCharWidth() * scalew);
167           }
168           boxX = width - boxWidth;
169         }
170
171         int col = (int) (boxX / scalew / av.getCharWidth());
172         int row = (int) (boxY / scaleh / av.getCharHeight());
173
174         if (av.hasHiddenColumns)
175         {
176           if (!av.getColumnSelection().isVisible(col))
177           {
178             return;
179           }
180
181           col = av.getColumnSelection().findColumnPosition(col);
182         }
183
184         if( av.hasHiddenRows )
185         {
186           row = av.alignment.getHiddenSequences().findIndexWithoutHiddenSeqs(row);
187         }
188
189         ap.setScrollValues( col, row );
190
191     }
192
193     /**
194      * DOCUMENT ME!
195      */
196     public void updateOverviewImage()
197     {
198         if (resizing)
199         {
200             resizeAgain = true;
201             return;
202         }
203
204         resizing = true;
205
206         if ( (getWidth() > 0) && (getHeight() > 0))
207         {
208           width = getWidth();
209           sequencesHeight = getHeight() - graphHeight;
210         }
211
212         setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
213
214         Thread thread = new Thread(this);
215         thread.start();
216         repaint();
217     }
218
219     // This is set true if the user resizes whilst
220     // the overview is being calculated
221     boolean resizeAgain = false;
222
223     /**
224      * DOCUMENT ME!
225      */
226     public void run()
227     {
228         miniMe = null;
229
230        if (av.showSequenceFeatures)
231        {
232          fr.transferSettings( ap.seqPanel.seqCanvas.getFeatureRenderer() );
233        }
234
235         int alwidth = av.alignment.getWidth();
236         int alheight = av.alignment.getHeight()
237             +av.alignment.getHiddenSequences().getSize();
238
239         setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));
240
241         int fullsizeWidth = alwidth * av.getCharWidth();
242         int fullsizeHeight = alheight * av.getCharHeight();
243
244         scalew = (float) width / (float) fullsizeWidth;
245         scaleh = (float) sequencesHeight / (float) fullsizeHeight;
246
247         miniMe = new BufferedImage(width, sequencesHeight + graphHeight,
248                 BufferedImage.TYPE_INT_RGB);
249
250
251         Graphics mg = miniMe.getGraphics();
252         mg.setColor(Color.orange);
253         mg.fillRect(0,0,width, miniMe.getHeight());
254
255         float sampleCol = (float) alwidth / (float) width;
256         float sampleRow = (float) alheight / (float) sequencesHeight;
257
258         int lastcol=-1, lastrow=-1;
259         int color = Color.white.getRGB();
260         int row, col;
261         jalview.datamodel.SequenceI seq;
262         boolean hiddenRow = false;
263         for (row = 0; row < sequencesHeight; row++)
264         {
265           if((int)(row*sampleRow)==lastrow)
266           {
267             //No need to recalculate the colours,
268             //Just copy from the row above
269             for (col = 0; col < width; col++)
270             {
271               miniMe.setRGB(col, row, miniMe.getRGB(col, row-1));
272             }
273             continue;
274           }
275
276           lastrow = (int)(row*sampleRow);
277
278           hiddenRow = false;
279           if (av.hasHiddenRows)
280           {
281             seq = av.alignment.getHiddenSequences().getHiddenSequence(lastrow);
282             if (seq == null)
283             {
284               int index =
285                  av.alignment.getHiddenSequences().findIndexWithoutHiddenSeqs(lastrow);
286
287              seq = av.alignment.getSequenceAt(index);
288             }
289             else
290             {
291               hiddenRow = true;
292             }
293           }
294           else
295             seq = av.alignment.getSequenceAt(lastrow);
296
297           if(seq==null)
298           {
299             System.out.println(lastrow+" null");
300             continue;
301           }
302
303             for (col = 0; col < width; col++)
304             {
305             if((int)(col*sampleCol) == lastcol && (int)(row*sampleRow)==lastrow)
306             {
307               miniMe.setRGB(col,row,color);
308               continue;
309             }
310
311
312             lastcol = (int)(col*sampleCol);
313
314             if (seq.getLength() > lastcol)
315             {
316               color = sr.getResidueBoxColour(
317                   seq, lastcol).getRGB();
318
319               if (av.showSequenceFeatures)
320                 color = fr.findFeatureColour(color, seq, lastcol);
321             }
322             else
323             {
324               color = -1; //White
325             }
326
327             if(hiddenRow ||
328                (av.hasHiddenColumns && !av.getColumnSelection().isVisible(lastcol)))
329             {
330               color = new Color(color).darker().darker().getRGB();
331             }
332
333
334             miniMe.setRGB(col,row,color);
335
336
337           }
338         }
339
340         if (av.conservation != null)
341         {
342           for (col = 0; col < width; col++)
343           {
344             lastcol = (int) (col * sampleCol);
345             {
346               mg.translate(col, sequencesHeight);
347               ap.annotationPanel.drawGraph(mg, av.conservation,
348                                            (int) (sampleCol) + 1,
349                                            graphHeight,
350                                            (int) (col * sampleCol),
351                                            (int) (col * sampleCol) + 1);
352               mg.translate( -col, -sequencesHeight);
353             }
354           }
355         }
356         System.gc();
357
358         resizing = false;
359
360         setBoxPosition();
361
362         if(resizeAgain)
363         {
364           resizeAgain = false;
365           updateOverviewImage();
366         }
367     }
368
369     /**
370      * DOCUMENT ME!
371      */
372     public void setBoxPosition()
373     {
374       int fullsizeWidth = av.alignment.getWidth() * av.getCharWidth();
375       int fullsizeHeight = (av.alignment.getHeight()
376                    +av.alignment.getHiddenSequences().getSize()) * av.getCharHeight();
377
378       int startRes = av.getStartRes();
379       int endRes = av.getEndRes();
380
381       if(av.hasHiddenColumns)
382       {
383         startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
384         endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
385       }
386
387       int startSeq = av.startSeq;
388       int endSeq = av.endSeq;
389
390       if (av.hasHiddenRows)
391       {
392         startSeq =
393             av.alignment.getHiddenSequences().adjustForHiddenSeqs(startSeq);
394
395         endSeq =
396             av.alignment.getHiddenSequences().adjustForHiddenSeqs(endSeq);
397
398       }
399
400
401       scalew = (float) width / (float) fullsizeWidth;
402       scaleh = (float) sequencesHeight / (float) fullsizeHeight;
403
404         boxX = (int) (startRes * av.getCharWidth() * scalew);
405         boxY = (int) (startSeq * av.getCharHeight() * scaleh);
406
407
408
409         if(av.hasHiddenColumns)
410           boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
411         else
412           boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
413
414
415         boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
416
417
418         repaint();
419     }
420
421     /**
422      * DOCUMENT ME!
423      *
424      * @param g DOCUMENT ME!
425      */
426     public void paintComponent(Graphics g)
427     {
428         if (miniMe != null && !resizing)
429         {
430           g.drawImage(miniMe, 0, 0, this);
431         }
432         else
433         {
434           g.setColor(Color.white);
435           g.fillRect(0, 0, getWidth(), getHeight());
436           g.setColor(Color.black);
437           g.setFont(new Font("Verdana", Font.BOLD, 15));
438           g.drawString("Recalculating", 5, sequencesHeight / 2);
439           g.drawString("Overview.....", 5, (sequencesHeight / 2) + 20);
440         }
441
442
443         g.setColor(Color.red);
444         g.drawRect(boxX, boxY, boxWidth, boxHeight);
445         g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
446
447     }
448 }