743d217fb10508d7b98de06e91473040b40a3156
[jalview.git] / src / jalview / appletgui / OverviewPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.appletgui;
22
23 import jalview.viewmodel.OverviewDimensions;
24
25 import java.awt.Color;
26 import java.awt.Dimension;
27 import java.awt.Frame;
28 import java.awt.Graphics;
29 import java.awt.Image;
30 import java.awt.Panel;
31 import java.awt.event.ComponentAdapter;
32 import java.awt.event.ComponentEvent;
33 import java.awt.event.MouseEvent;
34 import java.awt.event.MouseListener;
35 import java.awt.event.MouseMotionListener;
36
37 public class OverviewPanel extends Panel implements Runnable,
38         MouseMotionListener, MouseListener
39 {
40   private OverviewDimensions od;
41
42   private Image miniMe;
43
44   private Image offscreen;
45
46   private AlignViewport av;
47
48   private AlignmentPanel ap;
49
50   private boolean resizing = false;
51
52   // This is set true if the user resizes whilst
53   // the overview is being calculated
54   private boolean resizeAgain = false;
55
56   // Can set different properties in this seqCanvas than
57   // main visible SeqCanvas
58   private SequenceRenderer sr;
59
60   private FeatureRenderer fr;
61
62   private Frame nullFrame;
63
64   public OverviewPanel(AlignmentPanel ap)
65   {
66     this.av = ap.av;
67     this.ap = ap;
68     setLayout(null);
69     nullFrame = new Frame();
70     nullFrame.addNotify();
71
72     sr = new SequenceRenderer(av);
73     sr.graphics = nullFrame.getGraphics();
74     sr.renderGaps = false;
75     sr.forOverview = true;
76     fr = new FeatureRenderer(av);
77
78     od = new OverviewDimensions(av);
79
80     setSize(new Dimension(od.getWidth(), od.getHeight()));
81     addComponentListener(new ComponentAdapter()
82     {
83
84       @Override
85       public void componentResized(ComponentEvent evt)
86       {
87         if ((getWidth() != od.getWidth())
88                 || (getHeight() != (od.getHeight())))
89         {
90           updateOverviewImage();
91         }
92       }
93     });
94
95     addMouseMotionListener(this);
96
97     addMouseListener(this);
98
99     updateOverviewImage();
100
101   }
102
103   @Override
104   public void mouseEntered(MouseEvent evt)
105   {
106   }
107
108   @Override
109   public void mouseExited(MouseEvent evt)
110   {
111   }
112
113   @Override
114   public void mouseClicked(MouseEvent evt)
115   {
116   }
117
118   @Override
119   public void mouseMoved(MouseEvent evt)
120   {
121   }
122
123   @Override
124   public void mousePressed(MouseEvent evt)
125   {
126     od.setBoxX(evt.getX());
127     od.setBoxY(evt.getY());
128     checkValid();
129   }
130
131   @Override
132   public void mouseReleased(MouseEvent evt)
133   {
134     od.setBoxX(evt.getX());
135     od.setBoxY(evt.getY());
136     checkValid();
137   }
138
139   @Override
140   public void mouseDragged(MouseEvent evt)
141   {
142     od.setBoxX(evt.getX());
143     od.setBoxY(evt.getY());
144     checkValid();
145   }
146
147   /**
148    * Check box dimensions and scroll positions and correct if necessary
149    */
150   private void checkValid()
151   {
152     od.checkValid();
153     ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
154     ap.paintAlignment(false);
155   }
156
157   /**
158    * DOCUMENT ME!
159    */
160   public void updateOverviewImage()
161   {
162     if (resizing)
163     {
164       resizeAgain = true;
165       return;
166     }
167
168     if (av.isShowSequenceFeatures())
169     {
170       fr.transferSettings(ap.seqPanel.seqCanvas.fr);
171     }
172
173     resizing = true;
174
175     if ((getWidth() > 0) && (getHeight() > 0))
176     {
177       od.setWidth(getWidth()); // width = getWidth();
178       od.setHeight(getHeight()); // sequencesHeight = getHeight() - graphHeight;
179     }
180     setSize(new Dimension(od.getWidth(), od.getHeight()));
181
182     Thread thread = new Thread(this);
183     thread.start();
184     repaint();
185   }
186
187   @Override
188   public void run()
189   {
190     miniMe = null;
191
192     if (av.isShowSequenceFeatures())
193     {
194       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
195     }
196
197     if (getSize().width > 0 && getSize().height > 0)
198     {
199       od.setWidth(getSize().width);
200       od.setHeight(getSize().height - od.getGraphHeight());
201     }
202
203     setSize(new Dimension(od.getWidth(), od.getHeight()));
204
205     miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
206     offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
207
208     Graphics mg = miniMe.getGraphics();
209
210     od.updateScales();
211
212     int alwidth = av.getAlignment().getWidth();
213     int alheight = av.getAlignment().getHeight()
214             + av.getAlignment().getHiddenSequences().getSize();
215     float sampleCol = alwidth / (float) od.getWidth();
216     float sampleRow = alheight / (float) od.getSequencesHeight();
217
218     buildImage(sampleRow, sampleCol, mg);
219
220     if (av.getAlignmentConservationAnnotation() != null)
221     {
222       for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
223       {
224         mg.translate(col, od.getSequencesHeight());
225         ap.annotationPanel.renderer.drawGraph(mg,
226                 av.getAlignmentConservationAnnotation(),
227                 av.getAlignmentConservationAnnotation().annotations,
228                 (int) (sampleCol) + 1, od.getGraphHeight(),
229                 (int) (col * sampleCol), (int) (col * sampleCol) + 1);
230         mg.translate(-col, -od.getSequencesHeight());
231       }
232     }
233     System.gc();
234
235     resizing = false;
236
237     setBoxPosition();
238
239     if (resizeAgain)
240     {
241       resizeAgain = false;
242       updateOverviewImage();
243     }
244   }
245
246   private void buildImage(float sampleRow, float sampleCol, Graphics mg)
247   {
248     int lastcol = 0;
249     int lastrow = 0;
250     int xstart = 0;
251     int ystart = 0;
252     Color color = Color.yellow;
253     int sameRow = 0;
254     int sameCol = 0;
255
256     jalview.datamodel.SequenceI seq = null;
257     final boolean hasHiddenRows = av.hasHiddenRows();
258     final boolean hasHiddenCols = av.hasHiddenColumns();
259     boolean hiddenRow = false;
260
261     for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++)
262     {
263       if ((int) (row * sampleRow) == lastrow)
264       {
265         sameRow++;
266         continue;
267       }
268       else
269       {
270         // this should largely be a method in Alignment
271         hiddenRow = false;
272         if (hasHiddenRows)
273         {
274           seq = av.getAlignment().getHiddenSequences()
275                   .getHiddenSequence(lastrow);
276           if (seq == null)
277           {
278             int index = av.getAlignment().getHiddenSequences()
279                     .findIndexWithoutHiddenSeqs(lastrow);
280
281             seq = av.getAlignment().getSequenceAt(index);
282           }
283           else
284           {
285             hiddenRow = true;
286           }
287         }
288         else
289         {
290           seq = av.getAlignment().getSequenceAt(lastrow);
291         }
292         // end of Alignment method
293
294         for (int col = 0; col < od.getWidth(); col++)
295         {
296           if ((int) (col * sampleCol) == lastcol
297                   && (int) (row * sampleRow) == lastrow)
298           {
299             sameCol++;
300           }
301           else
302           {
303             lastcol = (int) (col * sampleCol);
304
305             color = getColumnColourFromSequence(seq, hiddenRow,
306                     hasHiddenCols, lastcol);
307
308             mg.setColor(color);
309             if (sameCol == 1 && sameRow == 1)
310             {
311               mg.drawLine(xstart, ystart, xstart, ystart);
312             }
313             else
314             {
315               mg.fillRect(xstart, ystart, sameCol, sameRow);
316             }
317
318             xstart = col;
319             sameCol = 1;
320           }
321         }
322         lastrow = (int) (row * sampleRow);
323         ystart = row;
324         sameRow = 1;
325       }
326     }
327
328   }
329
330   /*
331    * Find the colour of a sequence at a specified column position
332    */
333   private Color getColumnColourFromSequence(
334           jalview.datamodel.SequenceI seq, boolean hiddenRow,
335           boolean hasHiddenCols, int lastcol)
336   {
337     Color color;
338     if (seq.getLength() > lastcol)
339     {
340       color = sr.getResidueBoxColour(seq, lastcol);
341
342       if (av.isShowSequenceFeatures())
343       {
344         color = fr.findFeatureColour(color, seq, lastcol);
345       }
346     }
347     else
348     {
349       color = Color.white; // White
350     }
351
352     if (hiddenRow
353             || (hasHiddenCols && !av.getColumnSelection()
354                     .isVisible(lastcol)))
355     {
356       color = color.darker().darker();
357     }
358     return color;
359   }
360
361   /**
362    * Update the overview panel box when the associated alignment panel is
363    * changed
364    * 
365    */
366   public void setBoxPosition()
367   {
368     od.setBoxPosition();
369     repaint();
370   }
371
372   @Override
373   public void update(Graphics g)
374   {
375     paint(g);
376   }
377
378   @Override
379   public void paint(Graphics g)
380   {
381     Graphics og = offscreen.getGraphics();
382     if (miniMe != null)
383     {
384       og.drawImage(miniMe, 0, 0, this);
385       og.setColor(Color.red);
386       og.drawRect(od.getBoxX(), od.getBoxY(), od.getBoxWidth(),
387               od.getBoxHeight());
388       og.drawRect(od.getBoxX() + 1, od.getBoxY() + 1, od.getBoxWidth() - 2,
389               od.getBoxHeight() - 2);
390       g.drawImage(offscreen, 0, 0, this);
391     }
392   }
393
394 }