JAL-1432 updated copyright notices
[jalview.git] / src / jalview / gui / ScalePanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
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       x = av.getColumnSelection().adjustForHiddenColumns(x);
77     }
78
79     if (x >= av.getAlignment().getWidth())
80     {
81       res = av.getAlignment().getWidth() - 1;
82     }
83     else
84     {
85       res = x;
86     }
87
88     min = res;
89     max = res;
90
91     if (SwingUtilities.isRightMouseButton(evt))
92     {
93       JPopupMenu pop = new JPopupMenu();
94       if (reveal != null)
95       {
96         JMenuItem item = new JMenuItem("Reveal");
97         item.addActionListener(new ActionListener()
98         {
99           public void actionPerformed(ActionEvent e)
100           {
101             av.showColumn(reveal[0]);
102             reveal = null;
103             ap.paintAlignment(true);
104             if (ap.overviewPanel != null)
105             {
106               ap.overviewPanel.updateOverviewImage();
107             }
108           }
109         });
110         pop.add(item);
111
112         if (av.getColumnSelection().getHiddenColumns().size() > 1)
113         {
114           item = new JMenuItem("Reveal All");
115           item.addActionListener(new ActionListener()
116           {
117             public void actionPerformed(ActionEvent e)
118             {
119               av.showAllHiddenColumns();
120               reveal = null;
121               ap.paintAlignment(true);
122               if (ap.overviewPanel != null)
123               {
124                 ap.overviewPanel.updateOverviewImage();
125               }
126             }
127           });
128           pop.add(item);
129         }
130         pop.show(this, evt.getX(), evt.getY());
131       }
132       else if (av.getColumnSelection().contains(res))
133       {
134         JMenuItem item = new JMenuItem("Hide Columns");
135         item.addActionListener(new ActionListener()
136         {
137           public void actionPerformed(ActionEvent e)
138           {
139             av.hideColumns(res, res);
140             if (av.getSelectionGroup() != null
141                     && av.getSelectionGroup().getSize() == av
142                             .getAlignment().getHeight())
143             {
144               av.setSelectionGroup(null);
145             }
146
147             ap.paintAlignment(true);
148             if (ap.overviewPanel != null)
149             {
150               ap.overviewPanel.updateOverviewImage();
151             }
152           }
153         });
154         pop.add(item);
155         pop.show(this, evt.getX(), evt.getY());
156       }
157     }
158     else
159     // LEFT MOUSE TO SELECT
160     {
161       if (!evt.isControlDown() && !evt.isShiftDown())
162       {
163         av.getColumnSelection().clear();
164       }
165
166       av.getColumnSelection().addElement(res);
167       SequenceGroup sg = new SequenceGroup();
168       // try to be as quick as possible
169       SequenceI[] iVec = av.getAlignment().getSequencesArray();
170       for (int i = 0; i < iVec.length; i++)
171       {
172         sg.addSequence(iVec[i], false);
173         iVec[i] = null;
174       }
175       iVec = null;
176       sg.setStartRes(res);
177       sg.setEndRes(res);
178
179       if (evt.isShiftDown())
180       {
181         int min = Math.min(av.getColumnSelection().getMin(), res);
182         int max = Math.max(av.getColumnSelection().getMax(), res);
183         for (int i = min; i < max; i++)
184         {
185           av.getColumnSelection().addElement(i);
186         }
187         sg.setStartRes(min);
188         sg.setEndRes(max);
189       }
190       av.setSelectionGroup(sg);
191     }
192
193     ap.paintAlignment(false);
194     av.sendSelection();
195   }
196
197   /**
198    * DOCUMENT ME!
199    * 
200    * @param evt
201    *          DOCUMENT ME!
202    */
203   public void mouseReleased(MouseEvent evt)
204   {
205     mouseDragging = false;
206
207     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
208
209     if (av.hasHiddenColumns())
210     {
211       res = av.getColumnSelection().adjustForHiddenColumns(res);
212     }
213
214     if (res >= av.getAlignment().getWidth())
215     {
216       res = av.getAlignment().getWidth() - 1;
217     }
218
219     if (!stretchingGroup)
220     {
221       ap.paintAlignment(false);
222
223       return;
224     }
225
226     SequenceGroup sg = av.getSelectionGroup();
227
228     if (sg != null)
229     {
230       if (res > sg.getStartRes())
231       {
232         sg.setEndRes(res);
233       }
234       else if (res < sg.getStartRes())
235       {
236         sg.setStartRes(res);
237       }
238     }
239     stretchingGroup = false;
240     ap.paintAlignment(false);
241     av.sendSelection();
242   }
243
244   /**
245    * DOCUMENT ME!
246    * 
247    * @param evt
248    *          DOCUMENT ME!
249    */
250   public void mouseDragged(MouseEvent evt)
251   {
252     mouseDragging = true;
253
254     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
255     if (res < 0)
256     {
257       res = 0;
258     }
259
260     if (av.hasHiddenColumns())
261     {
262       res = av.getColumnSelection().adjustForHiddenColumns(res);
263     }
264
265     if (res >= av.getAlignment().getWidth())
266     {
267       res = av.getAlignment().getWidth() - 1;
268     }
269
270     if (res < min)
271     {
272       min = res;
273     }
274
275     if (res > max)
276     {
277       max = res;
278     }
279
280     SequenceGroup sg = av.getSelectionGroup();
281
282     if (sg != null)
283     {
284       stretchingGroup = true;
285
286       if (!av.getColumnSelection().contains(res))
287       {
288         av.getColumnSelection().addElement(res);
289       }
290
291       if (res > sg.getStartRes())
292       {
293         sg.setEndRes(res);
294       }
295       if (res < sg.getStartRes())
296       {
297         sg.setStartRes(res);
298       }
299
300       int col;
301       for (int i = min; i <= max; i++)
302       {
303         col = i; // av.getColumnSelection().adjustForHiddenColumns(i);
304
305         if ((col < sg.getStartRes()) || (col > sg.getEndRes()))
306         {
307           av.getColumnSelection().removeElement(col);
308         }
309         else
310         {
311           av.getColumnSelection().addElement(col);
312         }
313       }
314
315       ap.paintAlignment(false);
316     }
317   }
318
319   public void mouseEntered(MouseEvent evt)
320   {
321     if (mouseDragging)
322     {
323       ap.seqPanel.scrollCanvas(null);
324     }
325   }
326
327   public void mouseExited(MouseEvent evt)
328   {
329     if (mouseDragging)
330     {
331       ap.seqPanel.scrollCanvas(evt);
332     }
333   }
334
335   public void mouseClicked(MouseEvent evt)
336   {
337   }
338
339   public void mouseMoved(MouseEvent evt)
340   {
341     if (!av.hasHiddenColumns())
342     {
343       return;
344     }
345
346     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
347
348     res = av.getColumnSelection().adjustForHiddenColumns(res);
349
350     reveal = null;
351     for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size(); i++)
352     {
353       int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
354               .elementAt(i);
355       if (res + 1 == region[0] || res - 1 == region[1])
356       {
357         reveal = region;
358         ToolTipManager.sharedInstance().registerComponent(this);
359         this.setToolTipText("Reveal Hidden Columns with Right Mouse Button");
360         break;
361       }
362       else
363       {
364         this.setToolTipText(null);
365       }
366
367     }
368
369     repaint();
370   }
371
372   int[] reveal;
373
374   /**
375    * DOCUMENT ME!
376    * 
377    * @param g
378    *          DOCUMENT ME!
379    */
380   public void paintComponent(Graphics g)
381   {
382     drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
383   }
384
385   // scalewidth will normally be screenwidth,
386   public void drawScale(Graphics g, int startx, int endx, int width,
387           int height)
388   {
389     Graphics2D gg = (Graphics2D) g;
390     gg.setFont(av.getFont());
391
392     if (av.antiAlias)
393     {
394       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
395               RenderingHints.VALUE_ANTIALIAS_ON);
396     }
397
398     // Fill in the background
399     gg.setColor(Color.white);
400     gg.fillRect(0, 0, width, height);
401     gg.setColor(Color.black);
402
403     // Fill the selected columns
404     ColumnSelection cs = av.getColumnSelection();
405     int s;
406     if (cs != null)
407     {
408       gg.setColor(new Color(220, 0, 0));
409
410       for (int i = 0; i < cs.size(); i++)
411       {
412         int sel = cs.columnAt(i);
413         if (av.hasHiddenColumns())
414         {
415           if (cs.isVisible(sel))
416           {
417             sel = cs.findColumnPosition(sel);
418           }
419           else
420           {
421             continue;
422           }
423         }
424
425         if ((sel >= startx) && (sel <= endx))
426         {
427           gg.fillRect((sel - startx) * av.charWidth, 0, av.charWidth,
428                   getHeight());
429         }
430       }
431     }
432     // Draw the scale numbers
433     gg.setColor(Color.black);
434
435     int scalestartx = (startx / 10) * 10;
436
437     FontMetrics fm = gg.getFontMetrics(av.getFont());
438     int y = av.charHeight - fm.getDescent();
439
440     if ((scalestartx % 10) == 0)
441     {
442       scalestartx += 5;
443     }
444
445     String string;
446     int maxX = 0;
447
448     for (int i = scalestartx; i < endx; i += 5)
449     {
450       if ((i % 10) == 0)
451       {
452         string = String.valueOf(av.getColumnSelection()
453                 .adjustForHiddenColumns(i));
454         if ((i - startx - 1) * av.charWidth > maxX)
455         {
456           gg.drawString(string, (i - startx - 1) * av.charWidth, y);
457           maxX = (i - startx + 1) * av.charWidth + fm.stringWidth(string);
458         }
459
460         gg.drawLine(
461                 (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
462                 y + 2,
463                 (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
464                 y + (fm.getDescent() * 2));
465
466       }
467       else
468       {
469         gg.drawLine(
470                 (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
471                 y + fm.getDescent(),
472                 (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
473                 y + (fm.getDescent() * 2));
474       }
475     }
476
477     if (av.hasHiddenColumns())
478     {
479       gg.setColor(Color.blue);
480       int res;
481       if (av.getShowHiddenMarkers())
482       {
483         for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
484                 .size(); i++)
485         {
486
487           res = av.getColumnSelection().findHiddenRegionPosition(i)
488                   - startx;
489
490           if (res < 0 || res > endx - scalestartx)
491           {
492             continue;
493           }
494
495           gg.fillPolygon(new int[]
496           { res * av.charWidth - av.charHeight / 4,
497               res * av.charWidth + av.charHeight / 4, res * av.charWidth },
498                   new int[]
499                   { y - av.charHeight / 2, y - av.charHeight / 2, y + 8 },
500                   3);
501
502         }
503       }
504
505       if (reveal != null && reveal[0] > startx && reveal[0] < endx)
506       {
507         gg.drawString("Reveal Columns", reveal[0] * av.charWidth, 0);
508       }
509     }
510
511   }
512 }