Package watch.sound.swing.ui.cdi

Source Code of watch.sound.swing.ui.cdi.CDIDesktop$IconifiedFrameButton

package watch.sound.swing.ui.cdi;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

/**
* a desktop with additional functions:
* <li>iconified frame goes to a toolbar-like place holder
* <li>iconified frame group together based on the frame icon
* <li>configurable system popupmenu registered to both main window and toolbar
* <li>internal frames can be merged to create customized subwindow
* <li>panels within merged window can register to share a common channel
* <li>internal frames can be tear off to be a seperate window, which can also be
* docked back
* @author Hanning Ni
* @reviewer
*/
public class CDIDesktop extends JPanel implements PopupMenuListener{
   private static final long serialVersionUID = 1L;
  private static String IMAGE_DIR =  "smile/me/control/mdi/resource" + java.io.File.separator;
  private static ImageIcon ICONIZE_BUTTON_ICON = new ImageIcon(IMAGE_DIR+"iconize.gif");
  private static ImageIcon CLOSE_BUTTON_ICON = new ImageIcon(IMAGE_DIR+"close.gif");
  private static ImageIcon MAXIMIZE_BUTTON_ICON = new ImageIcon(IMAGE_DIR+"maximize.gif");
  private static ImageIcon MINIMIZE_BUTTON_ICON = new ImageIcon(IMAGE_DIR+"minimize.gif");

