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