Project

General

Profile

Download (16.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.draw2d;
12

    
13
import java.beans.PropertyChangeEvent;
14
import java.beans.PropertyChangeListener;
15

    
16
import org.eclipse.swt.graphics.Color;
17

    
18
import org.eclipse.draw2d.geometry.Dimension;
19
import org.eclipse.draw2d.geometry.Point;
20
import org.eclipse.draw2d.geometry.Rectangle;
21
import org.eclipse.draw2d.geometry.Transposer;
22

    
23
/**
24
 * Provides for the scrollbars used by the {@link ScrollPane}. A ScrollBar is
25
 * made up of five essential Figures: An 'Up' arrow button, a 'Down' arrow
26
 * button, a draggable 'Thumb', a 'Pageup' button, and a 'Pagedown' button.
27
 */
28
public class ScrollBar extends Figure implements Orientable,
29
		PropertyChangeListener {
30

    
31
	private static final int ORIENTATION_FLAG = Figure.MAX_FLAG << 1;
32
	/** @see Figure#MAX_FLAG */
33
	protected static final int MAX_FLAG = ORIENTATION_FLAG;
34

    
35
	private static final Color COLOR_TRACK = FigureUtilities.mixColors(
36
			ColorConstants.white, ColorConstants.button);
37

    
38
	private RangeModel rangeModel = null;
39
	private IFigure thumb;
40
	private Clickable pageUp, pageDown;
41
	private Clickable buttonUp, buttonDown;
42
	/**
43
	 * Listens to mouse events on the scrollbar to take care of scrolling.
44
	 */
45
	protected ThumbDragger thumbDragger = new ThumbDragger();
46

    
47
	private boolean isHorizontal = false;
48

    
49
	private int pageIncrement = 50;
50
	private int stepIncrement = 10;
51

    
52
	/**
53
	 * Transposes from vertical to horizontal if needed.
54
	 */
55
	protected final Transposer transposer = new Transposer();
56

    
57
	{
58
		setRangeModel(new DefaultRangeModel());
59
	}
60

    
61
	/**
62
	 * Constructs a ScrollBar. ScrollBar orientation is vertical by default.
63
	 * Call {@link #setHorizontal(boolean)} with <code>true</code> to set
64
	 * horizontal orientation.
65
	 * 
66
	 * @since 2.0
67
	 */
68
	public ScrollBar() {
69
		initialize();
70
	}
71

    
72
	/**
73
	 * Creates the default 'Up' ArrowButton for the ScrollBar.
74
	 * 
75
	 * @return the up button
76
	 * @since 2.0
77
	 */
78
	protected Clickable createDefaultUpButton() {
79
		Button buttonUp = new ArrowButton();
80
		buttonUp.setBorder(new ButtonBorder(
81
				ButtonBorder.SCHEMES.BUTTON_SCROLLBAR));
82
		return buttonUp;
83
	}
84

    
85
	/**
86
	 * Creates the default 'Down' ArrowButton for the ScrollBar.
87
	 * 
88
	 * @return the down button
89
	 * @since 2.0
90
	 */
91
	protected Clickable createDefaultDownButton() {
92
		Button buttonDown = new ArrowButton();
93
		buttonDown.setBorder(new ButtonBorder(
94
				ButtonBorder.SCHEMES.BUTTON_SCROLLBAR));
95
		return buttonDown;
96
	}
97

    
98
	/**
99
	 * Creates the pagedown Figure for the Scrollbar.
100
	 * 
101
	 * @return the page down figure
102
	 * @since 2.0
103
	 */
104
	protected Clickable createPageDown() {
105
		return createPageUp();
106
	}
107

    
108
	/**
109
	 * Creates the pageup Figure for the Scrollbar.
110
	 * 
111
	 * @return the page up figure
112
	 * @since 2.0
113
	 */
114
	protected Clickable createPageUp() {
115
		final Clickable clickable = new Clickable();
116
		clickable.setOpaque(true);
117
		clickable.setBackgroundColor(COLOR_TRACK);
118
		clickable.setRequestFocusEnabled(false);
119
		clickable.setFocusTraversable(false);
120
		clickable.addChangeListener(new ChangeListener() {
121
			public void handleStateChanged(ChangeEvent evt) {
122
				if (clickable.getModel().isArmed())
123
					clickable.setBackgroundColor(ColorConstants.black);
124
				else
125
					clickable.setBackgroundColor(COLOR_TRACK);
126
			}
127
		});
128
		return clickable;
129
	}
130

    
131
	/**
132
	 * Creates the Scrollbar's "thumb", the draggable Figure that indicates the
133
	 * Scrollbar's position.
134
	 * 
135
	 * @return the thumb figure
136
	 * @since 2.0
137
	 */
138
	protected IFigure createDefaultThumb() {
139
		Panel thumb = new Panel();
140
		thumb.setMinimumSize(new Dimension(6, 6));
141
		thumb.setBackgroundColor(ColorConstants.button);
142

    
143
		thumb.setBorder(new SchemeBorder(SchemeBorder.SCHEMES.BUTTON_CONTRAST));
144
		return thumb;
145
	}
146

    
147
	/**
148
	 * Returns the figure used as the up button.
149
	 * 
150
	 * @return the up button
151
	 */
152
	protected IFigure getButtonUp() {
153
		// TODO: The set method takes a Clickable while the get method returns
154
		// an IFigure.
155
		// Change the get method to return Clickable (since that's what it's
156
		// typed as).
157
		return buttonUp;
158
	}
159

    
160
	/**
161
	 * Returns the figure used as the down button.
162
	 * 
163
	 * @return the down button
164
	 */
165
	protected IFigure getButtonDown() {
166
		// TODO: The set method takes a Clickable while the get method returns
167
		// an IFigure.
168
		// Change the get method to return Clickable (since that's what it's
169
		// typed as).
170
		return buttonDown;
171
	}
172

    
173
	/**
174
	 * Returns the extent.
175
	 * 
176
	 * @return the extent
177
	 * @see RangeModel#getExtent()
178
	 */
179
	public int getExtent() {
180
		return getRangeModel().getExtent();
181
	}
182

    
183
	/**
184
	 * Returns the minumum value.
185
	 * 
186
	 * @return the minimum
187
	 * @see RangeModel#getMinimum()
188
	 */
189
	public int getMinimum() {
190
		return getRangeModel().getMinimum();
191
	}
192

    
193
	/**
194
	 * Returns the maximum value.
195
	 * 
196
	 * @return the maximum
197
	 * @see RangeModel#getMaximum()
198
	 */
199
	public int getMaximum() {
200
		return getRangeModel().getMaximum();
201
	}
202

    
203
	/**
204
	 * Returns the figure used for page down.
205
	 * 
206
	 * @return the page down figure
207
	 */
208
	protected IFigure getPageDown() {
209
		// TODO: The set method takes a Clickable while the get method returns
210
		// an IFigure.
211
		// Change the get method to return Clickable (since that's what it's
212
		// typed as).
213
		return pageDown;
214
	}
215

    
216
	/**
217
	 * Returns the the amound the scrollbar will move when the page up or page
218
	 * down areas are pressed.
219
	 * 
220
	 * @return the page increment
221
	 */
222
	public int getPageIncrement() {
223
		return pageIncrement;
224
	}
225

    
226
	/**
227
	 * Returns the figure used for page up.
228
	 * 
229
	 * @return the page up figure
230
	 */
231
	protected IFigure getPageUp() {
232
		// TODO: The set method takes a Clickable while the get method returns
233
		// an IFigure.
234
		// Change the get method to return Clickable (since that's what it's
235
		// typed as).
236
		return pageUp;
237
	}
238

    
239
	/**
240
	 * Returns the range model for this scrollbar.
241
	 * 
242
	 * @return the range model
243
	 */
244
	public RangeModel getRangeModel() {
245
		return rangeModel;
246
	}
247

    
248
	/**
249
	 * Returns the amount the scrollbar will move when the up or down arrow
250
	 * buttons are pressed.
251
	 * 
252
	 * @return the step increment
253
	 */
254
	public int getStepIncrement() {
255
		return stepIncrement;
256
	}
257

    
258
	/**
259
	 * Returns the figure used as the scrollbar's thumb.
260
	 * 
261
	 * @return the thumb figure
262
	 */
263
	protected IFigure getThumb() {
264
		return thumb;
265
	}
266

    
267
	/**
268
	 * Returns the current scroll position of the scrollbar.
269
	 * 
270
	 * @return the current value
271
	 * @see RangeModel#getValue()
272
	 */
273
	public int getValue() {
274
		return getRangeModel().getValue();
275
	}
276

    
277
	/**
278
	 * Returns the size of the range of allowable values.
279
	 * 
280
	 * @return the value range
281
	 */
282
	protected int getValueRange() {
283
		return getMaximum() - getExtent() - getMinimum();
284
	}
285

    
286
	/**
287
	 * Initilization of the ScrollBar. Sets the Scrollbar to have a
288
	 * ScrollBarLayout with vertical orientation. Creates the Figures that make
289
	 * up the components of the ScrollBar.
290
	 * 
291
	 * @since 2.0
292
	 */
293
	protected void initialize() {
294
		setLayoutManager(new ScrollBarLayout(transposer));
295
		setUpClickable(createDefaultUpButton());
296
		setDownClickable(createDefaultDownButton());
297
		setPageUp(createPageUp());
298
		setPageDown(createPageDown());
299
		setThumb(createDefaultThumb());
300
	}
301

    
302
	/**
303
	 * Returns <code>true</code> if this scrollbar is orientated horizontally,
304
	 * <code>false</code> otherwise.
305
	 * 
306
	 * @return whether this scrollbar is horizontal
307
	 */
308
	public boolean isHorizontal() {
309
		return isHorizontal;
310
	}
311

    
312
	private void pageDown() {
313
		setValue(getValue() + getPageIncrement());
314
	}
315

    
316
	private void pageUp() {
317
		setValue(getValue() - getPageIncrement());
318
	}
319

    
320
	/**
321
	 * @see PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
322
	 */
323
	public void propertyChange(PropertyChangeEvent event) {
324
		if (event.getSource() instanceof RangeModel) {
325
			setEnabled(getRangeModel().isEnabled());
326
			if (RangeModel.PROPERTY_VALUE.equals(event.getPropertyName())) {
327
				firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
328
						event.getNewValue());
329
				revalidate();
330
			}
331
			if (RangeModel.PROPERTY_MINIMUM.equals(event.getPropertyName())) {
332
				firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
333
						event.getNewValue());
334
				revalidate();
335
			}
336
			if (RangeModel.PROPERTY_MAXIMUM.equals(event.getPropertyName())) {
337
				firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
338
						event.getNewValue());
339
				revalidate();
340
			}
341
			if (RangeModel.PROPERTY_EXTENT.equals(event.getPropertyName())) {
342
				firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
343
						event.getNewValue());
344
				revalidate();
345
			}
