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 javax.swing.*;
  29 import java.awt.Rectangle;
  30 import java.awt.Dimension;
  31 import java.awt.Insets;
  32 import java.awt.Color;
  33 import java.awt.Graphics;
  34 import java.awt.Component;
  35 import java.awt.Point;
  36 import javax.swing.plaf.*;
  37 import java.io.Serializable;
  38 
  39 /**
  40  * <p>
  41  * <strong>Warning:</strong>
  42  * Serialized objects of this class will not be compatible with
  43  * future Swing releases.  The current serialization support is appropriate
  44  * for short term storage or RMI between applications running the same
  45  * version of Swing.  A future release of Swing will provide support for
  46  * long term persistence.
  47  *
  48  * @author David Kloba
  49  */
  50 public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneUI
  51 {
  52 
  53 /// DesktopPaneUI methods
  54     public static ComponentUI createUI(JComponent d)    {
  55         return new MotifDesktopPaneUI();
  56     }
  57 
  58     public MotifDesktopPaneUI() {
  59     }
  60 
  61     protected void installDesktopManager() {
  62         desktopManager = desktop.getDesktopManager();
  63         if(desktopManager == null) {
  64             desktopManager = new MotifDesktopManager();
  65             desktop.setDesktopManager(desktopManager);
  66             ((MotifDesktopManager)desktopManager).adjustIcons(desktop);
  67         }
  68     }
  69 
  70     public Insets getInsets(JComponent c) {return new Insets(0,0,0,0);}
  71 
  72 ////////////////////////////////////////////////////////////////////////////////////
  73 ///  DragPane class
  74 ////////////////////////////////////////////////////////////////////////////////////
  75     @SuppressWarnings("serial") // Superclass is not serializable across versions
  76     private class DragPane extends JComponent {
  77         public void paint(Graphics g) {
  78             g.setColor(Color.darkGray);
  79             g.drawRect(0, 0, getWidth()-1, getHeight()-1);
  80         }
  81     };
  82 
  83 ////////////////////////////////////////////////////////////////////////////////////
  84 ///  MotifDesktopManager class
  85 ////////////////////////////////////////////////////////////////////////////////////
  86     @SuppressWarnings("serial") // JDK-implementation class
  87     private class MotifDesktopManager extends DefaultDesktopManager implements Serializable, UIResource {
  88         JComponent dragPane;
  89         boolean usingDragPane = false;
  90         private transient JLayeredPane layeredPaneForDragPane;
  91         int iconWidth, iconHeight;
  92 
  93     // PENDING(klobad) this should be optimized
  94     public void setBoundsForFrame(JComponent f, int newX, int newY,
  95                         int newWidth, int newHeight) {
  96         if(!usingDragPane) {
  97             boolean didResize;
  98             didResize = (f.getWidth() != newWidth || f.getHeight() != newHeight);
  99             Rectangle r = f.getBounds();
 100             f.setBounds(newX, newY, newWidth, newHeight);
 101             SwingUtilities.computeUnion(newX, newY, newWidth, newHeight, r);
 102             f.getParent().repaint(r.x, r.y, r.width, r.height);
 103             if(didResize) {
 104                 f.validate();
 105             }
 106         } else {
 107             Rectangle r = dragPane.getBounds();
 108             dragPane.setBounds(newX, newY, newWidth, newHeight);
 109             SwingUtilities.computeUnion(newX, newY, newWidth, newHeight, r);
 110             dragPane.getParent().repaint(r.x, r.y, r.width, r.height);
 111         }
 112     }
 113 
 114     public void beginDraggingFrame(JComponent f) {
 115         usingDragPane = false;
 116         if(f.getParent() instanceof JLayeredPane) {
 117             if(dragPane == null)
 118                 dragPane = new DragPane();
 119             layeredPaneForDragPane = (JLayeredPane)f.getParent();
 120             layeredPaneForDragPane.setLayer(dragPane, Integer.MAX_VALUE);
 121             dragPane.setBounds(f.getX(), f.getY(), f.getWidth(), f.getHeight());
 122             layeredPaneForDragPane.add(dragPane);
 123             usingDragPane = true;
 124         }
 125     }
 126 
 127     public void dragFrame(JComponent f, int newX, int newY) {
 128         setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());
 129     }
 130 
 131     public void endDraggingFrame(JComponent f) {
 132         if(usingDragPane) {
 133             layeredPaneForDragPane.remove(dragPane);
 134             usingDragPane = false;
 135             if (f instanceof JInternalFrame) {
 136                 setBoundsForFrame(f, dragPane.getX(), dragPane.getY(),
 137                         dragPane.getWidth(), dragPane.getHeight());
 138             } else if (f instanceof JInternalFrame.JDesktopIcon) {
 139                 adjustBoundsForIcon((JInternalFrame.JDesktopIcon)f,
 140                         dragPane.getX(), dragPane.getY());
 141             }
 142         }
 143     }
 144 
 145     public void beginResizingFrame(JComponent f, int direction) {
 146         usingDragPane = false;
 147         if(f.getParent() instanceof JLayeredPane) {
 148             if(dragPane == null)
 149                 dragPane = new DragPane();
 150             JLayeredPane p = (JLayeredPane)f.getParent();
 151             p.setLayer(dragPane, Integer.MAX_VALUE);
 152             dragPane.setBounds(f.getX(), f.getY(),
 153                                 f.getWidth(), f.getHeight());
 154             p.add(dragPane);
 155             usingDragPane = true;
 156         }
 157     }
 158 
 159     public void resizeFrame(JComponent f, int newX, int newY,
 160                                 int newWidth, int newHeight) {
 161         setBoundsForFrame(f, newX, newY, newWidth, newHeight);
 162     }
 163 
 164     public void endResizingFrame(JComponent f) {
 165         if(usingDragPane) {
 166             JLayeredPane p = (JLayeredPane)f.getParent();
 167             p.remove(dragPane);
 168             usingDragPane = false;
 169             setBoundsForFrame(f, dragPane.getX(), dragPane.getY(),
 170                                 dragPane.getWidth(), dragPane.getHeight());
 171         }
 172     }
 173 
 174         public void iconifyFrame(JInternalFrame f) {
 175             JInternalFrame.JDesktopIcon icon = f.getDesktopIcon();
 176             Point p = icon.getLocation();
 177             adjustBoundsForIcon(icon, p.x, p.y);
 178             super.iconifyFrame(f);
 179         }
 180 
 181         /**
 182          * Change positions of icons in the desktop pane so that
 183          * they do not overlap
 184          */
 185         protected void adjustIcons(JDesktopPane desktop) {
 186             // We need to know Motif icon size
 187             JInternalFrame.JDesktopIcon icon = new JInternalFrame.JDesktopIcon(
 188                     new JInternalFrame());
 189             Dimension iconSize = icon.getPreferredSize();
 190             iconWidth = iconSize.width;
 191             iconHeight = iconSize.height;
 192 
 193             JInternalFrame[] frames = desktop.getAllFrames();
 194             for (int i=0; i<frames.length; i++) {
 195                 icon = frames[i].getDesktopIcon();
 196                 Point ip = icon.getLocation();
 197                 adjustBoundsForIcon(icon, ip.x, ip.y);
 198             }
 199         }
 200 
 201         /**
 202          * Change positions of icon so that it doesn't overlap
 203          * other icons.
 204          */
 205         protected void adjustBoundsForIcon(JInternalFrame.JDesktopIcon icon,
 206                 int x, int y) {
 207             JDesktopPane c = icon.getDesktopPane();
 208 
 209             int maxy = c.getHeight();
 210             int w = iconWidth;
 211             int h = iconHeight;
 212             c.repaint(x, y, w, h);
 213             x = x < 0 ? 0 : x;
 214             y = y < 0 ? 0 : y;
 215 
 216             /* Fix for disappearing icons. If the y value is maxy then this
 217              * algorithm would place the icon in a non-displayed cell.  Never
 218              * to be ssen again.*/
 219             y = y >= maxy ? (maxy - 1) : y;
 220 
 221             /* Compute the offset for the cell we are trying to go in. */
 222             int lx = (x / w) * w;
 223             int ygap = maxy % h;
 224             int ly = ((y-ygap) / h) * h + ygap;
 225 
 226             /* How far are we into the cell we dropped the icon in. */
 227             int dx = x - lx;
 228             int dy = y - ly;
 229 
 230             /* Set coordinates for the icon. */
 231             x = dx < w/2 ? lx: lx + w;
 232             y = dy < h/2 ? ly: ((ly + h) < maxy ? ly + h: ly);
 233 
 234             while (getIconAt(c, icon, x, y) != null) {
 235                 x += w;
 236             }
 237 
 238             /* Cancel the move if the x value was moved off screen. */
 239             if (x > c.getWidth()) {
 240                 return;
 241             }
 242             if (icon.getParent() != null) {
 243                 setBoundsForFrame(icon, x, y, w, h);
 244             } else {
 245                 icon.setLocation(x, y);
 246             }
 247         }
 248 
 249         protected JInternalFrame.JDesktopIcon getIconAt(JDesktopPane desktop,
 250             JInternalFrame.JDesktopIcon icon, int x, int y) {
 251 
 252             JInternalFrame.JDesktopIcon currentIcon = null;
 253             Component[] components = desktop.getComponents();
 254 
 255             for (int i=0; i<components.length; i++) {
 256                 Component comp = components[i];
 257                 if (comp instanceof JInternalFrame.JDesktopIcon &&
 258                     comp != icon) {
 259 
 260                     Point p = comp.getLocation();
 261                     if (p.x == x && p.y == y) {
 262                         return (JInternalFrame.JDesktopIcon)comp;
 263                     }
 264                 }
 265             }
 266             return null;
 267         }
 268     }; /// END of MotifDesktopManager
 269 }