source: josm/trunk/src/org/openstreetmap/josm/gui/ScrollViewport.java@ 13146

Last change on this file since 13146 was 12866, checked in by Don-vip, 7 years ago

SonarQube:

  • squid:S4144 - Methods should not have identical implementations
  • squid:S4165 - Assignments should not be redundant
  • Property svn:eol-style set to native
File size: 8.6 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[1180]2package org.openstreetmap.josm.gui;
3
4import java.awt.BorderLayout;
5import java.awt.Dimension;
6import java.awt.Point;
7import java.awt.Rectangle;
[2391]8import java.awt.event.ComponentAdapter;
9import java.awt.event.ComponentEvent;
[1180]10import java.awt.event.MouseAdapter;
11import java.awt.event.MouseEvent;
[2391]12import java.util.ArrayList;
13import java.util.List;
14
[1180]15import javax.swing.JButton;
16import javax.swing.JComponent;
17import javax.swing.JPanel;
18import javax.swing.JViewport;
19import javax.swing.Timer;
20
21import org.openstreetmap.josm.tools.ImageProvider;
22
[12073]23/**
24 * A viewport with UP and DOWN arrow buttons, so that the user can make the
[1180]25 * content scroll.
[12073]26 *
27 * This should be used for long, vertical toolbars.
[1180]28 */
29public class ScrollViewport extends JPanel {
30
31 private static final int NO_SCROLL = 0;
32
[12391]33 /**
34 * Direction flag for upwards
35 */
[1180]36 public static final int UP_DIRECTION = 1;
[12391]37 /**
38 * Direction flag for downwards
39 */
[1180]40 public static final int DOWN_DIRECTION = 2;
[12391]41 /**
42 * Direction flag for left
43 */
[1180]44 public static final int LEFT_DIRECTION = 4;
[12391]45 /**
46 * Direction flag for right
47 */
[1180]48 public static final int RIGHT_DIRECTION = 8;
[12073]49 /**
50 * Allow vertical scrolling
51 */
[1180]52 public static final int VERTICAL_DIRECTION = UP_DIRECTION | DOWN_DIRECTION;
[12073]53
54 /**
55 * Allow horizontal scrolling
56 */
[1180]57 public static final int HORIZONTAL_DIRECTION = LEFT_DIRECTION | RIGHT_DIRECTION;
[12073]58
59 /**
60 * Allow scrolling in both directions
61 */
[1180]62 public static final int ALL_DIRECTION = HORIZONTAL_DIRECTION | VERTICAL_DIRECTION;
63
64 private class ScrollViewPortMouseListener extends MouseAdapter {
[9078]65 private final int direction;
[1180]66
[8836]67 ScrollViewPortMouseListener(int direction) {
[1180]68 this.direction = direction;
69 }
70
[8836]71 @Override
[12866]72 public void mouseExited(MouseEvent e) {
73 mouseReleased(e);
[1180]74 }
75
[8836]76 @Override
[12866]77 public void mouseReleased(MouseEvent e) {
[1180]78 ScrollViewport.this.scrollDirection = NO_SCROLL;
79 timer.stop();
80 }
81
[12866]82 @Override
83 public void mousePressed(MouseEvent e) {
[1180]84 ScrollViewport.this.scrollDirection = direction;
85 scroll();
86 timer.restart();
87 }
88 }
89
[9078]90 private final JViewport vp = new JViewport();
[8840]91 private JComponent component;
[2512]92
[9078]93 private final List<JButton> buttons = new ArrayList<>();
[1180]94
[10634]95 private final Timer timer = new Timer(100, evt -> scroll());
[1180]96
97 private int scrollDirection = NO_SCROLL;
98
[12073]99 private final int allowedScrollDirections;
100
101 private final ComponentAdapter refreshButtonsOnResize = new ComponentAdapter() {
102 @Override
103 public void componentResized(ComponentEvent e) {
104 showOrHideButtons();
105 }
106 };
107
108 /**
109 * Create a new scroll viewport
110 * @param c The component to display as content.
111 * @param direction The direction to scroll.
112 * Should be one of {@link #VERTICAL_DIRECTION}, {@link #HORIZONTAL_DIRECTION}, {@link #ALL_DIRECTION}
113 */
[1180]114 public ScrollViewport(JComponent c, int direction) {
115 this(direction);
116 add(c);
117 }
118
[12073]119 /**
120 * Create a new scroll viewport
121 * @param direction The direction to scroll.
122 * Should be one of {@link #VERTICAL_DIRECTION}, {@link #HORIZONTAL_DIRECTION}, {@link #ALL_DIRECTION}
123 */
[1180]124 public ScrollViewport(int direction) {
[12073]125 super(new BorderLayout());
126 this.allowedScrollDirections = direction;
[2512]127
[1180]128 // UP
[10244]129 if ((direction & UP_DIRECTION) != 0) {
[12073]130 addScrollButton(UP_DIRECTION, "svpUp", BorderLayout.NORTH);
[1180]131 }
132
133 // DOWN
[10244]134 if ((direction & DOWN_DIRECTION) != 0) {
[12073]135 addScrollButton(DOWN_DIRECTION, "svpDown", BorderLayout.SOUTH);
[1180]136 }
137
138 // LEFT
[10244]139 if ((direction & LEFT_DIRECTION) != 0) {
[12073]140 addScrollButton(LEFT_DIRECTION, "svpLeft", BorderLayout.WEST);
[1180]141 }
142
143 // RIGHT
[10244]144 if ((direction & RIGHT_DIRECTION) != 0) {
[12073]145 addScrollButton(RIGHT_DIRECTION, "svpRight", BorderLayout.EAST);
[1180]146 }
147
148 add(vp, BorderLayout.CENTER);
149
[12073]150 this.addComponentListener(refreshButtonsOnResize);
[2391]151
152 showOrHideButtons();
[2512]153
[12079]154 if ((direction & VERTICAL_DIRECTION) != 0) {
155 addMouseWheelListener(e -> scroll(0, e.getUnitsToScroll() * 5));
156 } else if ((direction & HORIZONTAL_DIRECTION) != 0) {
157 addMouseWheelListener(e -> scroll(e.getUnitsToScroll() * 5, 0));
158 }
159
[1180]160 timer.setRepeats(true);
161 timer.setInitialDelay(400);
162 }
163
[12073]164 private void addScrollButton(int direction, String icon, String borderLayoutPosition) {
165 JButton button = new JButton();
166 button.addMouseListener(new ScrollViewPortMouseListener(direction));
167 button.setPreferredSize(new Dimension(10, 10));
168 button.setIcon(ImageProvider.get(icon));
169 add(button, borderLayoutPosition);
170 buttons.add(button);
171 }
172
173 /**
174 * Scrolls in the currently selected scroll direction.
175 */
[1180]176 public synchronized void scroll() {
177 int direction = scrollDirection;
178
[2676]179 if (component == null || direction == NO_SCROLL)
[1180]180 return;
181
182 Rectangle viewRect = vp.getViewRect();
183
[2391]184 int deltaX = 0;
185 int deltaY = 0;
[1180]186
187 if (direction < LEFT_DIRECTION) {
[2391]188 deltaY = viewRect.height * 2 / 7;
[1180]189 } else {
[2391]190 deltaX = viewRect.width * 2 / 7;
[1180]191 }
192
193 switch (direction) {
[2676]194 case UP_DIRECTION :
195 deltaY *= -1;
196 break;
197 case LEFT_DIRECTION :
198 deltaX *= -1;
199 break;
[10217]200 default: // Do nothing
[1180]201 }
202
[2391]203 scroll(deltaX, deltaY);
204 }
[8510]205
[12073]206 /**
207 * Scrolls by the given offset
208 * @param deltaX offset x
209 * @param deltaY offset y
210 */
[2391]211 public synchronized void scroll(int deltaX, int deltaY) {
[2676]212 if (component == null)
[2391]213 return;
214 Dimension compSize = component.getSize();
215 Rectangle viewRect = vp.getViewRect();
216
217 int newX = viewRect.x + deltaX;
218 int newY = viewRect.y + deltaY;
219
220 if (newY < 0) {
221 newY = 0;
222 }
223 if (newY > compSize.height - viewRect.height) {
224 newY = compSize.height - viewRect.height;
225 }
226 if (newX < 0) {
227 newX = 0;
228 }
229 if (newX > compSize.width - viewRect.width) {
230 newX = compSize.width - viewRect.width;
231 }
232
[1180]233 vp.setViewPosition(new Point(newX, newY));
234 }
235
[2391]236 /**
237 * Update the visibility of the buttons
238 * Only show them if the Viewport is too small for the content.
239 */
240 public void showOrHideButtons() {
[12073]241 boolean needButtons = false;
242 if ((allowedScrollDirections & VERTICAL_DIRECTION) != 0) {
243 needButtons |= getViewSize().height > getViewRect().height;
244 }
245 if ((allowedScrollDirections & HORIZONTAL_DIRECTION) != 0) {
246 needButtons |= getViewSize().width > getViewRect().width;
247 }
[2391]248 for (JButton b : buttons) {
249 b.setVisible(needButtons);
250 }
251 }
[2512]252
[12391]253 /**
254 * Gets the current visible part of the view
255 * @return The current view rect
256 */
[1180]257 public Rectangle getViewRect() {
258 return vp.getViewRect();
259 }
260
[12391]261 /**
262 * Gets the size of the view
263 * @return The size
264 */
[1180]265 public Dimension getViewSize() {
266 return vp.getViewSize();
267 }
268
[12391]269 /**
270 * Gets the position (offset) of the view area
271 * @return The offset
272 */
[1180]273 public Point getViewPosition() {
274 return vp.getViewPosition();
275 }
276
[12073]277 @Override
278 public Dimension getPreferredSize() {
[12079]279 if (component == null) {
280 return vp.getPreferredSize();
281 } else {
282 return component.getPreferredSize();
283 }
[12073]284 }
285
286 @Override
287 public Dimension getMinimumSize() {
[12079]288 if (component == null) {
289 return vp.getMinimumSize();
290 } else {
291 Dimension minSize = component.getMinimumSize();
292 if ((allowedScrollDirections & HORIZONTAL_DIRECTION) != 0) {
293 minSize = new Dimension(20, minSize.height);
294 }
295 if ((allowedScrollDirections & VERTICAL_DIRECTION) != 0) {
296 minSize = new Dimension(minSize.width, 20);
297 }
298 return minSize;
299 }
[12073]300 }
301
302 /**
303 * Sets the component to be used as content.
304 * @param c The component
305 */
[1180]306 public void add(JComponent c) {
307 vp.removeAll();
[12073]308 if (this.component != null) {
309 this.component.removeComponentListener(refreshButtonsOnResize);
310 }
[1180]311 this.component = c;
[12073]312 c.addComponentListener(refreshButtonsOnResize);
[1180]313 vp.add(c);
314 }
315}
Note: See TracBrowser for help on using the repository browser.