/*
* Copyright (C) 2007, 2008 Clam <clamisgood@gmail.com>
* Copyright (C) 2007, 2009 IsmAvatar <IsmAvatar@gmail.com>
* Copyright (C) 2008 Quadduc <quadduc@gmail.com>
*
* This file is part of LateralGM.
* LateralGM is free software and comes with ABSOLUTELY NO WARRANTY.
* See LICENSE for details.
*/
package org.lateralgm.components.mdi;
import java.awt.Component;
import java.awt.Rectangle;
import java.beans.PropertyVetoException;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import javax.swing.DesktopManager;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JScrollPane;
import org.lateralgm.main.WeakArrayList;
import org.lateralgm.subframes.InstantiableResourceFrame;
public class MDIPane extends JDesktopPane
{
private static final long serialVersionUID = 1L;
private int offset = -1;
private static final int OFFSET_WIDTH = 24;
private static final int OFFSET_HEIGHT = 24;
private static final int OFFSET_MAX = 9;
private final MDIMenu menu;
public static final String SELECTED_FRAME_PROPERTY = "selectedFrame";
private final WeakHashMap<Component,WeakArrayList<Component>> zMap;
public MDIMenu getMenu()
{
return menu;
}
public MDIPane()
{
setDesktopManager(new MDIManager(this));
menu = new MDIMenu(this);
zMap = new WeakHashMap<Component,WeakArrayList<Component>>();
}
public void setScrollPane(JScrollPane scroll)
{
MDIManager man = getMDIManager();
if (man != null) man.setScrollPane(scroll);
}
public void cascadeFrames()
{
offset = -1;
for (JInternalFrame f : getAllFrames())
{
if (f.isVisible() && !f.isIcon())
{
incrementOffset();
Rectangle r = f.getBounds();
r.x = offset * OFFSET_WIDTH;
r.y = offset * OFFSET_HEIGHT;
f.setBounds(r);
f.toFront();
try
{
f.setSelected(true);
}
catch (PropertyVetoException e)
{
e.printStackTrace();
}
}
}
resizeDesktop();
}
public void arrangeDesktopIcons()
{
int x = Integer.MAX_VALUE - 9000, y = getPreferredSize().height;
for (JInternalFrame f : getAllFrames())
{
if (f.isIcon())
{
Rectangle r = f.getDesktopIcon().getBounds();
if (x + r.width * 2 <= getPreferredSize().width)
x += r.width;
else
{
x = 0;
y -= r.height;
}
r.x = x;
r.y = y;
f.getDesktopIcon().setBounds(r);
}
}
resizeDesktop();
}
public void closeAll()
{
for (JInternalFrame f : getAllFrames())
{
if (f instanceof InstantiableResourceFrame<?,?>)
try
{
f.setClosed(true);
}
catch (PropertyVetoException e)
{
e.printStackTrace();
}
else
{
f.setVisible(false);
}
}
}
public void closeOthers()
{
if (getSelectedFrame() != null) for (JInternalFrame f : getAllFrames())
{
if (f != getSelectedFrame()) if (f instanceof InstantiableResourceFrame<?,?>)
try
{
f.setClosed(true);
}
catch (PropertyVetoException e)
{
e.printStackTrace();
}
else
{
f.setVisible(false);
}
}
}
public void iconizeAll()
{
for (JInternalFrame f : getAllFrames())
{
if (f.isVisible()) try
{
f.setIcon(true);
}
catch (PropertyVetoException e)
{
e.printStackTrace();
}
}
arrangeDesktopIcons();
}
public void setBounds(int x, int y, int w, int h)
{
super.setBounds(x,y,w,h);
resizeDesktop();
}
public MDIFrame add(MDIFrame f)
{
super.add(f);
incrementOffset();
Rectangle r = f.getBounds();
r.x = offset * OFFSET_WIDTH;
r.y = offset * OFFSET_HEIGHT;
f.setBounds(r);
return f;
}
public void remove(Component c)
{
super.remove(c);
resizeDesktop();
}
public void resizeDesktop()
{
MDIManager mg = getMDIManager();
if (mg != null) mg.resizeDesktop();
}
private void incrementOffset()
{
if (offset >= OFFSET_MAX)
offset = 0;
else
offset++;
}
public boolean isMaximum()
{
for (JInternalFrame f : getAllFrames())
if (f.isMaximum()) return true;
return false;
}
public void bringMaximumToTop()
{
if (!isMaximum()) return;
for (JInternalFrame f : getAllFrames())
if (f.isMaximum() && f instanceof MDIFrame && f.isVisible()) ((MDIFrame) f).toTop();
}
private MDIManager getMDIManager()
{
DesktopManager man = getDesktopManager();
if (man == null || !(man instanceof MDIManager)) return null;
return (MDIManager) man;
}
public void setSelectedFrame(JInternalFrame frame)
{
JInternalFrame old = getSelectedFrame();
super.setSelectedFrame(frame);
this.firePropertyChange(SELECTED_FRAME_PROPERTY,old,frame);
}
private void updateZChildren(Component p)
{
if (zMap == null) return;
int fi = getIndexOf(p);
int fl = getLayer(p);
int fp = getPosition(p);
WeakArrayList<Component> l = zMap.get(p);
if (l == null) return;
for (WeakReference<Component> cr : l)
{
Component c = cr.get();
int ci = c == null ? -1 : getIndexOf(c);
if (ci < 0 || ci <= fi) continue;
setLayer(c,fl,fp);
}
}
/**
* Adds given child component to the z list of components such
* that it will stay above the given parent component.
* This method is particularly useful for allowing a child to
* appear on top of a parent component without it monopolizing
* the z-space of the rest of the MDI (e.g. on top of everything)
* @param p The parent component to appear underneath
* @param c The child component to appear on top
*/
public void addZChild(Component p, Component c)
{
WeakArrayList<Component> l = zMap.get(p);
if (l == null)
{
l = new WeakArrayList<Component>();
zMap.put(p,l);
}
l.add(new WeakReference<Component>(c));
updateZChildren(p);
}
public void setLayer(Component c, int layer, int position)
{
super.setLayer(c,layer,position);
updateZChildren(c);
}
}