2288d72bd03d70cc090ea4bca560d9cfa35b03d8
[jalview.git] / src / jalview / gui / SplitFrame.java
1 package jalview.gui;
2
3 import jalview.jbgui.GSplitFrame;
4
5 import java.awt.Component;
6 import java.awt.MouseInfo;
7 import java.awt.Point;
8 import java.awt.Rectangle;
9 import java.awt.Toolkit;
10 import java.awt.event.ActionEvent;
11 import java.awt.event.KeyAdapter;
12 import java.awt.event.KeyEvent;
13 import java.awt.event.KeyListener;
14 import java.util.Map.Entry;
15
16 import javax.swing.AbstractAction;
17 import javax.swing.JComponent;
18 import javax.swing.JMenuItem;
19 import javax.swing.KeyStroke;
20 import javax.swing.event.InternalFrameAdapter;
21 import javax.swing.event.InternalFrameEvent;
22
23 public class SplitFrame extends GSplitFrame
24 {
25   private static final long serialVersionUID = 1L;
26
27   public SplitFrame(JComponent top, JComponent bottom)
28   {
29     super(top, bottom);
30     init();
31   }
32
33   /**
34    * Initialise this frame.
35    */
36   protected void init()
37   {
38     setSize(AlignFrame.DEFAULT_WIDTH, Desktop.instance.getHeight() - 20);
39
40     addCloseFrameListener();
41     
42     addKeyListener();
43
44     addKeyBindings();
45
46   }
47
48   /**
49    * Add a listener to tidy up when the frame is closed.
50    */
51   protected void addCloseFrameListener()
52   {
53     addInternalFrameListener(new InternalFrameAdapter()
54     {
55       @Override
56       public void internalFrameClosed(InternalFrameEvent evt)
57       {
58         if (getTopComponent() instanceof AlignFrame)
59         {
60           ((AlignFrame) getTopComponent())
61                   .closeMenuItem_actionPerformed(true);
62         }
63         if (getBottomComponent() instanceof AlignFrame)
64         {
65           ((AlignFrame) getBottomComponent())
66                   .closeMenuItem_actionPerformed(true);
67         }
68       };
69     });
70   }
71
72   /**
73    * Add a key listener that delegates to whichever split component the mouse is
74    * in (or does nothing if neither).
75    */
76   protected void addKeyListener()
77   {
78     // TODO Key Bindings rather than KeyListener are recommended for Swing
79     addKeyListener(new KeyAdapter() {
80
81       @Override
82       public void keyPressed(KeyEvent e)
83       {
84         Component c = getComponentAtMouse();
85         if (c != null)
86         {
87           for (KeyListener kl : c.getKeyListeners())
88           {
89             kl.keyPressed(e);
90           }
91         }
92       }
93
94       @Override
95       public void keyReleased(KeyEvent e)
96       {
97         Component c = getComponentAtMouse();
98         if (c != null)
99         {
100           for (KeyListener kl : c.getKeyListeners())
101           {
102             kl.keyReleased(e);
103           }
104         }
105       }
106       
107     });
108   }
109
110   /**
111    * Returns the split pane component the mouse is in, or null if neither.
112    * 
113    * @return
114    */
115   protected Component getComponentAtMouse()
116   {
117     Point loc = MouseInfo.getPointerInfo().getLocation();
118     
119     if (isIn(loc, getTopComponent())) {
120       return getTopComponent();
121     }
122     else if (isIn(loc, getBottomComponent()))
123     {
124       return getBottomComponent();
125     }
126     return null;
127   }
128
129   private boolean isIn(Point loc, JComponent comp)
130   {
131     Point p = comp.getLocationOnScreen();
132     Rectangle r = new Rectangle(p.x, p.y, comp.getWidth(), comp.getHeight());
133     return r.contains(loc);
134   }
135
136   /**
137    * Set key bindings (recommended for Swing over key accelerators).
138    */
139   private void addKeyBindings()
140   {
141     /*
142      * Bind Cmd-Alt/I (invert column selection)
143      */
144     // If AlignFrame exposed a Map of Action objects by key,
145     // we could delegate all key bindings with a single lookup
146     this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
147             KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_I, Toolkit
148                     .getDefaultToolkit().getMenuShortcutKeyMask()
149                     | java.awt.event.KeyEvent.ALT_MASK, false),
150             "INV_SEQ_SEL");
151     this.getActionMap().put("INV_SEQ_SEL", new AbstractAction()
152     {
153       @Override
154       public void actionPerformed(ActionEvent e)
155       {
156         Component c = getComponentAtMouse();
157         if (c instanceof AlignFrame)
158         {
159           ((AlignFrame) c).invertColSel_actionPerformed(null);
160         }
161       }
162     });
163     if (getTopComponent() instanceof AlignFrame)
164     {
165       for (Entry<KeyStroke, JMenuItem> acc : ((AlignFrame) getTopComponent())
166               .getAccelerators().entrySet())
167       {
168
169         final KeyStroke ks = acc.getKey();
170         this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, ks);
171         this.getActionMap().put(ks, new AbstractAction()
172         {
173           @Override
174           public void actionPerformed(ActionEvent e)
175           {
176             Component c = getComponentAtMouse();
177             if (c instanceof AlignFrame)
178             {
179               ((AlignFrame) c).getAccelerators().get(ks)
180                       .getActionListeners()[0].actionPerformed(null);
181             }
182           }
183         });
184       }
185     }
186   }
187 }