346
		}
347
	}
348

    
349
	/**
350
	 * @see IFigure#revalidate()
351
	 */
352
	public void revalidate() {
353
		// Override default revalidate to prevent going up the parent chain.
354
		// Reason for this
355
		// is that preferred size never changes unless orientation changes.
356
		invalidate();
357
		getUpdateManager().addInvalidFigure(this);
358
	}
359

    
360
	/**
361
	 * Does nothing because this doesn't make sense for a scrollbar.
362
	 * 
363
	 * @see Orientable#setDirection(int)
364
	 */
365
	public void setDirection(int direction) {
366
		// Doesn't make sense for Scrollbar.
367
	}
368

    
369
	/**
370
	 * Sets the Clickable that represents the down arrow of the Scrollbar to
371
	 * <i>down</i>.
372
	 * 
373
	 * @param down
374
	 *            the down button
375
	 * @since 2.0
376
	 */
377
	public void setDownClickable(Clickable down) {
378
		if (buttonDown != null) {
379
			remove(buttonDown);
380
		}
381
		buttonDown = down;
382
		if (buttonDown != null) {
383
			if (buttonDown instanceof Orientable)
384
				((Orientable) buttonDown)
385
						.setDirection(isHorizontal() ? Orientable.EAST
386
								: Orientable.SOUTH);
387
			buttonDown.setFiringMethod(Clickable.REPEAT_FIRING);
388
			buttonDown.addActionListener(new ActionListener() {
389
				public void actionPerformed(ActionEvent e) {
390
					stepDown();
391
				}
392
			});
393
			add(buttonDown, ScrollBarLayout.DOWN_ARROW);
394
		}
395
	}
