apply gpl development license
[jalview.git] / src / jalview / gui / ScalePanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 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 javax.swing.*;
24
25 import jalview.datamodel.*;
26
27 /**
28  * DOCUMENT ME!
29  * 
30  * @author $author$
31  * @version $Revision$
32  */
33 public class ScalePanel extends JPanel implements MouseMotionListener,
34         MouseListener
35 {
36   protected int offy = 4;
37
38   /** DOCUMENT ME!! */
39   public int width;
40
41   protected AlignViewport av;
42
43   AlignmentPanel ap;
44
45   boolean stretchingGroup = false;
46
47   int min; // used by mouseDragged to see if user
48
49   int max; // used by mouseDragged to see if user
50
51   boolean mouseDragging = false;
52
53   // wants to delete columns
54   public ScalePanel(AlignViewport av, AlignmentPanel ap)
55   {
56     this.av = av;
57     this.ap = ap;
58
59     addMouseListener(this);
60     addMouseMotionListener(this);
61   }
62
63   /**
64    * DOCUMENT ME!
65    * 
66    * @param evt
67    *                DOCUMENT ME!
68    */
69   public void mousePressed(MouseEvent evt)
70   {
71     int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
72     final int res;
73
74     if (av.hasHiddenColumns)
75     {
76       res = av.getColumnSelection().adjustForHiddenColumns(x);
77     }
78     else
79     {
80       res = x;
81     }
82
83     min = res;
84     max = res;
85
86     if (SwingUtilities.isRightMouseButton(evt))
87     {
88       JPopupMenu pop = new JPopupMenu();
89       if (reveal != null)
90       {
91         JMenuItem item = new JMenuItem("Reveal");
92         item.addActionListener(new ActionListener()
93         {
94           public void actionPerformed(ActionEvent e)
95           {
96             av.showColumn(reveal[0]);
97             reveal = null;
98             ap.paintAlignment(true);
99             if (ap.overviewPanel != null)
100             {
101               ap.overviewPanel.updateOverviewImage();
102             }
103           }
104         });
105         pop.add(item);
106
107         if (av.getColumnSelection().getHiddenColumns().size() > 1)
108         {
109           item = new JMenuItem("Reveal All");
110           item.addActionListener(new ActionListener()
111           {
112             public void actionPerformed(ActionEvent e)
113             {
114               av.showAllHiddenColumns();
115               reveal = null;
116               ap.paintAlignment(true);
117               if (ap.overviewPanel != null)
118               {
119                 ap.overviewPanel.updateOverviewImage();
120               }
121             }
122           });
123           pop.add(item);
124         }
125         pop.show(this, evt.getX(), evt.getY());
126       }
127       else if (av.getColumnSelection().contains(res))
128       {
129         JMenuItem item = new JMenuItem("Hide Columns");
130         item.addActionListener(new ActionListener()
131         {
132           public void actionPerformed(ActionEvent e)
133           {
134             av.hideColumns(res, res);
135             if (av.getSelectionGroup() != null
136                     && av.getSelectionGroup().getSize() == av.alignment
137                             .getHeight())
138             {
139               av.setSelectionGroup(null);
140             }
141
142             ap.paintAlignment(true);
143             if (ap.overviewPanel != null)
144             {
145               ap.overviewPanel.updateOverviewImage();
146             }
147           }
148         });
149         pop.add(item);
150         pop.show(this, evt.getX(), evt.getY());
151       }
152     }
153     else
154     // LEFT MOUSE TO SELECT
155     {
156       if (!evt.isControlDown() && !evt.isShiftDown())
157       {
158         av.getColumnSelection().clear();
159       }
160
161       av.getColumnSelection().addElement(res);
162       SequenceGroup sg = new SequenceGroup();
163       // try to be as quick as possible
164       SequenceI[] iVec = av.alignment.getSequencesArray();
165       for (int i = 0; i < iVec.length; i++)
166       {
167         sg.addSequence(iVec[i], false);
168         iVec[i] = null;
169       }
170       iVec = null;
171       sg.setStartRes(res);
172       sg.setEndRes(res);
173       av.setSelectionGroup(sg);
174
175       if (evt.isShiftDown())
176       {
177         int min = Math.min(av.getColumnSelection().getMin(), res);
178         int max = Math.max(av.getColumnSelection().getMax(), res);
179         for (int i = min; i < max; i++)
180         {
181           av.getColumnSelection().addElement(i);
182         }
183         sg.setStartRes(min);
184         sg.setEndRes(max);
185       }
186
187     }
188
189     ap.paintAlignment(false);
190     av.sendSelection();
191   }
192
193   /**
194    * DOCUMENT ME!
195    * 
196    * @param evt
197    *                DOCUMENT ME!
198    */
199   public void mouseReleased(MouseEvent evt)
200   {
201     mouseDragging = false;
202
203     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
204
205     if (res > av.alignment.getWidth())
206     {
207       res = av.alignment.getWidth() - 1;
208     }
209
210     if (av.hasHiddenColumns)
211     {
212       res = av.getColumnSelection().adjustForHiddenColumns(res);
213     }
214
215     if (!stretchingGroup)
216     {
217       ap.paintAlignment(false);
218
219       return;
220     }
221
222     SequenceGroup sg = av.getSelectionGroup();
223
224     if (sg != null)
225     {
226       if (res > sg.getStartRes())
227       {
228         sg.setEndRes(res);
229       }
230       else if (res < sg.getStartRes())
231       {
232         sg.setStartRes(res);
233       }
234     }
235     stretchingGroup = false;
236     ap.paintAlignment(false);
237     av.sendSelection();
238   }
239
240   /**
241    * DOCUMENT ME!
242    * 
243    * @param evt
244    *                DOCUMENT ME!
245    */
246   public void mouseDragged(MouseEvent evt)
247   {
248     mouseDragging = true;
249
250     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
251     if (res < 0)
252     {
253       res = 0;
254     }
255
256     if (av.hasHiddenColumns)
257     {
258       res = av.getColumnSelection().adjustForHiddenColumns(res);
259     }
260
261     if (res > av.alignment.getWidth())
262     {
263       res = av.alignment.getWidth() - 1;
264     }
265
266     if (res < min)
267     {
268       min = res;
269     }
270
271     if (res > max)
272     {
273       max = res;
274     }
275
276     SequenceGroup sg = av.getSelectionGroup();
277
278     if (sg != null)
279     {
280       stretchingGroup = true;
281
282       if (!av.getColumnSelection().contains(res))
283       {
284         av.getColumnSelection().addElement(res);
285       }
286
287       if (res > sg.getStartRes())
288       {
289         sg.setEndRes(res);
290       }
291       if (res < sg.getStartRes())
292       {
293         sg.setStartRes(res);
294       }
295
296       int col;
297       for (int i = min; i <= max; i++)
298       {
299         col = av.getColumnSelection().adjustForHiddenColumns(i);
300
301         if ((col < sg.getStartRes()) || (col > sg.getEndRes()))
302         {
303           av.getColumnSelection().removeElement(col);
304         }
305         else
306         {
307           av.getColumnSelection().addElement(col);
308         }
309       }
310
311       ap.paintAlignment(false);
312     }
313   }
314
315   public void mouseEntered(MouseEvent evt)
316   {
317     if (mouseDragging)
318     {
319       ap.seqPanel.scrollCanvas(null);
320     }
321   }
322
323   public void mouseExited(MouseEvent evt)
324   {
325     if (mouseDragging)
326     {
327       ap.seqPanel.scrollCanvas(evt);
328     }
329   }
330
331   public void mouseClicked(MouseEvent evt)
332   {
333   }
334
335   public void mouseMoved(MouseEvent evt)
336   {
337     if (!av.hasHiddenColumns)
338     {
339       return;
340     }
341
342     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
343
344     res = av.getColumnSelection().adjustForHiddenColumns(res);
345
346     reveal = null;
347     for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size(); i++)
348     {
349       int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
350               .elementAt(i);
351       if (res + 1 == region[0] || res - 1 == region[1])
352       {
353         reveal = region;
354         ToolTipManager.sharedInstance().registerComponent(this);
355         this
356                 .setToolTipText("Reveal Hidden Columns with Right Mouse Button");
357         break;
358       }
359       else
360       {
361         this.setToolTipText(null);
362       }
363
364     }
365
366     repaint();
367   }
368
369   int[] reveal;
370
371   /**
372    * DOCUMENT ME!
373    * 
374    * @param g
375    *                DOCUMENT ME!
376    */
377   public void paintComponent(Graphics g)
378   {
379     drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
380   }
381
382   // scalewidth will normally be screenwidth,
383   public void drawScale(Graphics g, int startx, int endx, int width,
384           int height)
385   {
386     Graphics2D gg = (Graphics2D) g;
387     gg.setFont(av.getFont());
388
389     if (av.antiAlias)
390     {
391       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
392               RenderingHints.VALUE_ANTIALIAS_ON);
393     }
394
395     // Fill in the background
396     gg.setColor(Color.white);
397     gg.fillRect(0, 0, width, height);
398     gg.setColor(Color.black);
399
400     // Fill the selected columns
401     ColumnSelection cs = av.getColumnSelection();
402     gg.setColor(new Color(220, 0, 0));
403
404     for (int i = 0; i < cs.size(); i++)
405     {
406       int sel = cs.columnAt(i);
407       if (av.hasHiddenColumns)
408       {
409         sel = av.getColumnSelection().findColumnPosition(sel);
410       }
411
412       if ((sel >= startx) && (sel <= endx))
413       {
414         gg.fillRect((sel - startx) * av.charWidth, 0, av.charWidth,
415                 getHeight());
416       }
417     }
418
419     // Draw the scale numbers
420     gg.setColor(Color.black);
421
422     int scalestartx = (startx / 10) * 10;
423
424     FontMetrics fm = gg.getFontMetrics(av.getFont());
425     int y = av.charHeight - fm.getDescent();
426
427     if ((scalestartx % 10) == 0)
428     {
429       scalestartx += 5;
430     }
431
432     String string;
433     int maxX = 0;
434
435     for (int i = scalestartx; i < endx; i += 5)
436     {
437       if ((i % 10) == 0)
438       {
439         string = String.valueOf(av.getColumnSelection()
440                 .adjustForHiddenColumns(i));
441         if ((i - startx - 1) * av.charWidth > maxX)
442         {
443           gg.drawString(string, (i - startx - 1) * av.charWidth, y);
444           maxX = (i - startx + 1) * av.charWidth + fm.stringWidth(string);
445         }
446
447         gg
448                 .drawLine(
449                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
450                         y + 2,
451                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
452                         y + (fm.getDescent() * 2));
453
454       }
455       else
456       {
457         gg
458                 .drawLine(
459                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
460                         y + fm.getDescent(),
461                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
462                         y + (fm.getDescent() * 2));
463       }
464     }
465
466     if (av.hasHiddenColumns)
467     {
468       gg.setColor(Color.blue);
469       int res;
470       if (av.getShowHiddenMarkers())
471       {
472         for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
473                 .size(); i++)
474         {
475
476           res = av.getColumnSelection().findHiddenRegionPosition(i)
477                   - startx;
478
479           if (res < 0 || res > endx - scalestartx)
480           {
481             continue;
482           }
483
484           gg.fillPolygon(new int[]
485           { res * av.charWidth - av.charHeight / 4,
486               res * av.charWidth + av.charHeight / 4, res * av.charWidth },
487                   new int[]
488                   { y - av.charHeight / 2, y - av.charHeight / 2, y + 8 },
489                   3);
490
491         }
492       }
493
494       if (reveal != null && reveal[0] > startx && reveal[0] < endx)
495       {
496         gg.drawString("Reveal Columns", reveal[0] * av.charWidth, 0);
497       }
498     }
499
500   }
501 }