BoundedZoomAction.java revision 1472:c18cbe5936b8
1/*
2 * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24package com.sun.hotspot.igv.util;
25
26import java.awt.Container;
27import java.awt.Dimension;
28import java.awt.Point;
29import java.awt.Rectangle;
30import javax.swing.JComponent;
31import javax.swing.JScrollPane;
32import org.netbeans.api.visual.action.WidgetAction;
33import org.netbeans.api.visual.action.WidgetAction.State;
34import org.netbeans.api.visual.action.WidgetAction.WidgetMouseWheelEvent;
35import org.netbeans.api.visual.animator.SceneAnimator;
36import org.netbeans.api.visual.widget.Scene;
37import org.netbeans.api.visual.widget.Widget;
38
39/**
40 *
41 * @author Thomas Wuerthinger
42 */
43public class BoundedZoomAction extends WidgetAction.Adapter {
44
45    private double minFactor = 0.0;
46    private double maxFactor = Double.MAX_VALUE;
47    private double zoomMultiplier;
48    private boolean useAnimator;
49
50    public BoundedZoomAction(double zoomMultiplier, boolean useAnimator) {
51        this.zoomMultiplier = zoomMultiplier;
52        this.useAnimator = useAnimator;
53    }
54
55    public double getMinFactor() {
56        return minFactor;
57    }
58
59    public void setMinFactor(double d) {
60        minFactor = d;
61    }
62
63    public double getMaxFactor() {
64        return maxFactor;
65    }
66
67    public void setMaxFactor(double d) {
68        maxFactor = d;
69    }
70
71    private JScrollPane findScrollPane(JComponent component) {
72        for (;;) {
73            if (component == null) {
74                return null;
75            }
76            if (component instanceof JScrollPane) {
77                return ((JScrollPane) component);
78            }
79            Container parent = component.getParent();
80            if (!(parent instanceof JComponent)) {
81                return null;
82            }
83            component = (JComponent) parent;
84        }
85    }
86
87    @Override
88    public State mouseWheelMoved(Widget widget, WidgetMouseWheelEvent event) {
89        final Scene scene = widget.getScene();
90        int amount = event.getWheelRotation();
91        JScrollPane scrollPane = findScrollPane(scene.getView());
92        Point viewPosition = null;
93        Point mouseLocation = scene.convertSceneToView(event.getPoint());
94        int xOffset = 0;
95        int yOffset = 0;
96        Point oldViewPosition = null;
97        Rectangle bounds = new Rectangle(scene.getBounds());
98        Dimension componentSize = new Dimension(scene.getView().getPreferredSize());
99
100        if (scrollPane != null) {
101            viewPosition = new Point(scrollPane.getViewport().getViewPosition());
102            oldViewPosition = new Point(viewPosition);
103            xOffset = (mouseLocation.x - viewPosition.x);
104            yOffset = (mouseLocation.y - viewPosition.y);
105            viewPosition.x += xOffset;
106            viewPosition.y += yOffset;
107        }
108
109        if (useAnimator) {
110            SceneAnimator sceneAnimator = scene.getSceneAnimator();
111            synchronized (sceneAnimator) {
112                double zoom = sceneAnimator.isAnimatingZoomFactor() ? sceneAnimator.getTargetZoomFactor() : scene.getZoomFactor();
113                while (amount > 0 && zoom / zoomMultiplier >= minFactor && zoom / zoomMultiplier <= maxFactor) {
114                    zoom /= zoomMultiplier;
115                    if (viewPosition != null) {
116                        viewPosition.x /= zoomMultiplier;
117                        viewPosition.y /= zoomMultiplier;
118                        bounds.width /= zoomMultiplier;
119                        bounds.height /= zoomMultiplier;
120                        componentSize.width /= zoomMultiplier;
121                        componentSize.height /= zoomMultiplier;
122                    }
123                    amount--;
124                }
125                while (amount < 0 && zoom * zoomMultiplier >= minFactor && zoom * zoomMultiplier <= maxFactor) {
126                    zoom *= zoomMultiplier;
127                    if (viewPosition != null) {
128                        viewPosition.x *= zoomMultiplier;
129                        viewPosition.y *= zoomMultiplier;
130                        bounds.width *= zoomMultiplier;
131                        bounds.height *= zoomMultiplier;
132                        componentSize.width *= zoomMultiplier;
133                        componentSize.height *= zoomMultiplier;
134                    }
135                    amount++;
136                }
137                sceneAnimator.animateZoomFactor(zoom);
138            }
139        } else {
140            double zoom = scene.getZoomFactor();
141            while (amount > 0 && zoom / zoomMultiplier >= minFactor && zoom / zoomMultiplier <= maxFactor) {
142                zoom /= zoomMultiplier;
143                if (viewPosition != null) {
144                    viewPosition.x /= zoomMultiplier;
145                    viewPosition.y /= zoomMultiplier;
146                    bounds.width /= zoomMultiplier;
147                    bounds.height /= zoomMultiplier;
148                    componentSize.width /= zoomMultiplier;
149                    componentSize.height /= zoomMultiplier;
150                }
151                amount--;
152            }
153            while (amount < 0 && zoom * zoomMultiplier >= minFactor && zoom * zoomMultiplier <= maxFactor) {
154                zoom *= zoomMultiplier;
155                if (viewPosition != null) {
156                    viewPosition.x *= zoomMultiplier;
157                    viewPosition.y *= zoomMultiplier;
158                    bounds.width *= zoomMultiplier;
159                    bounds.height *= zoomMultiplier;
160                    componentSize.width *= zoomMultiplier;
161                    componentSize.height *= zoomMultiplier;
162                }
163                amount++;
164            }
165            scene.setZoomFactor(zoom);
166        }
167
168        if (scrollPane != null) {
169            scene.validate(); // Call validate to update size of scene
170            Dimension size = scrollPane.getViewport().getExtentSize();
171            viewPosition.x -= xOffset;
172            viewPosition.y -= yOffset;
173            scene.resolveBounds(scene.getLocation(), bounds);
174            scene.getView().setPreferredSize(componentSize);
175            scene.getView().revalidate();
176            scene.getView().addNotify();
177            scrollPane.getViewport().setViewPosition(viewPosition);
178        }
179
180        return WidgetAction.State.CONSUMED;
181    }
182}
183