package org.freehep.application.mdi; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Point; import java.beans.PropertyVetoException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.Icon; import javax.swing.JDesktopPane; import javax.swing.JInternalFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.event.InternalFrameEvent; import org.freehep.application.Application; import org.freehep.swing.popup.HasPopupItems; import org.freehep.util.commanddispatcher.CommandProcessor; import org.freehep.util.commanddispatcher.CommandSourceAdapter; import org.freehep.util.commanddispatcher.CommandState; import org.freehep.util.commanddispatcher.CommandTargetManager; /** * A PageManager which manages its pages as InternalFrames on a Desktop * @author Tony Johnson (tonyj@slac.stanford.edu) * @version $Id: InternalFramePageManager.java 8584 2006-08-10 23:06:37Z duns $ */ public class InternalFramePageManager extends PageManager { public InternalFramePageManager() { setPageManagerType("Window"); } protected void show(PageContext page) { try { JInternalFrame frame = frameForPage(page); frame.moveToFront(); if (frame.isIcon()) frame.setIcon(false); frame.setSelected(true); } catch (PropertyVetoException x){} } protected Component getEmbodiment() { return top; } protected boolean close(PageContext page) { boolean ok = super.close(page); if (ok) ((JInternalFrame) map.remove(page)).dispose(); return ok; } protected void titleChanged(PageContext page) { frameForPage(page).setTitle(page.getTitle()); } protected void iconChanged(PageContext page) { frameForPage(page).setFrameIcon(page.getIcon()); } private JInternalFrame frameForPage(PageContext page) { return (JInternalFrame) map.get(page); } public PageContext openPage(Component c,String title,Icon icon, String type) { PageContext context = super.openPage(c, title, icon, type); JInternalFrame frame = new FrameWithContext(context); map.put(context,frame); top.add(frame); if (init) cascadeFrame(frame); frame.setVisible(true); super.firePageOpened(context); return context; } protected void init(List pages, PageContext selected) { Iterator i = pages.iterator(); while (i.hasNext()) { PageContext context = (PageContext) i.next(); JInternalFrame frame = new FrameWithContext(context); map.put(context,frame); top.add(frame); frame.setVisible(true); } if (selected != null) { try { frameForPage(selected).setSelected(true); } catch (java.beans.PropertyVetoException x) {} } super.init(pages,selected); } private void cascadeFrame(JInternalFrame frame) { Dimension paneSize = top.getSize(); Dimension frameSize = new Dimension(); frameSize.height = (int) (paneSize.height * m_yCascadeFraction); frameSize.width = (int) (paneSize.width * m_xCascadeFraction); Point position = new Point(); // at (0, 0) position.translate(m_nCascaded * m_xCascadeOffset, m_nCascaded * m_yCascadeOffset); frame.setLocation(position); frame.setPreferredSize(frameSize); frame.setSize(frameSize); m_nCascaded++; } void arrange(int index) { m_nCascaded = 0; JInternalFrame[] frames = top.getAllFrames(); // these are in reverse order from when they were last used JInternalFrame frame; // the current frame if (index == CASCADE) { for (int i = frames.length - 1; i >= 0;i--) { frame = frames[i]; if (!frame.isIcon()) { try { frames[i].setMaximum(false); cascadeFrame(frame); } catch (java.beans.PropertyVetoException x){} } } } else { final int numberOfWindows = getPageCount(); int nLeft = numberOfWindows; // Initially, the number left to put on the screen is the total number of frames. for (int i = 0; i < numberOfWindows; i++) { if (frames[i].isIcon()) nLeft--; // We don't count iconified frames. else { try { frames[i].setMaximum(false); } catch (java.beans.PropertyVetoException x) {nLeft--;} } } final int n = (int) Math.sqrt(nLeft); /* * In the case of horizontal tile, n is number of * columns; n is the number of rows in the case of * a vertical tile. */ if (n < 1) return; final int paneWidth = top.getSize().width; final int paneHeight = top.getSize().height; final boolean isHorizontal = (index == TILE_HORIZONTALLY); final int xTranslation_1 = (isHorizontal) ? paneWidth / n : 0; final int yTranslation_1 = (isHorizontal) ? 0 : paneHeight / n; /* * The above translations are used to go between rows * in a vertical tile and between rows in a horizontal * tile. */ int nThis; // number this row (vertical tile) or column (horizontal tile) int k = 0; // index for frames array, incremented as frames are accessed Dimension size = new Dimension(); // size of the current frame Point point = new Point(); // location of the current frame int xTranslation_2 = 0, yTranslation_2 = 0; /* * The above translations are used to go along rows * in a vertical tile and along rows in a horizontal * tile. */ if (isHorizontal) size.width = paneWidth / n; // n is the number of columns else size.height = paneHeight / n; // n is the number of rows for (int i = 0; i < n; i++) { point.setLocation(0, 0); point.translate(i * xTranslation_1, i * yTranslation_1); // translated to the starting point for this row (vert case) or column (horiz case) nThis = nLeft / (n - i); // n - i is the number or rows (vert case) or columns (horiz case) remaining nLeft -= nThis; if (isHorizontal) yTranslation_2 = size.height = paneHeight / nThis; // nThis is the number of rows in this column // yTranslation_2 is the amount of y translation between frames in this column // Leave xTranslation_2 as zero because there is no x transition while going along a column else xTranslation_2 = size.width = paneWidth / nThis; // nThis is the number of columns in this row // xTranslation_2 is the amount of x translation between frames in this row // Leave yTranslation_2 as zero because there is no y transition while traversing a row int j = 0; while (true) { do frame = frames[k++]; while (frame.isIcon() || frame.isMaximum()); // Don't include iconified frames. frame.setSize(new Dimension(size)); frame.setLocation(new Point(point)); if (++j < nThis) point.translate(xTranslation_2, yTranslation_2); // set up the point for the next frame in this column (horiz case) or row (vert case) else break; } } } } protected CommandProcessor createCommandProcessor() { return new InternalFrameCommandProcessor(); } protected void setActive(boolean active) { if (active) { map = new HashMap(); top = new MDIDesktopPane(); init = false; } else { map = null; top = null; } } private int m_nCascaded = 0; private boolean init = false; private final int m_xCascadeOffset = 20, m_yCascadeOffset = 20; private final float m_xCascadeFraction = 0.75F, m_yCascadeFraction = 0.75F; public static final int CASCADE = -3; public static final int TILE_HORIZONTALLY = -4; public static final int TILE_VERTICALLY = -5; private Map map; private JDesktopPane top; protected class MDIDesktopPane extends JDesktopPane implements HasPopupItems { public void doLayout() { super.doLayout(); if (!init) { arrange(CASCADE); init = true; } } public JPopupMenu modifyPopupMenu(JPopupMenu menu, Component source, Point p) { if (source == this) { CommandTargetManager cm = Application.getApplication().getCommandTargetManager(); JMenuItem cascade = new JMenuItem("Cascade"); cascade.setMnemonic('C'); cascade.setActionCommand("cascade"); cm.add(new CommandSourceAdapter(cascade)); menu.add(cascade); JMenuItem tileV = new JMenuItem("Tile Vertically"); tileV.setMnemonic('V'); tileV.setActionCommand("tileVertically"); cm.add(new CommandSourceAdapter(tileV)); menu.add(tileV); JMenuItem tileH = new JMenuItem("Tile Horizontally"); tileH.setMnemonic('H'); tileH.setActionCommand("tileHorizontally"); cm.add(new CommandSourceAdapter(tileH)); menu.add(tileH); JMenuItem close = new JMenuItem("Close All"); close.setMnemonic('A'); close.setActionCommand("closeAllPages"); cm.add(new CommandSourceAdapter(close)); menu.add(close); } else { InternalFramePageManager.this.modifyPopupMenu(menu, source,p); } return menu; } } private class FrameWithContext extends JInternalFrame { FrameWithContext(PageContext context) { super(context.getTitle(),true,true,true,true); this.context = context; setFrameIcon(context.getIcon()); setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); Component c = context.getPage(); if (c instanceof Container) setContentPane((Container) c); else getContentPane().add(c); } protected void fireInternalFrameEvent(int id) { switch (id) { case InternalFrameEvent.INTERNAL_FRAME_ICONIFIED: ManagedPage mp = getManagedPage(context.getPage()); if (mp != null) mp.pageIconized(); firePageEvent(context,PageEvent.PAGEICONIZED); getCommandProcessor().setChanged(); break; case InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED: mp = getManagedPage(context.getPage()); if (mp != null) mp.pageDeiconized(); firePageEvent(context,PageEvent.PAGEDEICONIZED); getCommandProcessor().setChanged(); break; case InternalFrameEvent.INTERNAL_FRAME_CLOSING: close(context); break; case InternalFrameEvent.INTERNAL_FRAME_ACTIVATED: fireSelectionChanged(context); } super.fireInternalFrameEvent(id); } private PageContext context; } class InternalFrameCommandProcessor extends PageManagerCommandProcessor { public void onCascade() { arrange(CASCADE); } public void onTileHorizontally() { arrange(TILE_HORIZONTALLY); } public void onTileVertically() { arrange(TILE_VERTICALLY); } public void onIconizeAll() { JInternalFrame[] frames = top.getAllFrames(); for (int i=0; i<frames.length; i++) { JInternalFrame frame = frames[i]; try { if (!frame.isIcon()) frame.setIcon(true); } catch (PropertyVetoException x) {} } } private boolean hasOpenPages() { JInternalFrame[] frames = top.getAllFrames(); for (int i=0; i<frames.length; i++) if (!frames[i].isIcon()) return true; return false; } public void enableCascade(CommandState state) { state.setEnabled(hasOpenPages()); } public void enableTileVertically(CommandState state) { state.setEnabled(hasOpenPages()); } public void enableTileHorizontally(CommandState state) { state.setEnabled(hasOpenPages()); } public void enableIconizeAll(CommandState state) { state.setEnabled(hasOpenPages()); } } }