  private Set ids = new HashSet();
   private final int OVERLAP = 2;
   private final float OVERLAP_DEGREE = 1.2f;
  protected HashMap map = new HashMap();
  protected JDesktopPane desktop;
  protected CDIToolbar       controlPanel;
  protected Map  icon2button = new HashMap();
  //for merged frame only
  protected Map  icon2button2 = new HashMap();
  protected Map  btn2frames = new HashMap();
  protected Map  id2JFrame = new HashMap();
  protected JPopupMenu systemPopup = new JPopupMenu();
  protected AbstractAction  closeAll, disambleAll, dockBackAll   ;
  protected JMenuItem  iconifyAll;
  public CDIDesktop(){
    setLayout(new BorderLayout());
    desktop = new JDesktopPane();
    add(desktop, BorderLayout.CENTER);
    JPanel mousetrap = new JPanel();
    desktop. add(mousetrap,
            new Integer(Integer.MIN_VALUE));
    mousetrap.setOpaque(false);
    mousetrap.setBounds(0,0,1000,1000);
    controlPanel = new CDIToolbar();
    add(controlPanel, BorderLayout.SOUTH);
    disambleAll = new AbstractAction("Disamble All in main frame"){
       public void actionPerformed(ActionEvent e) {
         disambleAll();
      }};
    systemPopup.add(disambleAll);
    dockBackAll = new AbstractAction("Dockback All"){
       public void actionPerformed(ActionEvent e) {
         dockBackAll();
      }};
    systemPopup.add(dockBackAll);
    iconifyAll = new JMenuItem(new AbstractAction(){
       public void actionPerformed(ActionEvent e) {
         iconifyAll("Iconify All".equals(iconifyAll.getText()));
      }});
    systemPopup.add(iconifyAll);
    closeAll = new AbstractAction("Close All"){
       public void actionPerformed(ActionEvent e) {
           closeAll();   
       }};
    systemPopup.add(closeAll);

    systemPopup.addPopupMenuListener(this);
    MouseListener l = new MouseAdapter(){
       public void mousePressed(MouseEvent e) {
         show(e);
       }
       public void mouseClicked(MouseEvent e) {
         show(e);
       }
       public void mouseReleased(MouseEvent e) {
         show(e);
      }
       private void show(MouseEvent e){
           if(e.isPopupTrigger()){
            if(e.getComponent() == controlPanel
             iconifyAll.setText("Deiconify All");
            else
             iconifyAll.setText("Iconify All");
           systemPopup.show(e.getComponent(), e.getPoint().x, e.getPoint().y);
           }
       }
     };
     mousetrap.addMouseListener(l);
    controlPanel.addMouseListener(l);
   
   
   
      UIManager.put("InternalFrame.maximizeIcon",MAXIMIZE_BUTTON_ICON);
      UIManager.put("InternalFrame.minimizeIcon",MINIMIZE_BUTTON_ICON);
      UIManager.put("InternalFrame.iconifyIcon",ICONIZE_BUTTON_ICON);
      UIManager.put("InternalFrame.closeIcon",CLOSE_BUTTON_ICON);
   }
  /**
   * close all open windows, include
   * <li> shown frame inside main window
   * <li> iconified window
   * <li> tear off window
   *
   */
  protected void closeAll() {
    for(Iterator it = id2JFrame.values().iterator(); it.hasNext();){
      DockableJFrame f = (DockableJFrame)it.next();
      f.forceClose();
    }
    id2JFrame.clear();
   
     for(Iterator it = btn2frames.keySet().iterator(); it.hasNext();){
       List fs = (List)btn2frames.get(it.next());
       for(Iterator itt = fs.iterator(); itt.hasNext();){
         CDIInternalFrame f = (CDIInternalFrame)itt.next();
         f.dispose();
       }
      }
     controlPanel.removeAllIcons();
     btn2frames.clear();
     icon2button .clear();
     icon2button2 .clear();
      
      
       closeAllFramesWithinDesktop();
  }
  /**
   * set toolbar floatable. default is false
   * @param  floatable
   */
  public void setToolbarFloatable(boolean floatable){
    controlPanel.setFloatable(floatable);
  }
  /**
   * iconify all shown frames within main window, or deiconfiy all iconfied
   * frames back into main window
   * @param iconify
   */
  protected void iconifyAll(boolean iconify) {
     if(iconify){
       CDIInternalFrame[] fs = getAllShownFramesWithinDesktop();
        for(int i = fs.length -1; i >=0;i--){
          addIconifiedFrame(fs[i]);
        }
     }else{
       for(Iterator it = btn2frames.keySet().iterator(); it.hasNext();){
         List fs = (List)btn2frames.get(it.next());
         for(Iterator itt = fs.iterator(); itt.hasNext();){
           CDIInternalFrame f = (CDIInternalFrame)itt.next();
           f.setVisible(true);
         }
         fs.clear();
       }
       controlPanel.removeAllIcons();
       btn2frames.clear();
       icon2button .clear();
       icon2button2 .clear();
     }
  }
  /**
   *  dock back all tear off window into main window
   */
  protected void dockBackAll() {
    List ids = new ArrayList(id2JFrame.values());
    for(Iterator it = ids.iterator(); it.hasNext();){
      DockableJFrame f = (DockableJFrame)it.next();
      dockBack(f,f.id);
      f.forceClose();
    }
  }
  /**
    * disamble all merged frames within main window
   */
  protected void disambleAll() {
    CDIInternalFrame[] fs = getAllMergedShownFramesWithinDesktop();
    for(int i = fs.length -1; i >=0;i--){
      disemble(fs[i]);
    }
  }
  /**
   * tear off given internal frame
   * @param comp
   */
  public void tearOff(CDIInternalFrame comp){
      cacheLoc(comp.getId(), comp.getBounds());
      DockableJFrame frame = new DockableJFrame(comp.getProperties(), this);
      frame.setContentPane(comp.getContentPane());
      frame.setBounds(comp.getBounds() );
      frame.setVisible(true);
      id2JFrame.put(comp.getProperties(), frame);
      comp.close();
  }
 
  /**
   * dock back tear-offed frame,create a new internal frame and configure it
   * with given property setting
   * @param frame
   * @param id
   */
  public void dockBack(JFrame frame, CDIFrameProperties id){
     id2JFrame.remove(id);
     backToFrame(frame.getContentPane(),id);
   }
  private void backToFrame(Container content, CDIFrameProperties id){
     CDIInternalFrame iframe =
       new CDIInternalFrame(id.getTitle(), this);
     iframe.setProperties(id);
     iframe.setContentPane(content);
     iframe.setBounds( restoreLoc(id.getId()));
     addInternalFrame(iframe);
     iframe.show();  
  }
  /**
   * merge two internal frames, new frame will
   * <li> has title from both frames
   * <li> new id
   * <li> frame icon from source1
   * <li> location of both frames can saved
   * @param source1
   * @param source2
   * @param orientation
   */
  public void mergablePanel(CDIInternalFrame source1,
      CDIInternalFrame source2,
            int orientation){
     cacheLoc(source1.getId(), source1.getBounds());
     cacheLoc(source2.getId(), source2.getBounds());
    
     MergablePanel mergedPanel = new MergablePanel(
              (JComponent)source1.getContentPane(),
              source1.getProperties(),
              (JComponent)source2.getContentPane(),
              source2.getProperties(),
              orientation);
     CDIFrameProperties p1 =  source1.getProperties();
     CDIFrameProperties p2 =  source2.getProperties();
     CDIFrameProperties p = new CDIFrameProperties();
     p.setFrameIcon(p1.getFrameIcon());
     p.setTitle(p1.getTitle() + ":" + p2.getTitle());
     p.setMergable(true);
     p.setMergeStatus(true);
     CDIInternalFrame iframe =
       new CDIInternalFrame("", this);
     String id = iframe.getId();
     p.setId(id);
     iframe.setProperties(p);
     iframe.setContentPane(mergedPanel);
     Rectangle dest = new Rectangle();
     Rectangle.union(source1.getBounds(), source2.getBounds(), dest);
     iframe.setBounds(dest);
     cacheLoc(p.getId(), dest);
     addInternalFrame(iframe);
     iframe.show();  
    
     source1.close();
     source2.close();
  }
 
  /**
   * dissemble merged frame comp, if comp is not merged one, do
   * nothing
   * @param comp
   */
  public void disemble(CDIInternalFrame comp){
    if(!comp.isMergedStatus())
      return;
    Container content = comp.getContentPane();
    if(content instanceof MergablePanel)
      disemble((MergablePanel)content);
    comp.close();
  }
 
  private void disemble(MergablePanel panel) {
    Container p = (Container)panel.getSplitPane().getLeftComponent();
    if(p instanceof MergablePanel)
      disemble((MergablePanel)p);
    else{
      CDIFrameProperties afp  = panel.getProperties1();
      afp.setMergable(false);
      backToFrame(p, afp);
    }
    p = (Container)panel.getSplitPane().getRightComponent();
    if(p instanceof MergablePanel)
      disemble((MergablePanel)p);
    else{
      CDIFrameProperties afp  = panel.getProperties2();
      afp.setMergable(false);
      backToFrame(p, afp);
    }
  }
  /**
   * add internal frame to desktop's main window
   * @param comp
   */
  public void addInternalFrame(CDIInternalFrame comp){
    desktop.add(comp);
  }
  /**
   * add internal frame to toolbar as iconified one
   * @param comp
   */
  public void addIconifiedFrame(CDIInternalFrame comp){
   
    Icon icon = comp.getFrameIcon();
    IconifiedFrameButton btn = null;
    if(comp.isMergedStatus())
      btn = (IconifiedFrameButton)icon2button2.get(icon);
    else
      btn = (IconifiedFrameButton)icon2button.get(icon);
    if(btn == null){
      btn = new IconifiedFrameButton(icon);
      if(comp.isMergedStatus())
        icon2button2.put(icon, btn);
      else
        icon2button.put(icon, btn);
       controlPanel.add(!comp.isMergedStatus(), btn);
    }
    List frames = (List)btn2frames.get(btn);
    if(frames == null){
      frames = new ArrayList();
      btn2frames.put(btn, frames);
    }
   
    if(!frames.contains(comp))
        frames.add(comp);
   
    btn.setNeedArraw(frames.size() > 1);
    comp.setVisible(false);
  }
  /**
   * cache the location of given id
   * @param id is id of the frame, which will keep unchanged during tearoff, iconify and
   * deiconify status
   * @param frame
   */
  public void cacheLoc(String id, Rectangle frame){
    map.put(id, frame);
  }
  /**
   * restore location for the frame of given id
   * @param id
   * @return
   */
  public Rectangle restoreLoc(String id){
    return (Rectangle)map.get(id);
  }

  /**
   * create unique id
   * @return
   */
  public synchronized  String getNextAvailableId() {
    String id =  "" + System.currentTimeMillis();
    Random r = new Random();
    while(ids.contains(id)){
      id = r.nextInt(1000000) + "";
    }
    ids.add(id);
     return id;
  }
 
 
  private class IconifiedFrameButton extends JButton implements ActionListener  {
     private static final long serialVersionUID = 1L;
    Dimension mdim;
        boolean   needArraw;
        Icon originalIcon;
        Icon arrawIcon;
      public IconifiedFrameButton( Icon ii) {
        super(ii);
        originalIcon = ii;
        mdim = new Dimension(ii.getIconWidth(), ii.getIconHeight());
        setContentAreaFilled(false);
        setBorder(null);
        addActionListener(this);
       }
      public boolean isFocusTraversable() { return false; }
      public void requestFocus() {};
      public Dimension getPreferredSize() {
        return mdim;
      }

      public Dimension getMinimumSize() {
        return mdim;
      }

      public Dimension getMaximumSize() {
        return mdim;
      }
    public boolean isNeedArraw() {
      return needArraw;
    }
    public void setNeedArraw(boolean needArraw) {
       this.needArraw = needArraw;
       if(needArraw){
         if(arrawIcon == null)
           arrawIcon = new ImageIconWithArraw(originalIcon);
         setIcon(arrawIcon);
       }else{
         setIcon(originalIcon);
       }
       mdim = new Dimension(getIcon().getIconWidth(), getIcon().getIconHeight());
       controlPanel.repaint();
    }
    public void actionPerformed(ActionEvent e) {
       final List frames = (List)btn2frames.get(this);
       if(frames == null){
         return ;//error??
       }else if(frames.size() == 1 ){
         CDIInternalFrame f = (CDIInternalFrame)
                        frames.get(0);
         frames.remove(f);
         if(f.isMergedStatus())
             icon2button2.remove(f.getFrameIcon());
         else
           icon2button.remove(f.getFrameIcon());
         controlPanel.remove(this);
         controlPanel.repaint();
         btn2frames.remove(this);
         f.setVisible(true);
         return;
       }else{
         final JPopupMenu menu = new JPopupMenu();
         for(int i =0;i < frames.size();i++){
           final CDIInternalFrame f = (CDIInternalFrame)
                    frames.get(i);
           JMenuItem item = new JMenuItem(f.getTitle().trim().length() ==0 ?
               "frame " + i : f.getTitle());
           item.addActionListener(new ActionListener(){
                      public void actionPerformed(ActionEvent e) {
                         frames.remove(f);
                         setNeedArraw(frames.size()>1);
                         f.setVisible(true);
            }}  );
           menu.add(item);
         }
               SwingUtilities.invokeLater(new Runnable(){
            public void run() {
              menu.show( IconifiedFrameButton.this,
                     0,
                     IconifiedFrameButton.this.getHeight());
            }});
            
       }
       //
     
    }
    }
 
 
    private class ImageIconWithArraw    implements Icon{
       Icon icon;
        public ImageIconWithArraw( Icon icon){
          this.icon = icon;
        }
    public int getIconHeight() {
       return icon.getIconHeight();
    }

    public int getIconWidth() {
       return icon.getIconWidth() + 10;
    }

      public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
            icon.paintIcon(c, g,x, y);
            g.translate(icon.getIconWidth() + 4 , icon.getIconHeight() /2 -3);
            g.fillPolygon(new int[]{0,4,2}, new int[]{0,0,3}, 3);
            g.translate(-icon.getIconWidth() - 4 , -icon.getIconHeight() /2 +3);
      }
     
    }

