1 package be
.nikiroo
.utils
.ui
;
3 import java
.awt
.event
.ActionEvent
;
4 import java
.awt
.event
.ActionListener
;
6 import javax
.swing
.BorderFactory
;
7 import javax
.swing
.BoxLayout
;
8 import javax
.swing
.DefaultComboBoxModel
;
9 import javax
.swing
.Icon
;
10 import javax
.swing
.JButton
;
11 import javax
.swing
.JComboBox
;
12 import javax
.swing
.JLabel
;
15 * A small panel that let you choose a zoom level or an actual zoom value (when
16 * there is enough space to allow that).
20 public class ZoomBox
extends ListenerPanel
{
21 private static final long serialVersionUID
= 1L;
23 /** The event that is fired on zoom change. */
24 public static final String ZOOM_CHANGED
= "zoom_changed";
26 private enum ZoomLevel
{
27 FIT_TO_WIDTH(0, true), //
28 FIT_TO_HEIGHT(0, false), //
29 ACTUAL_SIZE(1, null), //
30 HALF_SIZE(0.5, null), //
31 DOUBLE_SIZE(2, null),//
34 private final double zoom
;
35 private final Boolean snapMode
;
37 private ZoomLevel(double zoom
, Boolean snapMode
) {
39 this.snapMode
= snapMode
;
42 public double getZoom() {
46 public Boolean
getSnapToWidth() {
51 * Use default values that can be understood by a human.
54 public String
toString() {
57 return "Fit to width";
59 return "Fit to height";
67 return super.toString();
70 static ZoomLevel
[] values(boolean orderedSelection
) {
71 if (orderedSelection
) {
72 return new ZoomLevel
[] { //
85 private boolean vertical
;
86 private boolean small
;
88 private JButton zoomIn
;
89 private JButton zoomOut
;
90 private JButton snapWidth
;
91 private JButton snapHeight
;
92 private JLabel zoomLabel
;
94 @SuppressWarnings("rawtypes") // JComboBox<?> is not java 1.6 compatible
95 private JComboBox zoombox
;
97 private double zoom
= 1;
98 private Boolean snapMode
= true;
100 @SuppressWarnings("rawtypes") // JComboBox<?> not compatible java 1.6
101 private DefaultComboBoxModel zoomBoxModel
;
104 * Create a new {@link ZoomBox}.
106 @SuppressWarnings({ "unchecked", "rawtypes" }) // JComboBox<?> not
107 // compatible java 1.6
109 zoomIn
= new JButton();
110 zoomIn
.addActionListener(new ActionListener() {
112 public void actionPerformed(ActionEvent e
) {
117 zoomBoxModel
= new DefaultComboBoxModel(ZoomLevel
.values(true));
118 zoombox
= new JComboBox(zoomBoxModel
);
119 zoombox
.setEditable(true);
120 zoombox
.addActionListener(new ActionListener() {
122 public void actionPerformed(ActionEvent e
) {
123 Object selected
= zoomBoxModel
.getSelectedItem();
125 if (selected
== null) {
129 if (selected
instanceof ZoomLevel
) {
130 ZoomLevel selectedZoomLevel
= (ZoomLevel
) selected
;
131 setZoomSnapMode(selectedZoomLevel
.getZoom(),
132 selectedZoomLevel
.getSnapToWidth());
134 String selectedString
= selected
.toString();
135 selectedString
= selectedString
.trim();
136 if (selectedString
.endsWith("%")) {
137 selectedString
= selectedString
138 .substring(0, selectedString
.length() - 1)
143 int pc
= Integer
.parseInt(selectedString
);
145 throw new NumberFormatException("invalid");
148 setZoomSnapMode(pc
/ 100.0, null);
149 } catch (NumberFormatException nfe
) {
153 fireActionPerformed(ZOOM_CHANGED
);
157 zoomOut
= new JButton();
158 zoomOut
.addActionListener(new ActionListener() {
160 public void actionPerformed(ActionEvent e
) {
165 snapWidth
= new JButton();
166 snapWidth
.addActionListener(new ActionListener() {
168 public void actionPerformed(ActionEvent e
) {
173 snapHeight
= new JButton();
174 snapHeight
.addActionListener(new ActionListener() {
176 public void actionPerformed(ActionEvent e
) {
181 zoomLabel
= new JLabel();
182 zoomLabel
.setBorder(BorderFactory
.createEmptyBorder(10, 10, 0, 0));
184 setIcons(null, null, null, null);
185 setOrientation(vertical
);
191 * It usually returns 1 (default value), the value you passed yourself or 1
192 * (a snap to width or snap to height was asked by the user).
194 * Will cause a fire event if needed.
199 public void setZoom(double zoom
) {
200 if (this.zoom
!= zoom
) {
202 fireActionPerformed(ZOOM_CHANGED
);
207 * The snap mode (NULL means no snap mode, TRUE for snap to width, FALSE for
210 * Will cause a fire event if needed.
215 public void setSnapMode(Boolean snapToWidth
) {
216 if (this.snapMode
!= snapToWidth
) {
217 doSetSnapMode(snapToWidth
);
218 fireActionPerformed(ZOOM_CHANGED
);
223 * Set both {@link ZoomBox#setZoom(double)} and
224 * {@link ZoomBox#setSnapMode(Boolean)} but fire only one change event.
226 * Will cause a fire event if needed.
233 public void setZoomSnapMode(double zoom
, Boolean snapMode
) {
234 if (this.zoom
!= zoom
|| this.snapMode
!= snapMode
) {
236 doSetSnapMode(snapMode
);
237 fireActionPerformed(ZOOM_CHANGED
);
244 * It usually returns 1 (default value), the value you passed yourself or 0
245 * (a snap to width or snap to height was asked by the user).
247 * @return the zoom level
249 public double getZoom() {
254 * The snap mode (NULL means no snap mode, TRUE for snap to width, FALSE for
257 * @return the snap mode
259 public Boolean
getSnapMode() {
264 * Zoom in, by a certain amount in "steps".
266 * Note that zoomIn(-1) is the same as zoomOut(1).
269 * the number of zoom steps to make, can be negative
271 public void zoomIn(int steps
) {
272 // TODO: redo zoomIn/zoomOut correctly
278 double newZoom
= zoom
;
279 for (int i
= 0; i
< steps
; i
++) {
280 newZoom
= newZoom
+ (newZoom
< 0.1 ?
0.01 : 0.1);
282 newZoom
= Math
.round(newZoom
* 10.0) / 10.0; // snap to 10%
284 newZoom
= Math
.round(newZoom
* 100.0) / 100.0; // snap to 1%
288 setZoomSnapMode(newZoom
, null);
289 fireActionPerformed(ZOOM_CHANGED
);
293 * Zoom out, by a certain amount in "steps".
295 * Note that zoomOut(-1) is the same as zoomIn(1).
298 * the number of zoom steps to make, can be negative
300 public void zoomOut(int steps
) {
306 double newZoom
= zoom
;
307 for (int i
= 0; i
< steps
; i
++) {
308 newZoom
= newZoom
- (newZoom
> 0.19 ?
0.1 : 0.01);
309 if (newZoom
< 0.01) {
315 newZoom
= Math
.round(newZoom
* 10.0) / 10.0; // snap to 10%
317 newZoom
= Math
.round(newZoom
* 100.0) / 100.0; // snap to 1%
321 setZoomSnapMode(newZoom
, null);
322 fireActionPerformed(ZOOM_CHANGED
);
326 * Set icons for the buttons instead of square brackets.
328 * Any NULL value will make the button use square brackets again.
331 * the icon of the button "go to first page"
333 * the icon of the button "go to previous page"
335 * the icon of the button "go to next page"
337 * the icon of the button "go to last page"
339 public void setIcons(Icon zoomIn
, Icon zoomOut
, Icon snapWidth
,
341 this.zoomIn
.setIcon(zoomIn
);
342 this.zoomIn
.setText(zoomIn
== null ?
"+" : "");
343 this.zoomOut
.setIcon(zoomOut
);
344 this.zoomOut
.setText(zoomOut
== null ?
"-" : "");
345 this.snapWidth
.setIcon(snapWidth
);
346 this.snapWidth
.setText(snapWidth
== null ?
"W" : "");
347 this.snapHeight
.setIcon(snapHeight
);
348 this.snapHeight
.setText(snapHeight
== null ?
"H" : "");
352 * A smaller {@link ZoomBox} that uses buttons instead of a big combo box
353 * for the zoom modes.
355 * Always small in vertical orientation.
357 * @return TRUE if it is small
359 public boolean getSmall() {
364 * A smaller {@link ZoomBox} that uses buttons instead of a big combo box
365 * for the zoom modes.
367 * Always small in vertical orientation.
370 * TRUE to set it small
372 * @return TRUE if it changed something
374 public boolean setSmall(boolean small
) {
375 return setUi(small
, vertical
);
379 * The general orientation of the component.
381 * @return TRUE for vertical orientation, FALSE for horisontal orientation
383 public boolean getOrientation() {
388 * The general orientation of the component.
391 * TRUE for vertical orientation, FALSE for horisontal
394 * @return TRUE if it changed something
396 public boolean setOrientation(boolean vertical
) {
397 return setUi(small
, vertical
);
401 * Set the zoom level, no fire event.
403 * It usually returns 1 (default value), the value you passed yourself or 0
404 * (a snap to width or snap to height was asked by the user).
409 private void doSetZoom(double zoom
) {
411 String zoomStr
= Integer
.toString((int) Math
.round(zoom
* 100))
413 zoomLabel
.setText(zoomStr
);
414 if (snapMode
== null) {
415 zoomBoxModel
.setSelectedItem(zoomStr
);
423 * Set the snap mode, no fire event.
428 private void doSetSnapMode(Boolean snapToWidth
) {
429 if (snapToWidth
== null) {
430 String zoomStr
= Integer
.toString((int) Math
.round(zoom
* 100))
433 zoomBoxModel
.setSelectedItem(zoomStr
);
436 for (ZoomLevel level
: ZoomLevel
.values()) {
437 if (level
.getSnapToWidth() == snapToWidth
) {
438 zoomBoxModel
.setSelectedItem(level
);
443 this.snapMode
= snapToWidth
;
446 private boolean setUi(boolean small
, boolean vertical
) {
447 if (getWidth() == 0 || this.small
!= small
448 || this.vertical
!= vertical
) {
450 this.vertical
= vertical
;
452 BoxLayout layout
= new BoxLayout(this,
453 vertical ? BoxLayout
.Y_AXIS
: BoxLayout
.X_AXIS
);
457 if (vertical
|| small
) {
460 this.add(snapHeight
);