Clover icon

Coverage Report

  1. Project Clover database Wed Nov 13 2024 16:21:17 GMT
  2. Package jalview.appletgui

File ScalePanel.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
59% of files have more coverage

Code metrics

62
153
17
1
477
363
53
0.35
9
17
3.12

Classes

Class Line # Actions
ScalePanel 48 153 53
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

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.datamodel.ColumnSelection;
24    import jalview.datamodel.HiddenColumns;
25    import jalview.datamodel.SequenceGroup;
26    import jalview.renderer.ScaleRenderer;
27    import jalview.renderer.ScaleRenderer.ScaleMark;
28    import jalview.util.MessageManager;
29    import jalview.viewmodel.ViewportListenerI;
30    import jalview.viewmodel.ViewportRanges;
31   
32    import java.awt.Color;
33    import java.awt.FontMetrics;
34    import java.awt.Graphics;
35    import java.awt.MenuItem;
36    import java.awt.Panel;
37    import java.awt.PopupMenu;
38    import java.awt.event.ActionEvent;
39    import java.awt.event.ActionListener;
40    import java.awt.event.InputEvent;
41    import java.awt.event.MouseEvent;
42    import java.awt.event.MouseListener;
43    import java.awt.event.MouseMotionListener;
44    import java.beans.PropertyChangeEvent;
45    import java.util.Iterator;
46    import java.util.List;
47   
 
