JAL-1553 enhancement of column selection by annotation row to include the query filte...
[jalview.git] / src / jalview / gui / ScalePanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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().getHiddenColumns().size() > 1)
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 i = 0; i < av.getColumnSelection().getHiddenColumns().size(); i++)
375     {
376       int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
377               .elementAt(i);
378       if (res + 1 == region[0] || res - 1 == region[1])
379       {
380         reveal = region;
381         ToolTipManager.sharedInstance().registerComponent(this);
382         this.setToolTipText(MessageManager
383                 .getString("label.reveal_hidden_columns"));
384         break;
385       }
386       else
387       {
388         this.setToolTipText(null);
389       }
390
391     }
392     }
393     repaint();
394   }
395
396   int[] reveal;
397
398   /**
399    * DOCUMENT ME!
400    * 
401    * @param g
402    *          DOCUMENT ME!
403    */
404   public void paintComponent(Graphics g)
405   {
406     drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
407   }
408
409   // scalewidth will normally be screenwidth,
410   public void drawScale(Graphics g, int startx, int endx, int width,
411           int height)
412   {
413     Graphics2D gg = (Graphics2D) g;
414     gg.setFont(av.getFont());
415
416     if (av.antiAlias)
417     {
418       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
419               RenderingHints.VALUE_ANTIALIAS_ON);
420     }
421
422     // Fill in the background
423     gg.setColor(Color.white);
424     gg.fillRect(0, 0, width, height);
425     gg.setColor(Color.black);
426
427     // Fill the selected columns
428     ColumnSelection cs = av.getColumnSelection();
429     int s;
430     if (cs != null)
431     {
432       gg.setColor(new Color(220, 0, 0));
433
434       for (int i = 0; i < cs.size(); i++)
435       {
436         int sel = cs.columnAt(i);
437         if (av.hasHiddenColumns())
438         {
439           if (cs.isVisible(sel))
440           {
441             sel = cs.findColumnPosition(sel);
442           }
443           else
444           {
445             continue;
446           }
447         }
448
449         if ((sel >= startx) && (sel <= endx))
450         {
451           gg.fillRect((sel - startx) * av.charWidth, 0, av.charWidth,
452                   getHeight());
453         }
454       }
455     }
456     // Draw the scale numbers
457     gg.setColor(Color.black);
458
459     int scalestartx = (startx / 10) * 10;
460
461     FontMetrics fm = gg.getFontMetrics(av.getFont());
462     int y = av.charHeight - fm.getDescent();
463
464     if ((scalestartx % 10) == 0)
465     {
466       scalestartx += 5;
467     }
468
469     String string;
470     int maxX = 0;
471
472     for (int i = scalestartx; i < endx; i += 5)
473     {
474       if ((i % 10) == 0)
475       {
476         string = String.valueOf(av.getColumnSelection()
477                 .adjustForHiddenColumns(i));
478         if ((i - startx - 1) * av.charWidth > maxX)
479         {
480           gg.drawString(string, (i - startx - 1) * av.charWidth, y);
481           maxX = (i - startx + 1) * av.charWidth + fm.stringWidth(string);
482         }
483
484         gg.drawLine(
485                 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2),
486                 y + 2,
487                 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2),
488                 y + (fm.getDescent() * 2));
489
490       }
491       else
492       {
493         gg.drawLine(
494                 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2),
495                 y + fm.getDescent(),
496                 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2),
497                 y + (fm.getDescent() * 2));
498       }
499     }
500
501     if (av.hasHiddenColumns())
502     {
503       gg.setColor(Color.blue);
504       int res;
505       if (av.getShowHiddenMarkers()
506               && av.getColumnSelection().getHiddenColumns() != null)
507       {
508         for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
509                 .size(); i++)
510         {
511
512           res = av.getColumnSelection().findHiddenRegionPosition(i)
513                   - startx;
514
515           if (res < 0 || res > endx - scalestartx)
516           {
517             continue;
518           }
519
520           gg.fillPolygon(new int[]
521           { res * av.charWidth - av.charHeight / 4,
522               res * av.charWidth + av.charHeight / 4, res * av.charWidth },
523                   new int[]
524                   { y - av.charHeight / 2, y - av.charHeight / 2, y + 8 },
525                   3);
526
527         }
528       }
529
530       if (reveal != null && reveal[0] > startx && reveal[0] < endx)
531       {
532         gg.drawString(MessageManager.getString("label.reveal_columns"),
533                 reveal[0] * av.charWidth, 0);
534       }
535     }
536
537   }
538 }