396

    
397
	/**
398
	 * Sets the Clickable that represents the up arrow of the Scrollbar to
399
	 * <i>up</i>.
400
	 * 
401
	 * @param up
402
	 *            the up button
403
	 * @since 2.0
404
	 */
405
	public void setUpClickable(Clickable up) {
406
		if (buttonUp != null) {
407
			remove(buttonUp);
408
		}
409
		buttonUp = up;
410
		if (up != null) {
411
			if (up instanceof Orientable)
412
				((Orientable) up).setDirection(isHorizontal() ? Orientable.WEST
413
						: Orientable.NORTH);
414
			buttonUp.setFiringMethod(Clickable.REPEAT_FIRING);
415
			buttonUp.addActionListener(new ActionListener() {
416
				public void actionPerformed(ActionEvent e) {
417
					stepUp();
418
				}
419
			});
420
			add(buttonUp, ScrollBarLayout.UP_ARROW);
421
		}
422
	}
423

    
424
	/**
425
	 * @see IFigure#setEnabled(boolean)
426
	 */
427
	public void setEnabled(boolean value) {
428
		if (isEnabled() == value)
429
			return;
430
		super.setEnabled(value);
431
		setChildrenEnabled(value);
432
		if (getThumb() != null) {
433
			getThumb().setVisible(value);
434
			revalidate();
435
		}
436
	}
