|
1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License (the "License"). |
|
6 * You may not use this file except in compliance with the License. |
|
7 * |
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 * or http://www.opensolaris.org/os/licensing. |
|
10 * See the License for the specific language governing permissions |
|
11 * and limitations under the License. |
|
12 * |
|
13 * When distributing Covered Code, include this CDDL HEADER in each |
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 * If applicable, add the following below this CDDL HEADER, with the |
|
16 * fields enclosed by brackets "[]" replaced with your own identifying |
|
17 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 * |
|
19 * CDDL HEADER END |
|
20 */ |
|
21 |
|
22 /* |
|
23 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 package com.oracle.solaris.vp.panel.swing.timezone; |
|
27 |
|
28 import java.awt.*; |
|
29 import java.awt.event.*; |
|
30 import java.awt.geom.Point2D; |
|
31 import java.util.*; |
|
32 import javax.swing.*; |
|
33 import com.oracle.solaris.vp.util.swing.ScaledIcon; |
|
34 |
|
35 public class LocationPicker<T> extends JLabel |
|
36 implements MouseListener, MouseMotionListener |
|
37 { |
|
38 static final int LOC_OFFSET = 2; |
|
39 static final int LOC_SIZE = LOC_OFFSET * 2 + 1; |
|
40 |
|
41 /** |
|
42 * Maps a normalized 2D location (0..1, 0..1) to a pixel location |
|
43 * using the provided image dimensions. |
|
44 * |
|
45 * @param dim the dimension of the image to map into |
|
46 * @param point the normalized 2D location |
|
47 * @return the discrete pixel location within the image |
|
48 */ |
|
49 private static Point normToPixel(Dimension dim, Point2D point) |
|
50 { |
|
51 double width = dim.getWidth(); |
|
52 double height = dim.getHeight(); |
|
53 return new Point((int)(width * point.getX()), |
|
54 (int)(height * point.getY())); |
|
55 } |
|
56 |
|
57 private class LocationLabel extends JLabel |
|
58 { |
|
59 private final T object_; |
|
60 private final String label_; |
|
61 private final Point2D center_; |
|
62 private Point pixelCenter_; |
|
63 private boolean highlit_; |
|
64 private boolean selected_; |
|
65 |
|
66 LocationLabel(T object) |
|
67 { |
|
68 object_ = object; |
|
69 label_ = mapper_.getLabel(object); |
|
70 center_ = mapper_.map(object); |
|
71 |
|
72 setSize(LOC_SIZE, LOC_SIZE); |
|
73 } |
|
74 |
|
75 @Override |
|
76 public void paint(Graphics g) |
|
77 { |
|
78 Graphics2D g2 = (Graphics2D)g; |
|
79 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
|
80 RenderingHints.VALUE_ANTIALIAS_ON); |
|
81 |
|
82 g.setColor(Color.black); |
|
83 g.fillRect(1, 1, LOC_SIZE - 2, LOC_SIZE - 2); |
|
84 g.setColor(selected_ ? |
|
85 Color.yellow : highlit_ ? Color.cyan : Color.red.darker()); |
|
86 g.fillRect(0, 0, LOC_SIZE - 2, LOC_SIZE - 2); |
|
87 } |
|
88 |
|
89 Point2D getCenter() |
|
90 { |
|
91 return (center_); |
|
92 } |
|
93 |
|
94 Point getPixelCenter() |
|
95 { |
|
96 return (pixelCenter_); |
|
97 } |
|
98 |
|
99 void setPixelCenter(Point pixelCenter) |
|
100 { |
|
101 pixelCenter_ = pixelCenter; |
|
102 setLocation(pixelCenter.x - LOC_OFFSET, pixelCenter.y - LOC_OFFSET); |
|
103 } |
|
104 |
|
105 T getObject() |
|
106 { |
|
107 return (object_); |
|
108 } |
|
109 |
|
110 String getToolTip() |
|
111 { |
|
112 return (label_); |
|
113 } |
|
114 |
|
115 void setHighlit(boolean highlit) |
|
116 { |
|
117 highlit_ = highlit; |
|
118 repaint(getVisibleRect()); |
|
119 } |
|
120 |
|
121 void setSelected(boolean selected) |
|
122 { |
|
123 selected_ = selected; |
|
124 repaint(getVisibleRect()); |
|
125 } |
|
126 } |
|
127 |
|
128 private class LocationLayout implements LayoutManager |
|
129 { |
|
130 public void addLayoutComponent(String name, Component comp) |
|
131 { |
|
132 } |
|
133 |
|
134 public void removeLayoutComponent(Component comp) |
|
135 { |
|
136 } |
|
137 |
|
138 public Dimension preferredLayoutSize(Container parent) |
|
139 { |
|
140 return (new Dimension(0, 0)); |
|
141 } |
|
142 |
|
143 public Dimension minimumLayoutSize(Container parent) |
|
144 { |
|
145 return (new Dimension(0, 0)); |
|
146 } |
|
147 |
|
148 public void layoutContainer(Container parent) |
|
149 { |
|
150 int nComps = parent.getComponentCount(); |
|
151 |
|
152 Dimension size = parent.getSize(); |
|
153 for (int i = 0; i < nComps; i++) { |
|
154 Component c = parent.getComponent(i); |
|
155 if (!c.isVisible()) |
|
156 continue; |
|
157 LocationLabel label = (LocationLabel)c; |
|
158 label.setPixelCenter(normToPixel(size, label.getCenter())); |
|
159 } |
|
160 } |
|
161 } |
|
162 |
|
163 private LocationMapper<T> mapper_; |
|
164 private Map<T, LocationLabel> objects_ = new HashMap<T, LocationLabel>(); |
|
165 private LocationLabel current_; |
|
166 private LocationLabel selection_; |
|
167 |
|
168 private LocationSelectionListeners<T> selectionListeners_ = |
|
169 new LocationSelectionListeners<T>(); |
|
170 |
|
171 private LocationSelectionListeners<T> highlightListeners_ = |
|
172 new LocationSelectionListeners<T>(); |
|
173 |
|
174 private ScaledIcon icon_; |
|
175 |
|
176 // |
|
177 // Constructors |
|
178 // |
|
179 |
|
180 public LocationPicker(Icon background, LocationMapper<T> mapper) { |
|
181 |
|
182 icon_ = new ScaledIcon(background); |
|
183 setIcon(icon_); |
|
184 mapper_ = mapper; |
|
185 current_ = null; |
|
186 |
|
187 setLayout(new LocationLayout()); |
|
188 |
|
189 addMouseMotionListener(this); |
|
190 addMouseListener(this); |
|
191 } |
|
192 |
|
193 @Override |
|
194 public Dimension getPreferredSize() { |
|
195 if (isPreferredSizeSet()) { |
|
196 return super.getPreferredSize(); |
|
197 } |
|
198 |
|
199 Insets insets = getInsets(); |
|
200 Icon icon = icon_.getIcon(); |
|
201 int width = icon.getIconWidth() + insets.left + insets.right; |
|
202 int height = icon.getIconHeight() + insets.top + insets.bottom; |
|
203 |
|
204 return new Dimension(width, height); |
|
205 } |
|
206 |
|
207 @Override |
|
208 public void setBounds(int x, int y, int width, int height) |
|
209 { |
|
210 super.setBounds(x, y, width, height); |
|
211 icon_.setIconWidth(width); |
|
212 icon_.setIconHeight(height); |
|
213 } |
|
214 |
|
215 /* |
|
216 * MouseListener methods |
|
217 */ |
|
218 |
|
219 public void mouseClicked(MouseEvent e) |
|
220 { |
|
221 /* Theoretically, motion could be lost or not occur. */ |
|
222 mouseMoved(e); |
|
223 setSelection(current_); |
|
224 } |
|
225 |
|
226 public void mousePressed(MouseEvent e) |
|
227 { |
|
228 return; |
|
229 } |
|
230 |
|
231 public void mouseReleased(MouseEvent e) |
|
232 { |
|
233 return; |
|
234 } |
|
235 |
|
236 public void mouseEntered(MouseEvent e) |
|
237 { |
|
238 return; |
|
239 } |
|
240 |
|
241 public void mouseExited(MouseEvent e) |
|
242 { |
|
243 return; |
|
244 } |
|
245 |
|
246 /* |
|
247 * MouseMotionListener methods |
|
248 */ |
|
249 |
|
250 public void mouseDragged(MouseEvent e) |
|
251 { |
|
252 return; |
|
253 } |
|
254 |
|
255 public void mouseMoved(MouseEvent e) |
|
256 { |
|
257 double mindist = Double.MAX_VALUE; |
|
258 LocationLabel closest = null; |
|
259 |
|
260 /* |
|
261 * Simple but sufficient. |
|
262 */ |
|
263 Point target = e.getPoint(); |
|
264 for (LocationLabel ll : objects_.values()) { |
|
265 double dist = target.distanceSq(ll.getPixelCenter()); |
|
266 if (dist < mindist) { |
|
267 mindist = dist; |
|
268 closest = ll; |
|
269 } |
|
270 } |
|
271 setCurrent(closest); |
|
272 } |
|
273 |
|
274 /* |
|
275 * LocationPicker methods |
|
276 */ |
|
277 |
|
278 private void sendEvent(LocationSelectionListeners<T> listeners, |
|
279 LocationSelectionEvent.Type type, LocationLabel location) |
|
280 { |
|
281 LocationSelectionEvent<T> event = |
|
282 new LocationSelectionEvent<T>(this, type, |
|
283 location == null ? null : location.getObject()); |
|
284 |
|
285 listeners.locationChanged(event); |
|
286 } |
|
287 |
|
288 private void setCurrent(LocationLabel newloc) |
|
289 { |
|
290 if (newloc != current_) { |
|
291 if (current_ != null) |
|
292 current_.setHighlit(false); |
|
293 if (newloc != null) { |
|
294 newloc.setHighlit(true); |
|
295 setToolTipText(newloc.getToolTip()); |
|
296 } else { |
|
297 setToolTipText(null); |
|
298 } |
|
299 |
|
300 current_ = newloc; |
|
301 |
|
302 sendEvent(highlightListeners_, |
|
303 LocationSelectionEvent.Type.HIGHLIGHT, selection_); |
|
304 } |
|
305 } |
|
306 |
|
307 private void setSelection(LocationLabel newloc) |
|
308 { |
|
309 if (newloc != selection_) { |
|
310 if (selection_ != null) |
|
311 selection_.setSelected(false); |
|
312 if (newloc != null) |
|
313 newloc.setSelected(true); |
|
314 |
|
315 selection_ = newloc; |
|
316 |
|
317 sendEvent(selectionListeners_, |
|
318 LocationSelectionEvent.Type.SELECTION, selection_); |
|
319 } |
|
320 } |
|
321 |
|
322 public void setSelection(T object) |
|
323 { |
|
324 LocationLabel ll = objects_.get(object); |
|
325 if (ll == null && object != null) |
|
326 throw (new IllegalArgumentException("Object not in display")); |
|
327 setSelection(ll); |
|
328 } |
|
329 |
|
330 public T getSelection() |
|
331 { |
|
332 return ((selection_ == null) ? null : selection_.getObject()); |
|
333 } |
|
334 |
|
335 public void addSelectionListener(LocationSelectionListener<T> listener) |
|
336 { |
|
337 selectionListeners_.add(listener); |
|
338 } |
|
339 |
|
340 public boolean removeSelectionListener( |
|
341 LocationSelectionListener<T> listener) |
|
342 { |
|
343 return selectionListeners_.remove(listener); |
|
344 } |
|
345 |
|
346 public void addHighlightListener(LocationSelectionListener<T> listener) |
|
347 { |
|
348 highlightListeners_.add(listener); |
|
349 } |
|
350 |
|
351 public boolean removeHighlightListener( |
|
352 LocationSelectionListener<T> listener) |
|
353 { |
|
354 return highlightListeners_.remove(listener); |
|
355 } |
|
356 |
|
357 public void setObjects(Set<T> objects) { |
|
358 if (!objects_.isEmpty()) { |
|
359 for (LocationLabel label : objects_.values()) |
|
360 remove(label); |
|
361 objects_.clear(); |
|
362 } |
|
363 |
|
364 for (T o : objects) { |
|
365 LocationLabel l = new LocationLabel(o); |
|
366 add(l); |
|
367 objects_.put(o, l); |
|
368 } |
|
369 } |
|
370 } |