1 package be
.nikiroo
.utils
.ui
;
3 import java
.awt
.event
.ActionEvent
;
4 import java
.awt
.event
.ActionListener
;
6 import javax
.swing
.BoxLayout
;
7 import javax
.swing
.DefaultComboBoxModel
;
8 import javax
.swing
.Icon
;
9 import javax
.swing
.JButton
;
10 import javax
.swing
.JComboBox
;
11 import javax
.swing
.JLabel
;
14 * A small panel that let you choose a zoom level or an actual zoom value (when
15 * there is enough space to allow that).
19 public class ZoomBox
extends ListenerPanel
{
20 private static final long serialVersionUID
= 1L;
22 /** The event that is fired on zoom change. */
23 public static final String ZOOM_CHANGED
= "zoom_changed";
25 private enum ZoomLevel
{
26 FIT_TO_WIDTH(0, true), //
27 FIT_TO_HEIGHT(0, false), //
28 ACTUAL_SIZE(1, null), //
29 HALF_SIZE(0.5, null), //
30 DOUBLE_SIZE(2, null),//
33 private final double zoom
;
34 private final Boolean snapMode
;
36 private ZoomLevel(double zoom
, Boolean snapMode
) {
38 this.snapMode
= snapMode
;
41 public double getZoom() {
45 public Boolean
getSnapToWidth() {
50 * Use default values that can be understood by a human.
53 public String
toString() {
56 return "Fit to width";
58 return "Fit to height";
66 return super.toString();
69 static ZoomLevel
[] values(boolean orderedSelection
) {
70 if (orderedSelection
) {
71 return new ZoomLevel
[] { //
84 private boolean vertical
;
85 private boolean small
;
87 private JButton zoomIn
;
88 private JButton zoomOut
;
89 private JButton snapWidth
;
90 private JButton snapHeight
;
91 private JLabel zoomLabel
;
93 @SuppressWarnings("rawtypes") // JComboBox<?> is not java 1.6 compatible
94 private JComboBox zoombox
;
96 private double zoom
= 1;
97 private Boolean snapMode
= true;
99 @SuppressWarnings("rawtypes") // JComboBox<?> not compatible java 1.6
100 private DefaultComboBoxModel zoomBoxModel
;
103 * Create a new {@link ZoomBox}.
105 @SuppressWarnings({ "unchecked", "rawtypes" }) // JComboBox<?> not
106 // compatible java 1.6
108 zoomIn
= new JButton();
109 zoomIn
.addActionListener(new ActionListener() {
111 public void actionPerformed(ActionEvent e
) {
116 zoomBoxModel
= new DefaultComboBoxModel(ZoomLevel
.values(true));
117 zoombox
= new JComboBox(zoomBoxModel
);
118 zoombox
.setEditable(true);
119 zoombox
.addActionListener(new ActionListener() {
121 public void actionPerformed(ActionEvent e
) {
122 Object selected
= zoomBoxModel
.getSelectedItem();
124 if (selected
== null) {
128 if (selected
instanceof ZoomLevel
) {
129 ZoomLevel selectedZoomLevel
= (ZoomLevel
) selected
;
130 setZoomSnapMode(selectedZoomLevel
.getZoom(),
131 selectedZoomLevel
.getSnapToWidth());
133 String selectedString
= selected
.toString();
134 selectedString
= selectedString
.trim();
135 if (selectedString
.endsWith("%")) {
136 selectedString
= selectedString
137 .substring(0, selectedString
.length() - 1)
142 int pc
= Integer
.parseInt(selectedString
);
144 throw new NumberFormatException("invalid");
147 setZoomSnapMode(pc
/ 100.0, null);
148 } catch (NumberFormatException nfe
) {
152 fireActionPerformed(ZOOM_CHANGED
);
156 zoomOut
= new JButton();
157 zoomOut
.addActionListener(new ActionListener() {
159 public void actionPerformed(ActionEvent e
) {
164 snapWidth
= new JButton();
165 snapWidth
.addActionListener(new ActionListener() {
167 public void actionPerformed(ActionEvent e
) {
172 snapHeight
= new JButton();
173 snapHeight
.addActionListener(new ActionListener() {
175 public void actionPerformed(ActionEvent e
) {
180 zoomLabel
= new JLabel();
182 setIcons(null, null, null, null);
183 setOrientation(vertical
);
189 * It usually returns 1 (default value), the value you passed yourself or 1
190 * (a snap to width or snap to height was asked by the user).
192 * Will cause a fire event if needed.
197 public void setZoom(double zoom
) {
198 if (this.zoom
!= zoom
) {
200 fireActionPerformed(ZOOM_CHANGED
);
205 * The snap mode (NULL means no snap mode, TRUE for snap to width, FALSE for
208 * Will cause a fire event if needed.
213 public void setSnapMode(Boolean snapToWidth
) {
214 if (this.snapMode
!= snapToWidth
) {
215 doSetSnapMode(snapToWidth
);
216 fireActionPerformed(ZOOM_CHANGED
);
221 * Set both {@link ZoomBox#setZoom(double)} and
222 * {@link ZoomBox#setSnapMode(Boolean)} but fire only one change event.
224 * Will cause a fire event if needed.
231 public void setZoomSnapMode(double zoom
, Boolean snapMode
) {
232 if (this.zoom
!= zoom
|| this.snapMode
!= snapMode
) {
234 doSetSnapMode(snapMode
);
235 fireActionPerformed(ZOOM_CHANGED
);
242 * It usually returns 1 (default value), the value you passed yourself or 0
243 * (a snap to width or snap to height was asked by the user).
245 * @return the zoom level
247 public double getZoom() {
252 * The snap mode (NULL means no snap mode, TRUE for snap to width, FALSE for
255 * @return the snap mode
257 public Boolean
getSnapMode() {
262 * Zoom in, by a certain amount in "steps".
264 * Note that zoomIn(-1) is the same as zoomOut(1).
267 * the number of zoom steps to make, can be negative
269 public void zoomIn(int steps
) {
270 // TODO: redo zoomIn/zoomOut correctly
276 double newZoom
= zoom
;
277 for (int i
= 0; i
< steps
; i
++) {
278 newZoom
= newZoom
+ (newZoom
< 0.1 ?
0.01 : 0.1);
280 newZoom
= Math
.round(newZoom
* 10.0) / 10.0; // snap to 10%
282 newZoom
= Math
.round(newZoom
* 100.0) / 100.0; // snap to 1%
286 setZoomSnapMode(newZoom
, null);
287 fireActionPerformed(ZOOM_CHANGED
);
291 * Zoom out, by a certain amount in "steps".
293 * Note that zoomOut(-1) is the same as zoomIn(1).
296 * the number of zoom steps to make, can be negative
298 public void zoomOut(int steps
) {
304 double newZoom
= zoom
;
305 for (int i
= 0; i
< steps
; i
++) {
306 newZoom
= newZoom
- (newZoom
> 0.19 ?
0.1 : 0.01);
307 if (newZoom
< 0.01) {
313 newZoom
= Math
.round(newZoom
* 10.0) / 10.0; // snap to 10%
315 newZoom
= Math
.round(newZoom
* 100.0) / 100.0; // snap to 1%
319 setZoomSnapMode(newZoom
, null);
320 fireActionPerformed(ZOOM_CHANGED
);
324 * Set icons for the buttons instead of square brackets.
326 * Any NULL value will make the button use square brackets again.
329 * the icon of the button "go to first page"
331 * the icon of the button "go to previous page"
333 * the icon of the button "go to next page"
335 * the icon of the button "go to last page"
337 public void setIcons(Icon zoomIn
, Icon zoomOut
, Icon snapWidth
,
339 this.zoomIn
.setIcon(zoomIn
);
340 this.zoomIn
.setText(zoomIn
== null ?
"+" : "");
341 this.zoomOut
.setIcon(zoomOut
);
342 this.zoomOut
.setText(zoomOut
== null ?
"-" : "");
343 this.snapWidth
.setIcon(snapWidth
);
344 this.snapWidth
.setText(snapWidth
== null ?
"W" : "");
345 this.snapHeight
.setIcon(snapHeight
);
346 this.snapHeight
.setText(snapHeight
== null ?
"H" : "");
350 * A smaller {@link ZoomBox} that uses buttons instead of a big combo box
351 * for the zoom modes.
353 * Always small in vertical orientation.
355 * @return TRUE if it is small
357 public boolean getSmall() {
362 * A smaller {@link ZoomBox} that uses buttons instead of a big combo box
363 * for the zoom modes.
365 * Always small in vertical orientation.
368 * TRUE to set it small
370 * @return TRUE if it changed something
372 public boolean setSmall(boolean small
) {
373 return setUi(small
, vertical
);
377 * The general orientation of the component.
379 * @return TRUE for vertical orientation, FALSE for horisontal orientation
381 public boolean getOrientation() {
386 * The general orientation of the component.
389 * TRUE for vertical orientation, FALSE for horisontal
392 * @return TRUE if it changed something
394 public boolean setOrientation(boolean vertical
) {
395 return setUi(small
, vertical
);
399 * Set the zoom level, no fire event.
401 * It usually returns 1 (default value), the value you passed yourself or 0
402 * (a snap to width or snap to height was asked by the user).
407 private void doSetZoom(double zoom
) {
409 String zoomStr
= Integer
.toString((int) Math
.round(zoom
* 100))
411 zoomLabel
.setText(zoomStr
);
412 if (snapMode
== null) {
413 zoomBoxModel
.setSelectedItem(zoomStr
);
421 * Set the snap mode, no fire event.
426 private void doSetSnapMode(Boolean snapToWidth
) {
427 if (snapToWidth
== null) {
428 String zoomStr
= Integer
.toString((int) Math
.round(zoom
* 100))
431 zoomBoxModel
.setSelectedItem(zoomStr
);
434 for (ZoomLevel level
: ZoomLevel
.values()) {
435 if (level
.getSnapToWidth() == snapToWidth
) {
436 zoomBoxModel
.setSelectedItem(level
);
441 this.snapMode
= snapToWidth
;
444 private boolean setUi(boolean small
, boolean vertical
) {
445 if (getWidth() == 0 || this.small
!= small
446 || this.vertical
!= vertical
) {
448 this.vertical
= vertical
;
450 BoxLayout layout
= new BoxLayout(this,
451 vertical ? BoxLayout
.Y_AXIS
: BoxLayout
.X_AXIS
);
455 if (vertical
|| small
) {
458 this.add(snapHeight
);