    /**
     * check if there are internalframe is mergable and
     * is  at the merge location
     * @param frame
     */
  public boolean tryMerge(CDIInternalFrame frame) {
    Rectangle loc = frame.getBounds();
    JInternalFrame[] frames = desktop.getAllFrames();
    for(int i = frames.length -1; i >=0;i--){
      CDIInternalFrame f  = (CDIInternalFrame)frames[i];
      if(f == frame || !f.isVisible() || !f.isMergable())
        continue;
      Rectangle loc2 = f.getBounds();
      if(Math.abs(loc.x+ loc.width - loc2.x ) < OVERLAP){
        if( overlap(loc.y, loc.y + loc.height,
                loc2.y, loc2.y + loc2.height)){
          mergablePanel(frame, f, JSplitPane.HORIZONTAL_SPLIT);
          return true;
        }
      }else  if(Math.abs(loc.y+ loc.height - loc2.y ) < OVERLAP){
        if( overlap(loc.x, loc.x + loc.width,
              loc2.x, loc2.x + loc2.width)){
          mergablePanel(frame, f, JSplitPane.VERTICAL_SPLIT);
          return true;
          }
        }else if(Math.abs(loc2.x+ loc2.width - loc.x ) < OVERLAP){
        if( overlap(loc2.y, loc2.y + loc2.height,
                loc .y, loc .y + loc .height)){
          mergablePanel(f, frame,  JSplitPane.HORIZONTAL_SPLIT);
          return true;
        }
      }else  if(Math.abs(loc2.y+ loc2.height - loc .y ) < OVERLAP){
        if( overlap(loc2.x, loc2.x + loc2.width,
              loc .x, loc .x + loc .width)){
          mergablePanel(f,frame,  JSplitPane.VERTICAL_SPLIT);
          return true;
          }
        }
    }
    return false;
  }
 