48    public class ScalePanel extends Panel
49    implements MouseMotionListener, MouseListener, ViewportListenerI
50    {
51   
52    protected int offy = 4;
53   
54    public int width;
55   
56    protected AlignViewport av;
57   
58    AlignmentPanel ap;
59   
60    boolean stretchingGroup = false;
61   
62    int min; // used by mouseDragged to see if user
63   
64    int max; // used by mouseDragged to see if user
65   
66    boolean mouseDragging = false;
67   
68    int[] reveal;
69   
 
70  0 toggle public ScalePanel(AlignViewport av, AlignmentPanel ap)
71    {
72  0 setLayout(null);
73  0 this.av = av;
74  0 this.ap = ap;
75   
76  0 addMouseListener(this);
77  0 addMouseMotionListener(this);
78   
79  0 av.getRanges().addPropertyChangeListener(this);
80    }
81   
 
82  0 toggle @Override
83    public void mousePressed(MouseEvent evt)
84    {
85  0 int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
86  0 final int res;
87   
88  0 if (av.hasHiddenColumns())
89    {
90  0 res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x);
91    }
92    else
93    {
94  0 res = x;
95    }
96   
97  0 min = res;
98  0 max = res;
99  0 if ((evt.getModifiersEx()
100    & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
101    {
102  0 rightMouseButtonPressed(evt, res);
103    }
104    else
105    {
106  0 leftMouseButtonPressed(evt, res);
107    }
108    }
109   
110    /**
111    * Handles left mouse button pressed (selection / clear selections)
112    *
113    * @param evt
114    * @param res
115    */
 
116  0 toggle protected void leftMouseButtonPressed(MouseEvent evt, final int res)
117    {
118  0 if (!evt.isControlDown() && !evt.isShiftDown())
119    {
120  0 av.getColumnSelection().clear();
121    }
122   
123  0 av.getColumnSelection().addElement(res);
124  0 SequenceGroup sg = new SequenceGroup();
125  0 for (int i = 0; i < av.getAlignment().getSequences().size(); i++)
126    {
127  0 sg.addSequence(av.getAlignment().getSequenceAt(i), false);
128    }
129   
130  0 sg.setStartRes(res);
131  0 sg.setEndRes(res);
132  0 av.setSelectionGroup(sg);
133   
134  0 if (evt.isShiftDown())
135    {
136  0 int min = Math.min(av.getColumnSelection().getMin(), res);
137  0 int max = Math.max(av.getColumnSelection().getMax(), res);
138  0 for (int i = min; i < max; i++)
139    {
140  0 av.getColumnSelection().addElement(i);
141    }
142  0 sg.setStartRes(min);
143  0 sg.setEndRes(max);
144    }
145  0 ap.paintAlignment(false, false);
146  0 av.sendSelection();
147    }
148   
149    /**
150    * Handles right mouse button press. If pressed in a selected column, opens
151    * context menu for 'Hide Columns'. If pressed on a hidden columns marker,
152    * opens context menu for 'Reveal / Reveal All'. Else does nothing.
153    *
154    * @param evt
155    * @param res
156    */
 
157  0 toggle protected void rightMouseButtonPressed(MouseEvent evt, final int res)
158    {
159  0 PopupMenu pop = new PopupMenu();
160  0 if (reveal != null)
161    {
162  0 MenuItem item = new MenuItem(
163    MessageManager.getString("label.reveal"));
164  0 item.addActionListener(new ActionListener()
165    {
 
166  0 toggle @Override
167    public void actionPerformed(ActionEvent e)
168    {
169  0 av.showColumn(reveal[0]);
170  0 reveal = null;
171  0 ap.paintAlignment(true, true);
172  0 av.sendSelection();
173    }
174    });
175  0 pop.add(item);
176   
177  0 if (av.getAlignment().getHiddenColumns()
178    .hasMultiHiddenColumnRegions())
179    {
180  0 item = new MenuItem(MessageManager.getString("action.reveal_all"));
181  0 item.addActionListener(new ActionListener()
182    {
 
183  0 toggle @Override
184    public void actionPerformed(ActionEvent e)
185    {
186  0 av.showAllHiddenColumns();
187  0 reveal = null;
188  0 ap.paintAlignment(true, true);
189  0 av.sendSelection();
190    }
191    });
192  0 pop.add(item);
193    }
194  0 this.add(pop);
195  0 pop.show(this, evt.getX(), evt.getY());
196    }
197  0 else if (av.getColumnSelection().contains(res))
198    {
199  0 MenuItem item = new MenuItem(
200    MessageManager.getString("label.hide_columns"));
201  0 item.addActionListener(new ActionListener()
202    {
 
203  0 toggle @Override
204    public void actionPerformed(ActionEvent e)
205    {
206  0 av.hideColumns(res, res);
207  0 if (av.getSelectionGroup() != null && av.getSelectionGroup()
208    .getSize() == av.getAlignment().getHeight())
209    {
210  0 av.setSelectionGroup(null);
211    }
212   
213  0 ap.paintAlignment(true, true);
214  0 av.sendSelection();
215    }
216    });
217  0 pop.add(item);
218  0 this.add(pop);
219  0 pop.show(this, evt.getX(), evt.getY());
220    }
221    }
222   
 
223  0 toggle @Override
224    public void mouseReleased(MouseEvent evt)
225    {
226  0 mouseDragging = false;
227   
228  0 int res = (evt.getX() / av.getCharWidth())
229    + av.getRanges().getStartRes();
230   
231  0 if (res > av.getAlignment().getWidth())
232    {
233  0 res = av.getAlignment().getWidth() - 1;
234    }
235   
236  0 if (av.hasHiddenColumns())
237    {
238  0 res = av.getAlignment().getHiddenColumns()
239    .visibleToAbsoluteColumn(res);
240    }
241   
242  0 if (!stretchingGroup)
243    {
244  0 ap.paintAlignment(false, false);
245   
246  0 return;
247    }
248   
249  0 SequenceGroup sg = av.getSelectionGroup();
250   
251  0 if (res > sg.getStartRes())
252    {
253  0 sg.setEndRes(res);
254    }
255  0 else if (res < sg.getStartRes())
256    {
257  0 sg.setStartRes(res);
258    }
259   
260  0 stretchingGroup = false;
261  0 ap.paintAlignment(false, false);
262  0 av.sendSelection();
263    }
264   
265    /**
266    * Action on dragging the mouse in the scale panel is to expand or shrink the
267    * selection group range (including any hidden columns that it spans)
268    *
269    * @param evt
270    */
 
271  0 toggle @Override
272    public void mouseDragged(MouseEvent evt)
273    {
274  0 mouseDragging = true;
275  0 ColumnSelection cs = av.getColumnSelection();
276   
277  0 int res = (evt.getX() / av.getCharWidth())
278    + av.getRanges().getStartRes();
279  0 res = Math.max(0, res);
280  0 res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(res);
281  0 res = Math.min(res, av.getAlignment().getWidth() - 1);
282  0 min = Math.min(res, min);
283  0 max = Math.max(res, max);
284   
285  0 SequenceGroup sg = av.getSelectionGroup();
286  0 if (sg != null)
287    {
288  0 stretchingGroup = true;
289  0 cs.stretchGroup(res, sg, min, max);
290  0 ap.paintAlignment(false, false);
291    }
292    }
293   
 
294  0 toggle @Override
295    public void mouseEntered(MouseEvent evt)
296    {
297  0 if (mouseDragging)
298    {
299  0 ap.seqPanel.scrollCanvas(null);
300    }
301    }
302   
 
303  0 toggle @Override
304    public void mouseExited(MouseEvent evt)
305    {
306  0 if (mouseDragging)
307    {
308  0 ap.seqPanel.scrollCanvas(evt);
309    }
310    }
311   
 
312  0 toggle @Override
313    public void mouseClicked(MouseEvent evt)
314    {
315   
316    }
317   
 
318  0 toggle @Override
319    public void mouseMoved(MouseEvent evt)
320    {
321  0 if (!av.hasHiddenColumns())
322    {
323  0 return;
324    }
325   
326  0 int res = (evt.getX() / av.getCharWidth())
327    + av.getRanges().getStartRes();
328   
329  0 reveal = av.getAlignment().getHiddenColumns()
330    .getRegionWithEdgeAtRes(res);
331   
332  0 repaint();
333    }
334   
 
335  0 toggle @Override
336    public void update(Graphics g)
337    {
338  0 paint(g);
339    }
340   
 
341  0 toggle @Override
342    public void paint(Graphics g)
343    {
344    /*
345    * shouldn't get called in wrapped mode as the scale above is
346    * drawn instead by SeqCanvas.drawNorthScale
347    */
348  0 if (!av.getWrapAlignment())
349    {
350  0 drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
351    getSize().width, getSize().height);
352    }
353    }
354   
355    // scalewidth will normally be screenwidth,
 
356  0 toggle public void drawScale(Graphics gg, int startx, int endx, int width,
357    int height)
358    {
359  0 gg.setFont(av.getFont());
360    // Fill in the background
361  0 gg.setColor(Color.white);
362  0 gg.fillRect(0, 0, width, height);
363  0 gg.setColor(Color.black);
364   
365    // Fill the selected columns
366  0 ColumnSelection cs = av.getColumnSelection();
367  0 HiddenColumns hidden = av.getAlignment().getHiddenColumns();
368  0 int avCharWidth = av.getCharWidth();
369  0 int avcharHeight = av.getCharHeight();
370  0 if (cs != null)
371    {
372  0 gg.setColor(new Color(220, 0, 0));
373  0 boolean hasHiddenColumns = hidden.hasHiddenColumns();
374  0 for (int sel : cs.getSelected())
375    {
376    // TODO: JAL-2001 - provide a fast method to list visible selected in a
377    // given range
378  0 if (hasHiddenColumns)
379    {
380  0 if (hidden.isVisible(sel))
381    {
382  0 sel = hidden.absoluteToVisibleColumn(sel);
383    }
384    else
385    {
386  0 continue;
387    }
388    }
389   
390  0 if ((sel >= startx) && (sel <= endx))
391    {
392  0 gg.fillRect((sel - startx) * avCharWidth, 0, avCharWidth,
393    getSize().height);
394    }
395    }
396    }
397   
398    // Draw the scale numbers
399  0 gg.setColor(Color.black);
400   
401  0 int maxX = 0;
402  0 List<ScaleMark> marks = new ScaleRenderer().calculateMarks(av, startx,
403    endx);
404   
405  0 FontMetrics fm = gg.getFontMetrics(av.getFont());
406  0 int y = avcharHeight;
407  0 int yOf = fm.getDescent();
408  0 y -= yOf;
409  0 for (ScaleMark mark : marks)
410    {
411  0 boolean major = mark.major;
412  0 int mpos = mark.column; // (i - startx - 1)
413  0 String mstring = mark.text;
414  0 if (mstring != null)
415    {
416  0 if (mpos * avCharWidth > maxX)
417    {
418  0 gg.drawString(mstring, mpos * avCharWidth, y);
419  0 maxX = (mpos + 2) * avCharWidth + fm.stringWidth(mstring);
420    }
421    }
422  0 if (major)
423    {
424  0 gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + 2,
425    (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
426    }
427    else
428    {
429  0 gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + yOf,
430    (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
431    }
432    }
433   
434  0 if (av.hasHiddenColumns())
435    {
436  0 gg.setColor(Color.blue);
437  0 int res;
438  0 if (av.getShowHiddenMarkers())
439    {
440  0 int widthx = 1 + endx - startx;
441  0 Iterator<Integer> it = hidden.getStartRegionIterator(startx,
442    startx + widthx + 1);
443  0 while (it.hasNext())
444    {
445  0 res = it.next() - startx;
446   
447  0 gg.fillPolygon(
448    new int[]
449    { -1 + res * avCharWidth - avcharHeight / 4,
450    -1 + res * avCharWidth + avcharHeight / 4,
451    -1 + res * avCharWidth },
452    new int[]
453    { y, y, y + 2 * yOf }, 3);
454    }
455    }
456    }
457    }
458   
 
459  0 toggle @Override
460    public void propertyChange(PropertyChangeEvent evt)
461    {
462    // Respond to viewport change events (e.g. alignment panel was scrolled)
463    // Both scrolling and resizing change viewport ranges: scrolling changes
464    // both start and end points, but resize only changes end values.
465    // Here we only want to fastpaint on a scroll, with resize using a normal
466    // paint, so scroll events are identified as changes to the horizontal or
467    // vertical start value.
468  0 if (evt.getPropertyName().equals(ViewportRanges.STARTRES)
469    || evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ)
470    || evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))
471    {
472    // scroll event, repaint panel
473  0 repaint();
474    }
475    }
476   
477    }