437

    
438
	/**
439
	 * Sets the extent of the Scrollbar to <i>ext</i>
440
	 * 
441
	 * @param ext
442
	 *            the extent
443
	 * @since 2.0
444
	 */
445
	public void setExtent(int ext) {
446
		if (getExtent() == ext)
447
			return;
448
		getRangeModel().setExtent(ext);
449
	}
450

    
451
	/**
452
	 * Sets the orientation of the ScrollBar. If <code>true</code>, the
453
	 * Scrollbar will have a horizontal orientation. If <code>false</code>, the
454
	 * scrollBar will have a vertical orientation.
455
	 * 
456
	 * @param value
457
	 *            <code>true</code> if the scrollbar should be horizontal
458
	 * @since 2.0
459
	 */
460
	public final void setHorizontal(boolean value) {
461
		setOrientation(value ? HORIZONTAL : VERTICAL);
462
	}
463

    
464
	/**
465
	 * Sets the maximum position to <i>max</i>.
466
	 * 
467
	 * @param max
468
	 *            the maximum position
469
	 * @since 2.0
470
	 */
471
	public void setMaximum(int max) {
472
		if (getMaximum() == max)
473
			return;
474
		getRangeModel().setMaximum(max);
475
	}
476

    
477
	/**
478
	 * Sets the minimum position to <i>min</i>.
479
	 * 
480
	 * @param min
481
	 *            the minumum position
482
	 * @since 2.0
483
	 */
484
	public void setMinimum(int min) {
485
		if (getMinimum() == min)
486
			return;
487
		getRangeModel().setMinimum(min);
488
	}
489

    
490
	/**
491
	 * @see Orientable#setOrientation(int)
492
	 */
493
	public void setOrientation(int value) {
494
		if ((value == HORIZONTAL) == isHorizontal())
495
			return;
496
		isHorizontal = value == HORIZONTAL;
497
		transposer.setEnabled(isHorizontal);
498

    
499
		setChildrenOrientation(value);
500
		super.revalidate();
501
	}
502

    
503
	/**
504
	 * Sets the ScrollBar to scroll <i>increment</i> pixels when its pageup or
505
	 * pagedown buttons are pressed. (Note that the pageup and pagedown buttons
506
	 * are <b>NOT</b> the arrow buttons, they are the figures between the arrow
507
	 * buttons and the ScrollBar's thumb figure).
508
	 * 
509
	 * @param increment
510
	 *            the new page increment
511
	 * @since 2.0
512
	 */
513
	public void setPageIncrement(int increment) {
514
		pageIncrement = increment;
515
	}
516

    
517
	/**
518
	 * Sets the pagedown button to the passed Clickable. The pagedown button is
519
	 * the figure between the down arrow button and the ScrollBar's thumb
520
	 * figure.
521
	 * 
522
	 * @param down
523
	 *            the page down figure
524
	 * @since 2.0
525
	 */
526
	public void setPageDown(Clickable down) {
527
		if (pageDown != null)
528
			remove(pageDown);
529
		pageDown = down;
530
		if (pageDown != null) {
531
			pageDown.setFiringMethod(Clickable.REPEAT_FIRING);
532
			pageDown.addActionListener(new ActionListener() {
533
				public void actionPerformed(ActionEvent event) {
534
					pageDown();
535
				}
536
			});
537
			add(down, ScrollBarLayout.PAGE_DOWN);
538
		}
539
	}
540

    
541
	/**
542
	 * Sets the pageup button to the passed Clickable. The pageup button is the
543
	 * rectangular figure between the down arrow button and the ScrollBar's
544
	 * thumb figure.
545
	 * 
546
	 * @param up
547
	 *            the page up figure
548
	 * @since 2.0
549
	 */
550
	public void setPageUp(Clickable up) {
551
		if (pageUp != null)
552
			remove(pageUp);
553
		pageUp = up;
554
		if (pageUp != null) {
555
			pageUp.setFiringMethod(Clickable.REPEAT_FIRING);
556
			pageUp.addActionListener(new ActionListener() {
557
				public void actionPerformed(ActionEvent event) {
558
					pageUp();
559
				}
560
			});
561
			add(pageUp, ScrollBarLayout.PAGE_UP);
562
		}
563
	}
