JAL-2388 Renamed viewport position props to viewport ranges
[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.datamodel.SequenceI;
24 import jalview.viewmodel.OverviewDimensions;
25
26 import java.awt.Color;
27 import java.awt.Dimension;
28 import java.awt.Frame;
29 import java.awt.Graphics;
30 import java.awt.Image;
31 import java.awt.Panel;
32 import java.awt.event.ComponentAdapter;
33 import java.awt.event.ComponentEvent;
34 import java.awt.event.MouseEvent;
35 import java.awt.event.MouseListener;
36 import java.awt.event.MouseMotionListener;
37
38 public class OverviewPanel extends Panel implements Runnable,
39         MouseMotionListener, MouseListener
40 {
41   private OverviewDimensions od;
42
43   private Image miniMe;
44
45   private Image offscreen;
46
47   private AlignViewport av;
48
49   private AlignmentPanel ap;
50
51   private boolean resizing = false;
52
53   // This is set true if the user resizes whilst
54   // the overview is being calculated
55   private boolean resizeAgain = false;
56
57   // Can set different properties in this seqCanvas than
58   // main visible SeqCanvas
59   private SequenceRenderer sr;
60
61   private FeatureRenderer fr;
62
63   private Frame nullFrame;
64
65   public OverviewPanel(AlignmentPanel alPanel)
66   {
67     this.av = alPanel.av;
68     this.ap = alPanel;
69     setLayout(null);
70     nullFrame = new Frame();
71     nullFrame.addNotify();
72
73     sr = new SequenceRenderer(av);
74     sr.graphics = nullFrame.getGraphics();
75     sr.renderGaps = false;
76     sr.forOverview = true;
77     fr = new FeatureRenderer(av);
78
79     od = new OverviewDimensions(av.getRanges(), av.isShowAnnotation());
80
81     setSize(new Dimension(od.getWidth(), od.getHeight()));
82     addComponentListener(new ComponentAdapter()
83     {
84
85       @Override
86       public void componentResized(ComponentEvent evt)
87       {
88         if ((getWidth() != od.getWidth())
89                 || (getHeight() != (od.getHeight())))
90         {
91           updateOverviewImage();
92         }
93       }
94     });
95
96     addMouseMotionListener(this);
97
98     addMouseListener(this);
99
100     updateOverviewImage();
101
102   }
103
104   @Override
105   public void mouseEntered(MouseEvent evt)
106   {
107   }
108
109   @Override
110   public void mouseExited(MouseEvent evt)
111   {
112   }
113
114   @Override
115   public void mouseClicked(MouseEvent evt)
116   {
117   }
118
119   @Override
120   public void mouseMoved(MouseEvent evt)
121   {
122   }
123
124   @Override
125   public void mousePressed(MouseEvent evt)
126   {
127     mouseAction(evt);
128   }
129
130   @Override
131   public void mouseReleased(MouseEvent evt)
132   {
133     mouseAction(evt);
134   }
135
136   @Override
137   public void mouseDragged(MouseEvent evt)
138   {
139     mouseAction(evt);
140   }
141
142   private void mouseAction(MouseEvent evt)
143   {
144     od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
145             .getHiddenSequences(), av.getColumnSelection(), av
146             .getRanges());
147     ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
148     ap.paintAlignment(false);
149   }
150
151   /**
152    * Updates the overview image when the related alignment panel is updated
153    */
154   public void updateOverviewImage()
155   {
156     if (resizing)
157     {
158       resizeAgain = true;
159       return;
160     }
161
162     if (av.isShowSequenceFeatures())
163     {
164       fr.transferSettings(ap.seqPanel.seqCanvas.fr);
165     }
166
167     resizing = true;
168
169     if ((getSize().width > 0) && (getSize().height > 0))
170     {
171       od.setWidth(getSize().width);
172       od.setHeight(getSize().height);
173     }
174     setSize(new Dimension(od.getWidth(), od.getHeight()));
175
176     Thread thread = new Thread(this);
177     thread.start();
178     repaint();
179   }
180
181   @Override
182   public void run()
183   {
184     miniMe = null;
185
186     if (av.isShowSequenceFeatures())
187     {
188       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
189     }
190
191     if (getSize().width > 0 && getSize().height > 0)
192     {
193       od.setWidth(getSize().width);
194       od.setHeight(getSize().height);
195     }
196
197     setSize(new Dimension(od.getWidth(), od.getHeight()));
198
199     miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
200     offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
201
202     Graphics mg = miniMe.getGraphics();
203
204     int alwidth = av.getAlignment().getWidth();
205     int alheight = av.getAlignment().getAbsoluteHeight();
206     float sampleCol = alwidth / (float) od.getWidth();
207     float sampleRow = alheight / (float) od.getSequencesHeight();
208
209     buildImage(sampleRow, sampleCol, mg);
210
211     if (av.isShowAnnotation())
212     {
213       for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
214       {
215         mg.translate(col, od.getSequencesHeight());
216         ap.annotationPanel.renderer.drawGraph(mg,
217                 av.getAlignmentConservationAnnotation(),
218                 av.getAlignmentConservationAnnotation().annotations,
219                 (int) (sampleCol) + 1, od.getGraphHeight(),
220                 (int) (col * sampleCol), (int) (col * sampleCol) + 1);
221         mg.translate(-col, -od.getSequencesHeight());
222       }
223     }
224     System.gc();
225
226     resizing = false;
227
228     setBoxPosition();
229
230     if (resizeAgain)
231     {
232       resizeAgain = false;
233       updateOverviewImage();
234     }
235   }
236
237   /*
238    * Build the overview panel image
239    */
240   private void buildImage(float sampleRow, float sampleCol, Graphics mg)
241   {
242     int lastcol = 0;
243     int lastrow = 0;
244     int xstart = 0;
245     int ystart = 0;
246     Color color = Color.yellow;
247     int sameRow = 0;
248     int sameCol = 0;
249
250     SequenceI seq = null;
251
252     final boolean hasHiddenCols = av.hasHiddenColumns();
253     boolean hiddenRow = false;
254
255     for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++)
256     {
257       if ((int) (row * sampleRow) == lastrow)
258       {
259         sameRow++;
260       }
261       else
262       {
263         // get the sequence which would be at alignment index 'lastrow' if no
264         // columns were hidden, and determine whether it is hidden or not
265         hiddenRow = av.getAlignment().isHidden(lastrow);
266         seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
267
268         for (int col = 0; col < od.getWidth(); col++)
269         {
270           if ((int) (col * sampleCol) == lastcol
271                   && (int) (row * sampleRow) == lastrow)
272           {
273             sameCol++;
274           }
275           else
276           {
277             lastcol = (int) (col * sampleCol);
278
279             color = getColumnColourFromSequence(seq, hiddenRow,
280                     hasHiddenCols, lastcol);
281
282             mg.setColor(color);
283             if (sameCol == 1 && sameRow == 1)
284             {
285               mg.drawLine(xstart, ystart, xstart, ystart);
286             }
287             else
288             {
289               mg.fillRect(xstart, ystart, sameCol, sameRow);
290             }
291
292             xstart = col;
293             sameCol = 1;
294           }
295         }
296         lastrow = (int) (row * sampleRow);
297         ystart = row;
298         sameRow = 1;
299       }
300     }
301   }
302
303   /*
304    * Find the colour of a sequence at a specified column position
305    */
306   private Color getColumnColourFromSequence(
307           jalview.datamodel.SequenceI seq, boolean hiddenRow,
308           boolean hasHiddenCols, int lastcol)
309   {
310     Color color;
311     if (seq.getLength() > lastcol)
312     {
313       color = sr.getResidueBoxColour(seq, lastcol);
314
315       if (av.isShowSequenceFeatures())
316       {
317         color = fr.findFeatureColour(color, seq, lastcol);
318       }
319     }
320     else
321     {
322       color = Color.white;
323     }
324
325     if (hiddenRow
326             || (hasHiddenCols && !av.getColumnSelection()
327                     .isVisible(lastcol)))
328     {
329       color = color.darker().darker();
330     }
331     return color;
332   }
333
334   /**
335    * Update the overview panel box when the associated alignment panel is
336    * changed
337    * 
338    */
339   public void setBoxPosition()
340   {
341     od.setBoxPosition(av.getAlignment()
342             .getHiddenSequences(), av.getColumnSelection(), av.getRanges());
343     repaint();
344   }
345
346   @Override
347   public void update(Graphics g)
348   {
349     paint(g);
350   }
351
352   @Override
353   public void paint(Graphics g)
354   {
355     Graphics og = offscreen.getGraphics();
356     if (miniMe != null)
357     {
358       og.drawImage(miniMe, 0, 0, this);
359       og.setColor(Color.red);
360       od.drawBox(og);
361       g.drawImage(offscreen, 0, 0, this);
362     }
363   }
364
365 }