001 /* BasicDesktopIconUI.java --
002 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing.plaf.basic;
040
041 import java.awt.BorderLayout;
042 import java.awt.Color;
043 import java.awt.Component;
044 import java.awt.Dimension;
045 import java.awt.Graphics;
046 import java.awt.Insets;
047 import java.awt.Rectangle;
048 import java.awt.event.ActionEvent;
049 import java.awt.event.ActionListener;
050 import java.awt.event.MouseEvent;
051 import java.beans.PropertyChangeEvent;
052 import java.beans.PropertyChangeListener;
053 import java.beans.PropertyVetoException;
054
055 import javax.swing.Icon;
056 import javax.swing.JButton;
057 import javax.swing.JComponent;
058 import javax.swing.JDesktopPane;
059 import javax.swing.JInternalFrame;
060 import javax.swing.JInternalFrame.JDesktopIcon;
061 import javax.swing.SwingConstants;
062 import javax.swing.border.Border;
063 import javax.swing.event.MouseInputAdapter;
064 import javax.swing.event.MouseInputListener;
065 import javax.swing.plaf.ComponentUI;
066 import javax.swing.plaf.DesktopIconUI;
067
068 /**
069 * This class acts as the UI delegate for JDesktopIcons for the Basic look and feel.
070 */
071 public class BasicDesktopIconUI extends DesktopIconUI
072 {
073 /**
074 * This helper class handles mouse events that occur on the JDesktopIcon.
075 */
076 public class MouseInputHandler extends MouseInputAdapter
077 {
078 /** The x offset from the MouseEvent coordinates to the top left corner. */
079 private transient int xOffset;
080
081 /** The y offset fromt he MouseEvent coordinates to the top left corner. */
082 private transient int yOffset;
083
084 /** A cached value of the JDesktopPane that parents this JDesktopIcon. */
085 private transient JDesktopPane pane;
086
087 /**
088 * This method is called when the mouse is dragged in the JDesktopIcon.
089 *
090 * @param e The MouseEvent.
091 */
092 public void mouseDragged(MouseEvent e)
093 {
094 Rectangle b = desktopIcon.getBounds();
095
096 moveAndRepaint(desktopIcon, b.x + e.getX() - xOffset,
097 b.y + e.getY() - yOffset, b.width, b.height);
098 }
099
100 /**
101 * This method is called when the mouse is moved in the JDesktopIcon.
102 *
103 * @param e The MouseEvent.
104 */
105 public void mouseMoved(MouseEvent e)
106 {
107 // Nothing to do.
108 }
109
110 /**
111 * This method is called when the mouse is pressed in the JDesktopIcon.
112 *
113 * @param e The MouseEvent.
114 */
115 public void mousePressed(MouseEvent e)
116 {
117 xOffset = e.getX();
118 yOffset = e.getY();
119 pane = frame.getDesktopPane();
120 if (pane != null)
121 pane.getDesktopManager().beginDraggingFrame(desktopIcon);
122 }
123
124 /**
125 * This method is called when the mouse is released in the JDesktopIcon.
126 *
127 * @param e The MouseEvent.
128 */
129 public void mouseReleased(MouseEvent e)
130 {
131 if (pane != null)
132 pane.getDesktopManager().endDraggingFrame(desktopIcon);
133 xOffset = 0;
134 yOffset = 0;
135 }
136
137 /**
138 * This method moves and repaints the JDesktopIcon to the given bounds.
139 *
140 * @param f The JComponent to move and repaint.
141 * @param newX The new x coordinate.
142 * @param newY The new y coordinate.
143 * @param newWidth The new width.
144 * @param newHeight The new height.
145 */
146 public void moveAndRepaint(JComponent f, int newX, int newY, int newWidth,
147 int newHeight)
148 {
149 if (pane != null)
150 pane.getDesktopManager().dragFrame(f, newX, newY);
151 else
152 desktopIcon.setBounds(newX, newY, newWidth, newHeight);
153 }
154 }
155
156 /**
157 * This class acts as the border for the JDesktopIcon.
158 */
159 private class DesktopIconBorder implements Border
160 {
161 /** The left inset value. */
162 int left = 10;
163
164 /** The top inset value. */
165 int top = 4;
166
167 /** The right inset value. */
168 int right = top;
169
170 /** The bottom inset value. */
171 int bottom = top;
172
173 /**
174 * This method returns the insets of the border.
175 *
176 * @param c The Component to find border insets for.
177 *
178 * @return The border insets.
179 */
180 public Insets getBorderInsets(Component c)
181 {
182 return new Insets(top, left, bottom, right);
183 }
184
185 /**
186 * This method returns whether the border is opaque.
187 *
188 * @return Whether the border is opaque.
189 */
190 public boolean isBorderOpaque()
191 {
192 return true;
193 }
194
195 /**
196 * This method paints the border.
197 *
198 * @param c The Component the border is in.
199 * @param g The Graphics object to paint with.
200 * @param x The x coordinate of the Component.
201 * @param y The y coordinate of the Component.
202 * @param width The width of the Component.
203 * @param height The height of the Component.
204 */
205 public void paintBorder(Component c, Graphics g, int x, int y, int width,
206 int height)
207 {
208 g.translate(x, y);
209 Color saved = g.getColor();
210
211 g.setColor(Color.LIGHT_GRAY);
212
213 g.fillRect(0, 0, left, height);
214 g.fillRect(0, 0, width, top);
215 g.fillRect(0, height - bottom, width, bottom);
216 g.fillRect(width - right, 0, right, height);
217
218 g.setColor(Color.BLACK);
219 g.drawRect(0, 0, width - 1, height - 1);
220
221 int fHeight = height / 4;
222 int hLeft = left / 2;
223
224 g.setColor(Color.BLACK);
225 g.fillRect(hLeft, fHeight, 2, 2);
226 g.fillRect(hLeft, fHeight * 2, 2, 2);
227 g.fillRect(hLeft, fHeight * 3, 2, 2);
228
229 g.setColor(saved);
230 g.translate(-x, -y);
231 }
232 }
233
234 /** The static width and height of the iconSize. */
235 private static final int iconSize = 16;
236
237 /**
238 * This class represents the default frame icon when none
239 * is supplied by the JInternalFrame.
240 */
241 static class InternalFrameDefaultMenuIcon implements Icon
242 {
243 /**
244 * This returns the icon height.
245 *
246 * @return The icon height.
247 */
248 public int getIconHeight()
249 {
250 return iconSize;
251 }
252
253 /**
254 * This returns the icon width.
255 *
256 * @return The icon width.
257 */
258 public int getIconWidth()
259 {
260 return iconSize;
261 }
262
263 /**
264 * This method paints the icon.
265 *
266 * @param c The Component this icon belongs to.
267 * @param g The Graphics object to paint with.
268 * @param x The x coordinate to paint at.
269 * @param y The y coordinate to paint at.
270 */
271 public void paintIcon(Component c, Graphics g, int x, int y)
272 {
273 g.translate(x, y);
274 Color saved = g.getColor();
275
276 g.setColor(Color.BLUE);
277 g.fillRect(0, 0, iconSize, (int) ((double) iconSize / 3) + 1);
278
279 g.setColor(Color.WHITE);
280 g.fillRect(0, (int) ((double) iconSize / 3), iconSize, iconSize * 5 / 6);
281
282 g.setColor(Color.GRAY);
283 g.drawRect(0, 0, iconSize, iconSize);
284
285 g.setColor(saved);
286 g.translate(-x, -y);
287 }
288 }
289
290 /** The default JDesktopIcon width. */
291 private static final int iconWidth = 160;
292
293 /** The default JDesktopIcon height */
294 private static final int iconHeight = 35;
295
296 /** The JDesktopIcon this UI delegate represents. */
297 protected JDesktopIcon desktopIcon;
298
299 /** The JInternalFrame associated with the JDesktopIcon. */
300 protected JInternalFrame frame;
301
302 /** The MouseListener responsible for reacting to MouseEvents on the JDesktopIcon. */
303 private transient MouseInputListener mouseHandler;
304
305 /** The Button in the JDesktopIcon responsible for deiconifying it.
306 * This is package-private to avoid an accessor method. */
307 transient BoundButton button;
308
309 /** The PropertyChangeListener listening to the JDesktopIcon. */
310 private transient PropertyChangeListener propertyHandler;
311
312 /** The default icon used when no frame icon is given by the JInternalFrame. */
313 static Icon defaultIcon = new InternalFrameDefaultMenuIcon();
314
315 /**
316 * This is a helper class that is used in JDesktopIcon and gives the Button a predetermined size.
317 */
318 private class BoundButton extends JButton
319 {
320 /**
321 * Creates a new BoundButton object.
322 *
323 * @param title The title of the button.
324 */
325 public BoundButton(String title)
326 {
327 super(title);
328 }
329
330 /**
331 * This method returns a standard size (based on the defaults of the JDesktopIcon) and the insets.
332 *
333 * @return The preferred size of the JDesktopIcon.
334 */
335 public Dimension getPreferredSize()
336 {
337 Insets insets = desktopIcon.getInsets();
338 return new Dimension(iconWidth - insets.left - insets.right,
339 iconHeight - insets.top - insets.bottom);
340 }
341
342 /**
343 * This method returns the minimum size of the button.
344 *
345 * @return The minimum size of the button.
346 */
347 public Dimension getMinimumSize()
348 {
349 return getPreferredSize();
350 }
351
352 /**
353 * This method returns the maximum size of the button.
354 *
355 * @return The maximum size of the button.
356 */
357 public Dimension getMaximumSize()
358 {
359 return getPreferredSize();
360 }
361 }
362
363 /**
364 * Creates a new BasicDesktopIconUI object.
365 */
366 public BasicDesktopIconUI()
367 {
368 // Nothing to do here.
369 }
370
371 /**
372 * This method creates a new BasicDesktopIconUI for the given JComponent.
373 *
374 * @param c The JComponent to create a UI for.
375 *
376 * @return A new BasicDesktopIconUI.
377 */
378 public static ComponentUI createUI(JComponent c)
379 {
380 return new BasicDesktopIconUI();
381 }
382
383 /**
384 * This method installs the UI for the given JComponent.
385 *
386 * @param c The JComponent to install this UI for.
387 */
388 public void installUI(JComponent c)
389 {
390 if (c instanceof JDesktopIcon)
391 {
392 desktopIcon = (JDesktopIcon) c;
393 desktopIcon.setLayout(new BorderLayout());
394 frame = desktopIcon.getInternalFrame();
395
396 installDefaults();
397 installComponents();
398 installListeners();
399
400 desktopIcon.setOpaque(true);
401 }
402 }
403
404 /**
405 * This method uninstalls the UI for the given JComponent.
406 *
407 * @param c The JComponent to uninstall this UI for.
408 */
409 public void uninstallUI(JComponent c)
410 {
411 desktopIcon.setOpaque(false);
412
413 uninstallListeners();
414 uninstallComponents();
415 uninstallDefaults();
416
417 frame = null;
418 desktopIcon.setLayout(null);
419 desktopIcon = null;
420 }
421
422 /**
423 * This method installs the necessary sub components for the JDesktopIcon.
424 */
425 protected void installComponents()
426 {
427 // Try to create a button based on what the frame's
428 // state is currently
429 button = new BoundButton(frame.getTitle());
430 button.setHorizontalAlignment(SwingConstants.LEFT);
431 button.setHorizontalTextPosition(SwingConstants.TRAILING);
432
433 Icon use = frame.getFrameIcon();
434 if (use == null)
435 use = defaultIcon;
436 button.setIcon(use);
437
438 desktopIcon.add(button, SwingConstants.CENTER);
439 }
440
441 /**
442 * This method uninstalls the sub components for the JDesktopIcon.
443 */
444 protected void uninstallComponents()
445 {
446 desktopIcon.remove(button);
447
448 button = null;
449 }
450
451 /**
452 * This method installs the listeners needed by this UI.
453 */
454 protected void installListeners()
455 {
456 mouseHandler = createMouseInputListener();
457
458 desktopIcon.addMouseMotionListener(mouseHandler);
459 desktopIcon.addMouseListener(mouseHandler);
460
461 propertyHandler = new PropertyChangeListener()
462 {
463 public void propertyChange(PropertyChangeEvent e)
464 {
465 if (e.getPropertyName().equals(JInternalFrame.TITLE_PROPERTY))
466 button.setText(desktopIcon.getInternalFrame().getTitle());
467 else if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY))
468 {
469 Icon use = desktopIcon.getInternalFrame().getFrameIcon();
470 if (use == null)
471 use = defaultIcon;
472 button.setIcon(use);
473 }
474 desktopIcon.revalidate();
475 desktopIcon.repaint();
476 }
477 };
478 frame.addPropertyChangeListener(propertyHandler);
479
480 button.addActionListener(new ActionListener()
481 {
482 public void actionPerformed(ActionEvent e)
483 {
484 deiconize();
485 }
486 });
487 }
488
489 /**
490 * This method uninstalls the listeners needed by the UI.
491 */
492 protected void uninstallListeners()
493 {
494 // button is nulled so no need to remove it.
495
496 frame.removePropertyChangeListener(propertyHandler);
497 propertyHandler = null;
498
499 desktopIcon.removeMouseMotionListener(mouseHandler);
500 desktopIcon.removeMouseListener(mouseHandler);
501 }
502
503 /**
504 * This method installs the defaults for the JDesktopIcon.
505 */
506 protected void installDefaults()
507 {
508 // FIXME: Move border to defaults.
509 desktopIcon.setBorder(new DesktopIconBorder());
510 }
511
512 /**
513 * This method uninstalls the defaults for the JDesktopIcon.
514 */
515 protected void uninstallDefaults()
516 {
517 desktopIcon.setBorder(null);
518 }
519
520 /**
521 * This method creates a new MouseInputListener for the JDesktopIcon.
522 *
523 * @return A new MouseInputListener.
524 */
525 protected MouseInputListener createMouseInputListener()
526 {
527 return new MouseInputHandler();
528 }
529
530 /**
531 * This method returns the preferred size for the given JComponent.
532 *
533 * @param c The JComponent to find a preferred size for.
534 *
535 * @return The preferred size.
536 */
537 public Dimension getPreferredSize(JComponent c)
538 {
539 return new Dimension(iconWidth, iconHeight);
540 }
541
542 /**
543 * This method returns the minimum size for the given JComponent.
544 *
545 * @param c The JComponent to find a minimum size for.
546 *
547 * @return The minimum size.
548 */
549 public Dimension getMinimumSize(JComponent c)
550 {
551 return getPreferredSize(c);
552 }
553
554 /**
555 * This method returns the maximum size for the given JComponent.
556 *
557 * @param c The JComponent to find a maximum size for.
558 *
559 * @return The maximum size.
560 */
561 public Dimension getMaximumSize(JComponent c)
562 {
563 return getPreferredSize(c);
564 }
565
566 /**
567 * This method returns the insets of the given JComponent.
568 *
569 * @param c The JComponent to find insets for.
570 *
571 * @return The insets of the given JComponent.
572 */
573 public Insets getInsets(JComponent c)
574 {
575 return c.getInsets();
576 }
577
578 /**
579 * This method deiconizes the JInternalFrame associated with the JDesktopIcon.
580 */
581 public void deiconize()
582 {
583 try
584 {
585 frame.setIcon(false);
586 }
587 catch (PropertyVetoException pve)
588 {
589 // We do nothing if the attempt has been vetoed.
590 }
591 }
592 }