564

    
565
	/**
566
	 * Sets the ScrollBar's RangeModel to the passed value.
567
	 * 
568
	 * @param rangeModel
569
	 *            the new range model
570
	 * @since 2.0
571
	 */
572
	public void setRangeModel(RangeModel rangeModel) {
573
		if (this.rangeModel != null)
574
			this.rangeModel.removePropertyChangeListener(this);
575
		this.rangeModel = rangeModel;
576
		rangeModel.addPropertyChangeListener(this);
577
	}
578

    
579
	/**
580
	 * Sets the ScrollBar's step increment to the passed value. The step
581
	 * increment indicates how many pixels the ScrollBar will scroll when its up
582
	 * or down arrow button is pressed.
583
	 * 
584
	 * @param increment
585
	 *            the new step increment
586
	 * @since 2.0
587
	 */
588
	public void setStepIncrement(int increment) {
589
		stepIncrement = increment;
590
	}
591

    
592
	/**
593
	 * Sets the ScrollBar's thumb to the passed Figure. The thumb is the
594
	 * draggable component of the ScrollBar that indicates the ScrollBar's
595
	 * position.
596
	 * 
597
	 * @param figure
598
	 *            the thumb figure
599
	 * @since 2.0
600
	 */
601
	public void setThumb(IFigure figure) {
602
		if (thumb != null) {
603
			thumb.removeMouseListener(thumbDragger);
604
			thumb.removeMouseMotionListener(thumbDragger);
605
			remove(thumb);
606
		}
607
		thumb = figure;
608
		if (thumb != null) {
609
			thumb.addMouseListener(thumbDragger);
610
			thumb.addMouseMotionListener(thumbDragger);
611
			add(thumb, ScrollBarLayout.THUMB);
612
		}
613
	}
614

    
615
	/**
616
	 * Sets the value of the Scrollbar to <i>v</i>
617
	 * 
618
	 * @param v
619
	 *            the new value
620
	 * @since 2.0
621
	 */
622
	public void setValue(int v) {
623
		getRangeModel().setValue(v);
624
	}
625

    
626
	/**
627
	 * Causes the ScrollBar to scroll down (or right) by the value of its step
628
	 * increment.
629
	 * 
630
	 * @since 2.0
631
	 */
632
	protected void stepDown() {
633
		setValue(getValue() + getStepIncrement());
634
	}
635

    
636
	/**
637
	 * Causes the ScrollBar to scroll up (or left) by the value of its step
638
	 * increment.
639
	 * 
640
	 * @since 2.0
641
	 */
642
	protected void stepUp() {
643
		setValue(getValue() - getStepIncrement());
644
	}
645

    
646
	/**
647
	 * @since 3.6
648
	 */
649
	protected class ThumbDragger extends MouseMotionListener.Stub implements
650
			MouseListener {
651
		protected Point start;
652
		protected int dragRange;
653
		protected int revertValue;
654
		protected boolean armed;
655

    
656
		public ThumbDragger() {
657
		}
658

    
659
		public void mousePressed(MouseEvent me) {
660
			armed = true;
661
			start = me.getLocation();
662
			Rectangle area = new Rectangle(transposer.t(getClientArea()));
663
			Dimension thumbSize = transposer.t(getThumb().getSize());
664
			if (getButtonUp() != null)
665
				area.height -= transposer.t(getButtonUp().getSize()).height;
666
			if (getButtonDown() != null)
667
				area.height -= transposer.t(getButtonDown().getSize()).height;
668
			Dimension sizeDifference = new Dimension(area.width, area.height
669
					- thumbSize.height);
670
			dragRange = sizeDifference.height;
671
			revertValue = getValue();
672
			me.consume();
673
		}
674

    
675
		public void mouseDragged(MouseEvent me) {
676
			if (!armed)
677
				return;
678
			Dimension difference = transposer.t(me.getLocation().getDifference(
679
					start));
680
			int change = getValueRange() * difference.height / dragRange;
681
			setValue(revertValue + change);
682
			me.consume();
683
		}
684

    
685
		public void mouseReleased(MouseEvent me) {
686
			if (!armed)
687
				return;
688
			armed = false;
689
			me.consume();
690
		}
691

    
692
		public void mouseDoubleClicked(MouseEvent me) {
693
		}
694
	}
695

    
696
}
(142-142/171)