  /**
   * check overlap between [x1,y1],[x2,y2]
   * and overlap is great than 90% of smaller one
   * @param x1
   * @param y1
   * @param x2
   * @param y2
   * @return
   */
  private boolean overlap(int x1, int y1, int x2, int y2){
    float overlapLen = (Math.min(y1,y2) -Math.max(x1, x2))*
                                    OVERLAP_DEGREE;
    return overlapLen > y1-x1 || overlapLen > y2-x2;
   }
 
 
 
  /**
   * dispath event to all SmileGroupChangableI components within
   * the toplevel container which contains eventSource
   * <p>event will not get dispatched if
   * <li> oldValue and newValue are the same
   * @param groupInterface the panel the event original comes from
   * @param eventSource control which fire event
   * @param source  object whose property changed
   * @param property
   * @param oldValue
   * @param newValue
   */
  public static void dispatchGroupEvent(
      CDIGroupChangableI groupInterface,
      Container eventSource,
      Object source,
            String property,
            Object oldValue,
            Object newValue){
    if(oldValue == null && newValue == null)
      return;
    if(newValue != null && newValue.equals(oldValue))
            return;
    Container parent = null;
    Container kid = eventSource;
    while( (parent = SwingUtilities.getAncestorOfClass(MergablePanel.class, kid))
        != null){
      kid = parent;
    }
    parent = kid;
    dispatchGroupEvent2( parent,
        groupInterface, eventSource, source,property,oldValue,newValue);
  }
  /**
   * dispath event to all SmileGroupChangableI components within
   * the toplevel container comp
   * <p>event will not get dispatched if
   * <li> oldValue and newValue are the same
   * <li> comp is null
   * <li> current component is groupInterface itself
   * @param comp  top level component
   * @param groupInterface the panel the event original comes from
   * @param eventSource control which fire event
   * @param source  object whose property changed
   * @param property
   * @param oldValue
   * @param newValue
   */
  public static void dispatchGroupEvent2(Container comp,
      CDIGroupChangableI groupInterface,
      Container eventSource,
      Object source,
            String property,
            Object oldValue,
            Object newValue){
    if(comp == null)
      return;
    if(oldValue == null && newValue == null)
      return;
    if(newValue != null && newValue.equals(oldValue))
            return;
    if(comp instanceof CDIGroupChangableI &&
       comp != groupInterface){
      ((CDIGroupChangableI)comp).groupChangeEventReceived(
           eventSource, source, property, oldValue, newValue);
    }
    Component[] childs = comp.getComponents();
    for(int i = childs.length -1; i >=0;i--){
      if(childs[i] instanceof Container){
        dispatchGroupEvent2( (Container)childs[i],
            groupInterface, eventSource, source,property,oldValue,newValue);
      }
    }
  }
  /**
   * get all shown internal frames winthin the main window
   * @return
   */
  public CDIInternalFrame[] getAllShownFramesWithinDesktop(){
    JInternalFrame[] fs = desktop.getAllFrames();
    List sfs = new ArrayList();
    for(int i = 0 ; i < fs.length;i++){
      if(fs[i].isValid() && fs[i].isVisible() && (fs[i] instanceof CDIInternalFrame))
        sfs.add(fs[i]);
    }
    return (CDIInternalFrame[]) sfs.toArray(new CDIInternalFrame[0]);
   }
  /**
   * get all merged internal frames which is shown in the main window
   * @return
   */
  public CDIInternalFrame[] getAllMergedShownFramesWithinDesktop(){
    JInternalFrame[] fs = desktop.getAllFrames();
    List sfs = new ArrayList();
    for(int i = 0 ; i < fs.length;i++){
      if(fs[i] instanceof CDIInternalFrame &&
        ((CDIInternalFrame)fs[i]).isMergedStatus())
        sfs.add(fs[i]);
    }
    return (CDIInternalFrame[]) sfs.toArray(new CDIInternalFrame[0]);
   }
  /**
   * close all frames within main window
   */
  public void closeAllFramesWithinDesktop(){
    JInternalFrame[] fs = desktop.getAllFrames();
     for(int i = 0 ; i < fs.length;i++){
       fs[i].dispose();
    }
  }
  /**
   * get a system popup menu
   * @return
   */
  public JPopupMenu getSystemPopup() {
    return systemPopup;
  }
  public void popupMenuCanceled(PopupMenuEvent e) { }
  public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
  /**
   * the place to configure system popup menu
   */
  public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    closeAll.setEnabled( getAllShownFramesWithinDesktop().length +
                     id2JFrame.size() + icon2button.size() +
                     icon2button2.size() > 0;
    dockBackAll.setEnabled(id2JFrame.size() >0);
    disambleAll.setEnabled(getAllMergedShownFramesWithinDesktop().length +
        icon2button2.size() >0);
    if(closeAll.isEnabled() ){
      if("Deiconify All".equals(iconifyAll.getText())){
        iconifyAll.setEnabled(icon2button.size() +  icon2button2.size() > 0);
      }else{
        iconifyAll.setEnabled(getAllShownFramesWithinDesktop().length >0);
      }
     }else{
      iconifyAll.setEnabled(false);
    }
   }
}
TOP

Related Classes of watch.sound.swing.ui.cdi.CDIDesktop$IconifiedFrameButton

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.