/*
 * @(#)MotifDesktopPaneUI.java	1.22 01/12/03
 *
 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.sun.java.swing.plaf.motif;

import javax.swing.*;
import java.awt.Rectangle;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Component;
import java.awt.Point;
import javax.swing.plaf.*;
import java.io.Serializable;

/**
 * <p>
 * <strong>Warning:</strong>
 * Serialized objects of this class will not be compatible with
 * future Swing releases.  The current serialization support is appropriate
 * for short term storage or RMI between applications running the same
 * version of Swing.  A future release of Swing will provide support for
 * long term persistence.
 *
 * @version 1.22 12/03/01
 * @author David Kloba
 */
public class MotifDesktopPaneUI extends javax.swing.plaf.basic.BasicDesktopPaneUI
{

/// DesktopPaneUI methods
    public static ComponentUI createUI(JComponent d)    {
        return new MotifDesktopPaneUI();
    }

    public MotifDesktopPaneUI() {
    }

    protected void installDesktopManager() {
	if(desktop.getDesktopManager() == null) {
	    desktopManager = new MotifDesktopManager();
	    desktop.setDesktopManager(desktopManager);
            ((MotifDesktopManager)desktopManager).adjustIcons(desktop);
	}
    }

    public Insets getInsets(JComponent c) {return new Insets(0,0,0,0);}

////////////////////////////////////////////////////////////////////////////////////
///  DragPane class
////////////////////////////////////////////////////////////////////////////////////
    private class DragPane extends JComponent {
	public void paint(Graphics g) {
	    g.setColor(Color.darkGray);
	    g.drawRect(0, 0, getWidth()-1, getHeight()-1);
	}
    };

////////////////////////////////////////////////////////////////////////////////////
///  MotifDesktopManager class
////////////////////////////////////////////////////////////////////////////////////
    private class MotifDesktopManager extends DefaultDesktopManager implements Serializable {
        JComponent dragPane;
        boolean usingDragPane = false;
        private transient JLayeredPane layeredPaneForDragPane;
        int iconWidth, iconHeight;

    // PENDING(klobad) this should be optimized
    public void setBoundsForFrame(JComponent f, int newX, int newY, 
			int newWidth, int newHeight) {
	if(!usingDragPane) {
            boolean didResize;
            didResize = (f.getWidth() != newWidth || f.getHeight() != newHeight);
	    Rectangle r = f.getBounds();
	    f.setBounds(newX, newY, newWidth, newHeight);		
	    SwingUtilities.computeUnion(newX, newY, newWidth, newHeight, r);
	    f.getParent().repaint(r.x, r.y, r.width, r.height);
	    if(didResize) {
	        f.validate();
  	    }
	} else {
	    Rectangle r = dragPane.getBounds();
	    dragPane.setBounds(newX, newY, newWidth, newHeight);		
	    SwingUtilities.computeUnion(newX, newY, newWidth, newHeight, r);
	    dragPane.getParent().repaint(r.x, r.y, r.width, r.height);
	}
    }

    public void beginDraggingFrame(JComponent f) {	
	usingDragPane = false;
	if(f.getParent() instanceof JLayeredPane) {
	    if(dragPane == null)
		dragPane = new DragPane();
	    layeredPaneForDragPane = (JLayeredPane)f.getParent();
	    layeredPaneForDragPane.setLayer(dragPane, Integer.MAX_VALUE);
	    dragPane.setBounds(f.getX(), f.getY(), f.getWidth(), f.getHeight());
	    layeredPaneForDragPane.add(dragPane);
	    usingDragPane = true;
	}
    }

    public void dragFrame(JComponent f, int newX, int newY) {
	setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());
    }

    public void endDraggingFrame(JComponent f) {
	if(usingDragPane) {
	    layeredPaneForDragPane.remove(dragPane);
	    usingDragPane = false;
            if (f instanceof JInternalFrame) {
                setBoundsForFrame(f, dragPane.getX(), dragPane.getY(), 
                        dragPane.getWidth(), dragPane.getHeight());
            } else if (f instanceof JInternalFrame.JDesktopIcon) {
                adjustBoundsForIcon((JInternalFrame.JDesktopIcon)f,
                        dragPane.getX(), dragPane.getY());
            }
	}
    }

