1 /*
   2  * Copyright (c) 1997, 2014, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.java.swing.plaf.motif;
  27 
  28 import sun.swing.SwingUtilities2;
  29 import java.awt.*;
  30 import java.awt.event.*;
  31 import javax.swing.*;
  32 import javax.swing.border.*;
  33 import javax.swing.plaf.*;
  34 import javax.swing.plaf.basic.*;
  35 import java.beans.*;
  36 import java.util.EventListener;
  37 import java.io.Serializable;
  38 
  39 
  40 /**
  41  * Motif rendition of the component.
  42  *
  43  * @author Thomas Ball
  44  * @author Rich Schiavi
  45  */
  46 public class MotifDesktopIconUI extends BasicDesktopIconUI
  47 {
  48     protected DesktopIconActionListener desktopIconActionListener;
  49     protected DesktopIconMouseListener  desktopIconMouseListener;
  50 
  51     protected Icon       defaultIcon;
  52     protected IconButton iconButton;
  53     protected IconLabel  iconLabel;
  54 
  55     // This is only used for its system menu, but we need a reference to it so
  56     // we can remove its listeners.
  57     private MotifInternalFrameTitlePane sysMenuTitlePane;
  58 
  59     JPopupMenu systemMenu;
  60     EventListener mml;
  61 
  62     final static int LABEL_HEIGHT = 18;
  63     final static int LABEL_DIVIDER = 4;    // padding between icon and label
  64 
  65     final static Font defaultTitleFont =
  66         new Font(Font.SANS_SERIF, Font.PLAIN, 12);
  67 
  68     public static ComponentUI createUI(JComponent c)    {
  69         return new MotifDesktopIconUI();
  70     }
  71 
  72     public MotifDesktopIconUI() {
  73     }
  74 
  75     protected void installDefaults(){
  76         super.installDefaults();
  77         setDefaultIcon(UIManager.getIcon("DesktopIcon.icon"));
  78         iconButton = createIconButton(defaultIcon);
  79         // An underhanded way of creating a system popup menu.
  80         sysMenuTitlePane =  new MotifInternalFrameTitlePane(frame);
  81         systemMenu = sysMenuTitlePane.getSystemMenu();
  82 
  83         MotifBorders.FrameBorder border = new MotifBorders.FrameBorder(desktopIcon);
  84         desktopIcon.setLayout(new BorderLayout());
  85         iconButton.setBorder(border);
  86         desktopIcon.add(iconButton, BorderLayout.CENTER);
  87         iconLabel = createIconLabel(frame);
  88         iconLabel.setBorder(border);
  89         desktopIcon.add(iconLabel, BorderLayout.SOUTH);
  90         desktopIcon.setSize(desktopIcon.getPreferredSize());
  91         desktopIcon.validate();
  92         JLayeredPane.putLayer(desktopIcon, JLayeredPane.getLayer(frame));
  93     }
  94 
  95     protected void installComponents(){
  96     }
  97 
  98     protected void uninstallComponents(){
  99     }
 100 
 101     protected void installListeners(){
 102         super.installListeners();
 103         desktopIconActionListener = createDesktopIconActionListener();
 104         desktopIconMouseListener = createDesktopIconMouseListener();
 105         iconButton.addActionListener(desktopIconActionListener);
 106         iconButton.addMouseListener(desktopIconMouseListener);
 107         iconLabel.addMouseListener(desktopIconMouseListener);
 108     }
 109 
 110     JInternalFrame.JDesktopIcon getDesktopIcon(){
 111       return desktopIcon;
 112     }
 113 
 114     void setDesktopIcon(JInternalFrame.JDesktopIcon d){
 115       desktopIcon = d;
 116     }
 117 
 118     JInternalFrame getFrame(){
 119       return frame;
 120     }
 121 
 122     void setFrame(JInternalFrame f){
 123       frame = f ;
 124     }
 125 
 126     protected void showSystemMenu(){
 127       systemMenu.show(iconButton, 0, getDesktopIcon().getHeight());
 128     }
 129 
 130     protected void hideSystemMenu(){
 131       systemMenu.setVisible(false);
 132     }
 133 
 134     protected IconLabel createIconLabel(JInternalFrame frame){
 135         return new IconLabel(frame);
 136     }
 137 
 138     protected IconButton createIconButton(Icon i){
 139         return new IconButton(i);
 140     }
 141 
 142     protected DesktopIconActionListener createDesktopIconActionListener(){
 143         return new DesktopIconActionListener();
 144     }
 145 
 146     protected DesktopIconMouseListener createDesktopIconMouseListener(){
 147         return new DesktopIconMouseListener();
 148     }
 149 
 150     protected void uninstallDefaults(){
 151         super.uninstallDefaults();
 152         desktopIcon.setLayout(null);
 153         desktopIcon.remove(iconButton);
 154         desktopIcon.remove(iconLabel);
 155     }
 156 
 157     protected void uninstallListeners(){
 158         super.uninstallListeners();
 159         iconButton.removeActionListener(desktopIconActionListener);
 160         iconButton.removeMouseListener(desktopIconMouseListener);
 161         sysMenuTitlePane.uninstallListeners();
 162     }
 163 
 164     public Dimension getMinimumSize(JComponent c) {
 165         JInternalFrame iframe = desktopIcon.getInternalFrame();
 166 
 167         int w = defaultIcon.getIconWidth();
 168         int h = defaultIcon.getIconHeight() + LABEL_HEIGHT + LABEL_DIVIDER;
 169 
 170         Border border = iframe.getBorder();
 171         if(border != null) {
 172             w += border.getBorderInsets(iframe).left +
 173                 border.getBorderInsets(iframe).right;
 174             h += border.getBorderInsets(iframe).bottom +
 175                 border.getBorderInsets(iframe).top;
 176         }
 177 
 178         return new Dimension(w, h);
 179     }
 180 
 181     public Dimension getPreferredSize(JComponent c) {
 182         return getMinimumSize(c);
 183     }
 184 
 185     public Dimension getMaximumSize(JComponent c){
 186         return getMinimumSize(c);
 187     }
 188 
 189     /**
 190       * Returns the default desktop icon.
 191       */
 192     public Icon getDefaultIcon() {
 193         return defaultIcon;
 194     }
 195 
 196     /**
 197       * Sets the icon used as the default desktop icon.
 198       */
 199     public void setDefaultIcon(Icon newIcon) {
 200         defaultIcon = newIcon;
 201     }
 202 
 203     @SuppressWarnings("serial") // Superclass is not serializable across versions
 204     protected class IconLabel extends JPanel {
 205         JInternalFrame frame;
 206 
 207         IconLabel(JInternalFrame f) {
 208             super();
 209             this.frame = f;
 210             setFont(defaultTitleFont);
 211 
 212             // Forward mouse events to titlebar for moves.
 213             addMouseMotionListener(new MouseMotionListener() {
 214                 public void mouseDragged(MouseEvent e) {
 215                     forwardEventToParent(e);
 216                 }
 217                 public void mouseMoved(MouseEvent e) {
 218                     forwardEventToParent(e);
 219                 }
 220             });
 221             addMouseListener(new MouseListener() {
 222                 public void mouseClicked(MouseEvent e) {
 223                     forwardEventToParent(e);
 224                 }
 225                 public void mousePressed(MouseEvent e) {
 226                     forwardEventToParent(e);
 227                 }
 228                 public void mouseReleased(MouseEvent e) {
 229                     forwardEventToParent(e);
 230                 }
 231                 public void mouseEntered(MouseEvent e) {
 232                     forwardEventToParent(e);
 233                 }
 234                 public void mouseExited(MouseEvent e) {
 235                     forwardEventToParent(e);
 236                 }
 237             });
 238         }
 239 
 240         void forwardEventToParent(MouseEvent e) {
 241             getParent().dispatchEvent(new MouseEvent(
 242                 getParent(), e.getID(), e.getWhen(), e.getModifiers(),
 243                 e.getX(), e.getY(), e.getXOnScreen(),
 244                 e.getYOnScreen(), e.getClickCount(),
 245                 e.isPopupTrigger(), MouseEvent.NOBUTTON));
 246         }
 247 
 248         @SuppressWarnings("deprecation")
 249         public boolean isFocusTraversable() {
 250             return false;
 251         }
 252 
 253         public Dimension getMinimumSize() {
 254             return new Dimension(defaultIcon.getIconWidth() + 1,
 255                                  LABEL_HEIGHT + LABEL_DIVIDER);
 256         }
 257 
 258         public Dimension getPreferredSize() {
 259             String title = frame.getTitle();
 260             FontMetrics fm = frame.getFontMetrics(defaultTitleFont);
 261             int w = 4;
 262             if (title != null) {
 263                 w += SwingUtilities2.stringWidth(frame, fm, title);
 264             }
 265             return new Dimension(w, LABEL_HEIGHT + LABEL_DIVIDER);
 266         }
 267 
 268         public void paint(Graphics g) {
 269             super.paint(g);
 270 
 271             // touch-up frame
 272             int maxX = getWidth() - 1;
 273             Color shadow =
 274                 UIManager.getColor("inactiveCaptionBorder").darker().darker();
 275             g.setColor(shadow);
 276             g.setClip(0, 0, getWidth(), getHeight());
 277             g.drawLine(maxX - 1, 1, maxX - 1, 1);
 278             g.drawLine(maxX, 0, maxX, 0);
 279 
 280             // fill background
 281             g.setColor(UIManager.getColor("inactiveCaption"));
 282             g.fillRect(2, 1, maxX - 3, LABEL_HEIGHT + 1);
 283 
 284             // draw text -- clipping to truncate text like CDE/Motif
 285             g.setClip(2, 1, maxX - 4, LABEL_HEIGHT);
 286             int y = LABEL_HEIGHT - SwingUtilities2.getFontMetrics(frame, g).
 287                                                    getDescent();
 288             g.setColor(UIManager.getColor("inactiveCaptionText"));
 289             String title = frame.getTitle();
 290             if (title != null) {
 291                 SwingUtilities2.drawString(frame, g, title, 4, y);
 292             }
 293         }
 294     }
 295 
 296     @SuppressWarnings("serial") // Superclass is not serializable across versions
 297     protected class IconButton extends JButton {
 298         Icon icon;
 299 
 300         IconButton(Icon icon) {
 301             super(icon);
 302             this.icon = icon;
 303             // Forward mouse events to titlebar for moves.
 304             addMouseMotionListener(new MouseMotionListener() {
 305                 public void mouseDragged(MouseEvent e) {
 306                     forwardEventToParent(e);
 307                 }
 308                 public void mouseMoved(MouseEvent e) {
 309                     forwardEventToParent(e);
 310                 }
 311             });
 312             addMouseListener(new MouseListener() {
 313                 public void mouseClicked(MouseEvent e) {
 314                     forwardEventToParent(e);
 315                 }
 316                 public void mousePressed(MouseEvent e) {
 317                     forwardEventToParent(e);
 318                 }
 319                 public void mouseReleased(MouseEvent e) {
 320                     if (!systemMenu.isShowing()) {
 321                         forwardEventToParent(e);
 322                     }
 323                 }
 324                 public void mouseEntered(MouseEvent e) {
 325                     forwardEventToParent(e);
 326                 }
 327                 public void mouseExited(MouseEvent e) {
 328                     forwardEventToParent(e);
 329                 }
 330             });
 331         }
 332 
 333         void forwardEventToParent(MouseEvent e) {
 334             getParent().dispatchEvent(new MouseEvent(
 335                 getParent(), e.getID(), e.getWhen(), e.getModifiers(),
 336                 e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(),
 337                 e.getClickCount(), e.isPopupTrigger(), MouseEvent.NOBUTTON ));
 338         }
 339 
 340         @SuppressWarnings("deprecation")
 341         public boolean isFocusTraversable() {
 342             return false;
 343         }
 344     }
 345 
 346 
 347     protected class DesktopIconActionListener implements ActionListener {
 348         public void actionPerformed(ActionEvent e){
 349             systemMenu.show(iconButton, 0, getDesktopIcon().getHeight());
 350         }
 351     }
 352 
 353     protected class DesktopIconMouseListener extends MouseAdapter {
 354         // if we drag or move we should deengage the popup
 355         public void mousePressed(MouseEvent e){
 356             if (e.getClickCount() > 1) {
 357                 try {
 358                     getFrame().setIcon(false);
 359                 } catch (PropertyVetoException e2){ }
 360                 systemMenu.setVisible(false);
 361                 /* the mouse release will not get reported correctly,
 362                    because the icon will no longer be in the hierarchy;
 363                    maybe that should be fixed, but until it is, we need
 364                    to do the required cleanup here. */
 365                 getFrame().getDesktopPane().getDesktopManager().endDraggingFrame((JComponent)e.getSource());
 366             }
 367         }
 368     }
 369 }