JAL-2388 Initial removal of hidden cols/seqs out of overview
[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     mouseAction(evt);
127   }
128
129   @Override
130   public void mouseReleased(MouseEvent evt)
131   {
132     mouseAction(evt);
133   }
134
135   @Override
136   public void mouseDragged(MouseEvent evt)
137   {
138     mouseAction(evt);
139   }
140
141   private void mouseAction(MouseEvent evt)
142   {
143     od.setBoxPositionByMouse(evt.getX(), evt.getY());
144     ap.setScrollValues(od.getScrollCol(), od.getScrollRow());
145     ap.paintAlignment(false);
146   }
147
148   /**
149    * DOCUMENT ME!
150    */
151   public void updateOverviewImage()
152   {
153     if (resizing)
154     {
155       resizeAgain = true;
156       return;
157     }
158
159     if (av.isShowSequenceFeatures())
160     {
161       fr.transferSettings(ap.seqPanel.seqCanvas.fr);
162     }
163
164     resizing = true;
165
166     if ((getWidth() > 0) && (getHeight() > 0))
167     {
168       od.setWidth(getWidth()); // width = getWidth();
169       od.setHeight(getHeight()); // sequencesHeight = getHeight() - graphHeight;
170     }
171     setSize(new Dimension(od.getWidth(), od.getHeight()));
172
173     Thread thread = new Thread(this);
174     thread.start();
175     repaint();
176   }
177
178   @Override
179   public void run()
180   {
181     miniMe = null;
182
183     if (av.isShowSequenceFeatures())
184     {
185       fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer());
186     }
187
188     if (getSize().width > 0 && getSize().height > 0)
189     {
190       od.setWidth(getSize().width);
191       od.setHeight(getSize().height - od.getGraphHeight());
192     }
193
194     setSize(new Dimension(od.getWidth(), od.getHeight()));
195
196     miniMe = nullFrame.createImage(od.getWidth(), od.getHeight());
197     offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
198
199     Graphics mg = miniMe.getGraphics();
200
201     // od.updateScales();
202
203     int alwidth = av.getAlignment().getWidth();
204     int alheight = av.getAlignment().getAbsoluteHeight();
205     float sampleCol = alwidth / (float) od.getWidth();
206     float sampleRow = alheight / (float) od.getSequencesHeight();
207
208     buildImage(sampleRow, sampleCol, mg);
209
210     if (av.getAlignmentConservationAnnotation() != null)
211     {
212       for (int col = 0; col < od.getWidth() && !resizeAgain; col++)
213       {
214         mg.translate(col, od.getSequencesHeight());
215         ap.annotationPanel.renderer.drawGraph(mg,
216                 av.getAlignmentConservationAnnotation(),
217                 av.getAlignmentConservationAnnotation().annotations,
218                 (int) (sampleCol) + 1, od.getGraphHeight(),
219                 (int) (col * sampleCol), (int) (col * sampleCol) + 1);
220         mg.translate(-col, -od.getSequencesHeight());
221       }
222     }
223     System.gc();
224
225     resizing = false;
226
227     setBoxPosition();
228
229     if (resizeAgain)
230     {
231       resizeAgain = false;
232       updateOverviewImage();
233     }
234   }
235
236   private void buildImage(float sampleRow, float sampleCol, Graphics mg)
237   {
238     int lastcol = 0;
239     int lastrow = 0;
240     int xstart = 0;
241     int ystart = 0;
242     Color color = Color.yellow;
243     int sameRow = 0;
244     int sameCol = 0;
245
246     jalview.datamodel.SequenceI seq = null;
247
248     final boolean hasHiddenCols = av.hasHiddenColumns();
249     boolean hiddenRow = false;
250
251     for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++)
252     {
253       if ((int) (row * sampleRow) == lastrow)
254       {
255         sameRow++;
256       }
257       else
258       {
259         // get the sequence which would be at alignment index 'lastrow' if no
260         // columns were hidden, and determine whether it is hidden or not
261         hiddenRow = av.getAlignment().isHidden(lastrow);
262         seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow);
263
264         for (int col = 0; col < od.getWidth(); col++)
265         {
266           if ((int) (col * sampleCol) == lastcol
267                   && (int) (row * sampleRow) == lastrow)
268           {
269             sameCol++;
270           }
271           else
272           {
273             lastcol = (int) (col * sampleCol);
274
275             color = getColumnColourFromSequence(seq, hiddenRow,
276                     hasHiddenCols, lastcol);
277
278             mg.setColor(color);
279             if (sameCol == 1 && sameRow == 1)
280             {
281               mg.drawLine(xstart, ystart, xstart, ystart);
282             }
283             else
284             {
285               mg.fillRect(xstart, ystart, sameCol, sameRow);
286             }
287
288             xstart = col;
289             sameCol = 1;
290           }
291         }
292         lastrow = (int) (row * sampleRow);
293         ystart = row;
294         sameRow = 1;
295       }
296     }
297
298   }
299
300   /*
301    * Find the colour of a sequence at a specified column position
302    */
303   private Color getColumnColourFromSequence(
304           jalview.datamodel.SequenceI seq, boolean hiddenRow,
305           boolean hasHiddenCols, int lastcol)
306   {
307     Color color;
308     if (seq.getLength() > lastcol)
309     {
310       color = sr.getResidueBoxColour(seq, lastcol);
311
312       if (av.isShowSequenceFeatures())
313       {
314         color = fr.findFeatureColour(color, seq, lastcol);
315       }
316     }
317     else
318     {
319       color = Color.white; // White
320     }
321
322     if (hiddenRow
323             || (hasHiddenCols && !av.getColumnSelection()
324                     .isVisible(lastcol)))
325     {
326       color = color.darker().darker();
327     }
328     return color;
329   }
330
331   /**
332    * Update the overview panel box when the associated alignment panel is
333    * changed
334    * 
335    */
336   public void setBoxPosition()
337   {
338     od.setBoxPosition();
339     repaint();
340   }
341
342   @Override
343   public void update(Graphics g)
344   {
345     paint(g);
346   }
347
348   @Override
349   public void paint(Graphics g)
350   {
351     Graphics og = offscreen.getGraphics();
352     if (miniMe != null)
353     {
354       og.drawImage(miniMe, 0, 0, this);
355       og.setColor(Color.red);
356       od.drawBox(og);
357       g.drawImage(offscreen, 0, 0, this);
358     }
359   }
360
361 }