    public void beginResizingFrame(JComponent f, int direction) {
	usingDragPane = false;
	if(f.getParent() instanceof JLayeredPane) {
	    if(dragPane == null)
		dragPane = new DragPane();
	    JLayeredPane p = (JLayeredPane)f.getParent();
	    p.setLayer(dragPane, Integer.MAX_VALUE);
	    dragPane.setBounds(f.getX(), f.getY(), 
				f.getWidth(), f.getHeight());
	    p.add(dragPane);
	    usingDragPane = true;
	}
    }

    public void resizeFrame(JComponent f, int newX, int newY, 
				int newWidth, int newHeight) {
	setBoundsForFrame(f, newX, newY, newWidth, newHeight);
    }

    public void endResizingFrame(JComponent f) {
	if(usingDragPane) {
	    JLayeredPane p = (JLayeredPane)f.getParent();
	    p.remove(dragPane);
	    usingDragPane = false;
            setBoundsForFrame(f, dragPane.getX(), dragPane.getY(), 
				dragPane.getWidth(), dragPane.getHeight());
	}
    }

        public void iconifyFrame(JInternalFrame f) {
            JInternalFrame.JDesktopIcon icon = f.getDesktopIcon();
            Point p = icon.getLocation();
            adjustBoundsForIcon(icon, p.x, p.y);
            super.iconifyFrame(f);
        }

        /**
         * Change positions of icons in the desktop pane so that
         * they do not overlap
         */
        protected void adjustIcons(JDesktopPane desktop) {
            // We need to know Motif icon size
            JInternalFrame.JDesktopIcon icon = new JInternalFrame.JDesktopIcon(
                    new JInternalFrame());
            Dimension iconSize = icon.getPreferredSize();
            iconWidth = iconSize.width;
            iconHeight = iconSize.height;

            JInternalFrame[] frames = desktop.getAllFrames();
            for (int i=0; i<frames.length; i++) {
                icon = frames[i].getDesktopIcon();
                Point ip = icon.getLocation();
                adjustBoundsForIcon(icon, ip.x, ip.y);
            }
        }

        /**
         * Change positions of icon so that it doesn't overlap
         * other icons.
         */
        protected void adjustBoundsForIcon(JInternalFrame.JDesktopIcon icon,
                int x, int y) {
            JDesktopPane c = icon.getDesktopPane();

            int maxy = c.getHeight();
            int w = iconWidth;
            int h = iconHeight;
            c.repaint(x, y, w, h);
            x = x < 0 ? 0 : x;
            y = y < 0 ? 0 : y;

            /* Fix for disappearing icons. If the y value is maxy then this
             * algorithm would place the icon in a non-displayed cell.  Never
             * to be ssen again.*/
            y = y >= maxy ? (maxy - 1) : y;

            /* Compute the offset for the cell we are trying to go in. */
            int lx = (x / w) * w;
            int ygap = maxy % h;
            int ly = ((y-ygap) / h) * h + ygap;

            /* How far are we into the cell we dropped the icon in. */
            int dx = x - lx;
            int dy = y - ly;

            /* Set coordinates for the icon. */
            x = dx < w/2 ? lx: lx + w;
            y = dy < h/2 ? ly: ((ly + h) < maxy ? ly + h: ly);

            while (getIconAt(c, icon, x, y) != null) {
                x += w;
            }

            /* Cancel the move if the x value was moved off screen. */
            if (x > c.getWidth()) {
                return;
            }
            if (icon.getParent() != null) {
                setBoundsForFrame(icon, x, y, w, h);
            } else {
                icon.setLocation(x, y);
            }
        }

        protected JInternalFrame.JDesktopIcon getIconAt(JDesktopPane desktop,
            JInternalFrame.JDesktopIcon icon, int x, int y) {

            JInternalFrame.JDesktopIcon currentIcon = null;
            Component[] components = desktop.getComponents();

            for (int i=0; i<components.length; i++) {
                Component comp = components[i];
                if (comp instanceof JInternalFrame.JDesktopIcon &&
                    comp != icon) {

                    Point p = comp.getLocation();
                    if (p.x == x && p.y == y) {
                        return (JInternalFrame.JDesktopIcon)comp;
                    }
                }
            }
            return null;
        }
    }; /// END of MotifDesktopManager
}
