1 /*
   2  * Copyright (c) 1997, 2003, 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     private class DragPane extends JComponent {
  76         public void paint(Graphics g) {
  77             g.setColor(Color.darkGray);
  78             g.drawRect(0, 0, getWidth()-1, getHeight()-1);
  79         }
  80     };
  81 
  82 ////////////////////////////////////////////////////////////////////////////////////
  83 ///  MotifDesktopManager class
  84 ////////////////////////////////////////////////////////////////////////////////////
  85     private class MotifDesktopManager extends DefaultDesktopManager implements Serializable, UIResource {
  86         JComponent dragPane;
  87         boolean usingDragPane = false;
  88         private transient JLayeredPane layeredPaneForDragPane;
  89         int iconWidth, iconHeight;
  90 
  91     // PENDING(klobad) this should be optimized
  92     public void setBoundsForFrame(JComponent f, int newX, int newY,
  93                         int newWidth, int newHeight) {
  94         if(!usingDragPane) {
  95             boolean didResize;
  96             didResize = (f.getWidth() != newWidth || f.getHeight() != newHeight);
  97             Rectangle r = f.getBounds();
  98             f.setBounds(newX, newY, newWidth, newHeight);
  99             SwingUtilities.computeUnion(newX, newY, newWidth, newHeight, r);
 100             f.getParent().repaint(r.x, r.y, r.width, r.height);
 101             if(didResize) {
 102                 f.validate();
 103             }
 104         } else {
 105             Rectangle r = dragPane.getBounds();
 106             dragPane.setBounds(newX, newY, newWidth, newHeight);
 107             SwingUtilities.computeUnion(newX, newY, newWidth, newHeight, r);
 108             dragPane.getParent().repaint(r.x, r.y, r.width, r.height);
 109         }
 110     }
 111 
 112     public void beginDraggingFrame(JComponent f) {
 113         usingDragPane = false;
 114         if(f.getParent() instanceof JLayeredPane) {
 115             if(dragPane == null)
 116                 dragPane = new DragPane();
 117             layeredPaneForDragPane = (JLayeredPane)f.getParent();
 118             layeredPaneForDragPane.setLayer(dragPane, Integer.MAX_VALUE);
 119             dragPane.setBounds(f.getX(), f.getY(), f.getWidth(), f.getHeight());
 120             layeredPaneForDragPane.add(dragPane);
 121             usingDragPane = true;
 122         }
 123     }
 124 
 125     public void dragFrame(JComponent f, int newX, int newY) {
 126         setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());
 127     }
 128 
 129     public void endDraggingFrame(JComponent f) {
 130         if(usingDragPane) {
 131             layeredPaneForDragPane.remove(dragPane);
 132             usingDragPane = false;
 133             if (f instanceof JInternalFrame) {
 134                 setBoundsForFrame(f, dragPane.getX(), dragPane.getY(),
 135                         dragPane.getWidth(), dragPane.getHeight());
 136             } else if (f instanceof JInternalFrame.JDesktopIcon) {
 137                 adjustBoundsForIcon((JInternalFrame.JDesktopIcon)f,
 138                         dragPane.getX(), dragPane.getY());
 139             }
 140         }
 141     }
 142 
 143     public void beginResizingFrame(JComponent f, int direction) {
 144         usingDragPane = false;
 145         if(f.getParent() instanceof JLayeredPane) {
 146             if(dragPane == null)
 147                 dragPane = new DragPane();
 148             JLayeredPane p = (JLayeredPane)f.getParent();
 149             p.setLayer(dragPane, Integer.MAX_VALUE);
 150             dragPane.setBounds(f.getX(), f.getY(),
 151                                 f.getWidth(), f.getHeight());
 152             p.add(dragPane);
 153             usingDragPane = true;
 154         }
 155     }
 156 
 157     public void resizeFrame(JComponent f, int newX, int newY,
 158                                 int newWidth, int newHeight) {
 159         setBoundsForFrame(f, newX, newY, newWidth, newHeight);
 160     }
 161 
 162     public void endResizingFrame(JComponent f) {
 163         if(usingDragPane) {
 164             JLayeredPane p = (JLayeredPane)f.getParent();
 165             p.remove(dragPane);
 166             usingDragPane = false;
 167             setBoundsForFrame(f, dragPane.getX(), dragPane.getY(),
 168                                 dragPane.getWidth(), dragPane.getHeight());
 169         }
 170     }
 171 
 172         public void iconifyFrame(JInternalFrame f) {
 173             JInternalFrame.JDesktopIcon icon = f.getDesktopIcon();
 174             Point p = icon.getLocation();
 175             adjustBoundsForIcon(icon, p.x, p.y);
 176             super.iconifyFrame(f);
 177         }
 178 
 179         /**
 180          * Change positions of icons in the desktop pane so that
 181          * they do not overlap
 182          */
 183         protected void adjustIcons(JDesktopPane desktop) {
 184             // We need to know Motif icon size
 185             JInternalFrame.JDesktopIcon icon = new JInternalFrame.JDesktopIcon(
 186                     new JInternalFrame());
 187             Dimension iconSize = icon.getPreferredSize();
 188             iconWidth = iconSize.width;
 189             iconHeight = iconSize.height;
 190 
 191             JInternalFrame[] frames = desktop.getAllFrames();
 192             for (int i=0; i<frames.length; i++) {
 193                 icon = frames[i].getDesktopIcon();
 194                 Point ip = icon.getLocation();
 195                 adjustBoundsForIcon(icon, ip.x, ip.y);
 196             }
 197         }
 198 
 199         /**
 200          * Change positions of icon so that it doesn't overlap
 201          * other icons.
 202          */
 203         protected void adjustBoundsForIcon(JInternalFrame.JDesktopIcon icon,
 204                 int x, int y) {
 205             JDesktopPane c = icon.getDesktopPane();
 206 
 207             int maxy = c.getHeight();
 208             int w = iconWidth;
 209             int h = iconHeight;
 210             c.repaint(x, y, w, h);
 211             x = x < 0 ? 0 : x;
 212             y = y < 0 ? 0 : y;
 213 
 214             /* Fix for disappearing icons. If the y value is maxy then this
 215              * algorithm would place the icon in a non-displayed cell.  Never
 216              * to be ssen again.*/
 217             y = y >= maxy ? (maxy - 1) : y;
 218 
 219             /* Compute the offset for the cell we are trying to go in. */
 220             int lx = (x / w) * w;
 221             int ygap = maxy % h;
 222             int ly = ((y-ygap) / h) * h + ygap;
 223 
 224             /* How far are we into the cell we dropped the icon in. */
 225             int dx = x - lx;
 226             int dy = y - ly;
 227 
 228             /* Set coordinates for the icon. */
 229             x = dx < w/2 ? lx: lx + w;
 230             y = dy < h/2 ? ly: ((ly + h) < maxy ? ly + h: ly);
 231 
 232             while (getIconAt(c, icon, x, y) != null) {
 233                 x += w;
 234             }
 235 
 236             /* Cancel the move if the x value was moved off screen. */
 237             if (x > c.getWidth()) {
 238                 return;
 239             }
 240             if (icon.getParent() != null) {
 241                 setBoundsForFrame(icon, x, y, w, h);
 242             } else {
 243                 icon.setLocation(x, y);
 244             }
 245         }
 246 
 247         protected JInternalFrame.JDesktopIcon getIconAt(JDesktopPane desktop,
 248             JInternalFrame.JDesktopIcon icon, int x, int y) {
 249 
 250             JInternalFrame.JDesktopIcon currentIcon = null;
 251             Component[] components = desktop.getComponents();
 252 
 253             for (int i=0; i<components.length; i++) {
 254                 Component comp = components[i];
 255                 if (comp instanceof JInternalFrame.JDesktopIcon &&
 256                     comp != icon) {
 257 
 258                     Point p = comp.getLocation();
 259                     if (p.x == x && p.y == y) {
 260                         return (JInternalFrame.JDesktopIcon)comp;
 261                     }
 262                 }
 263             }
 264             return null;
 265         }
 266     }; /// END of MotifDesktopManager
 267 }