[gui-dev] layout patch

Felix Berger <[email protected]> Sun, 27 Feb 2005 19:20:17 +0100
Newsgroups gmane.network.gnutella.limewire.gui.devel
Message-ID <[email protected]>
Hi,

while looking around how things are done in Limewire I did polished the 
ListEditor and the StandardListEditor.

The changes for the StandardListEditor are:

* use gridbag layout to make the (add, remove) buttons on the right have the 
same horizontal size.
* Removed button row implementation for this purpose, made 
ButtonRow.BUTTON_SEP public so the buttons still have the same distance from 
each other
* Use Actions internally
* no interface changes

The changes for ListEditor are:

* use gridbag layout for nicer layout of the buttons, the insets can still be 
tweaked
* disable remove button when nothing is selected
* enter key in editor field triggers add action
* delete key in list triggers remove action
* use actions internally
* no public interface changes

It's all in  one patch.

Regards,
Felix

-- 
Try Debian GNU/Linux!
http://www.felix.beldesign.de/

_______________________________________________
gui-dev mailing list
[email protected]
http://www.limewire.org/mailman/listinfo/gui-dev
layout.patch (text/x-diff, 14.6 KB)
Index: com/limegroup/gnutella/gui/ListEditor.java
===================================================================
RCS file: /cvs/gui/com/limegroup/gnutella/gui/ListEditor.java,v
retrieving revision 1.16
diff -u -b -B -d -w -U5 -r1.16 ListEditor.java
--- com/limegroup/gnutella/gui/ListEditor.java	10 Feb 2005 21:33:02 -0000	1.16
+++ com/limegroup/gnutella/gui/ListEditor.java	27 Feb 2005 18:02:26 -0000
@@ -1,19 +1,27 @@
 package com.limegroup.gnutella.gui;
 
 import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
 import java.util.Vector;
 
-import javax.swing.BoxLayout;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
 import javax.swing.DefaultListModel;
+import javax.swing.InputMap;
 import javax.swing.JButton;
+import javax.swing.JComponent;
 import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTextField;
+import javax.swing.KeyStroke;
 import javax.swing.ListSelectionModel;
 import javax.swing.event.ListDataEvent;
 import javax.swing.event.ListDataListener;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
@@ -65,41 +73,67 @@
      * @see setModel
      */
     public ListEditor(Vector /* of String */ model) {
         this.listeners=new Vector();
 
+        GridBagLayout gl = new GridBagLayout();
+        setLayout(gl);
+
         //Top half of the editor
-        JPanel controls=new JPanel();
         editor=new LimeTextField("");
         editor.setColumns(DEFAULT_COLUMNS);
 		editor.setPreferredSize(new Dimension(500, 20));
 		editor.setMaximumSize(new Dimension(500, 20));
-        addButton =
-        new JButton(GUIMediator.getStringResource("LIST_EDITOR_ADD_BUTTON_2"));
-        addButton.addActionListener(new AddListener());
-        removeButton = 
-        new JButton(GUIMediator.getStringResource("LIST_EDITOR_REMOVE_BUTTON"));
-        removeButton.addActionListener(new RemoveListener());
-        controls.setLayout(new BoxLayout(controls, BoxLayout.X_AXIS));
-        controls.add(editor);
-        controls.add(addButton);
-        controls.add(removeButton);
+		
+		GridBagConstraints gbc = new GridBagConstraints();
+		gbc.fill = GridBagConstraints.BOTH;
+		gbc.anchor = GridBagConstraints.NORTHWEST;
+		gbc.weightx = 1;
+		
+		gl.setConstraints(editor, gbc);
+		add(editor);
+		
+		Action addAction = new AddAction();
+        addButton =  new JButton(addAction);
+        bindKey(editor, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), addAction);
+                
+        gbc = new GridBagConstraints();
+        gbc.anchor = GridBagConstraints.NORTHWEST;
+        gbc.insets = new Insets(0, ButtonRow.BUTTON_SEP, 0, 0);
+        
+        gl.setConstraints(addButton, gbc);
+        add(addButton);
+        
+        Action removeAction = new RemoveAction();
+        removeButton = new JButton(removeAction); 
+        removeButton.setEnabled(false);
+        
+        gbc.gridwidth = GridBagConstraints.REMAINDER;
+        gl.setConstraints(removeButton, gbc);
+        add(removeButton);
         
         //Bottom half of the editor
         list=new JList();
         list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
         list.addListSelectionListener(new ListListener());
+        bindKey(list, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), removeAction);
+        
         JScrollPane scrollPane=new JScrollPane(list, 
                                   JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                                   JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
         setModel(model);
 		scrollPane.setPreferredSize(new Dimension(500, 50));
 		scrollPane.setMaximumSize(new Dimension(500, 50));
 
-        //Put them together
-        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
-        add(controls);
+        gbc = new GridBagConstraints();
+        gbc.insets = new Insets(ButtonRow.BUTTON_SEP, 0, 0, 0);
+        gbc.gridwidth = GridBagConstraints.REMAINDER;
+        gbc.anchor = GridBagConstraints.NORTHWEST;
+        gbc.fill = GridBagConstraints.BOTH;
+        gbc.weighty = 1;
+        
+        gl.setConstraints(scrollPane, gbc);
         add(scrollPane);
     }
 
     /** 
      * @requires model not subsequently modified
@@ -167,24 +201,59 @@
      */
     public synchronized void addListDataListener(ListDataListener listener) {
         listeners.add(listener);
     }
 
-    /** Someone selected something from the list. */
+    /**
+     * Binds a key stroke to the given action for the component. The action is triggered when the
+     * key is pressed while the component has the keyboard focus.
+     * @param c component for which the keybinding is installed
+     * @param key the key that triggers the action
+     * @param a the action
+     */
+    private void bindKey(JComponent c, KeyStroke key, Action a)
+    {
+    	InputMap inputMap = c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+        ActionMap actionMap = c.getActionMap();
+        if (inputMap != null && actionMap != null) {
+        	inputMap.put(key, a);
+        	actionMap.put(a, a);
+        }
+        
+    }
+    
+    /**
+     * Enables the remove button if the selection of the lis is not empty, otherwise disables it.
+     * Also sets the text of the currently selected value in the edit field.
+     */
     private class ListListener implements ListSelectionListener {
         public void valueChanged(ListSelectionEvent e) {
+        	
+			if (list.isSelectionEmpty()) {
+				removeButton.setEnabled(false);
+			}
+			else {
+				removeButton.setEnabled(true);
+			}
+			
             //Put it in the editor.
             Object val=list.getSelectedValue();
             if (val==null) 
                 return;
             else
                 editor.setText((String)val);
         }
     }
 
     /** Someone tried to add something to the list. */
-    private class AddListener implements ActionListener {
+    private class AddAction extends AbstractAction {
+    	
+    	public AddAction()
+    	{
+    		putValue(Action.NAME, GUIMediator.getStringResource("LIST_EDITOR_ADD_BUTTON_2"));
+    	}
+    	
         public void actionPerformed(ActionEvent e) {
             String text=editor.getText();
             //If nothing in editor, ignore
             if (text.trim().equals(""))
                 return;
@@ -226,21 +295,27 @@
             editor.setText("");
             list.clearSelection();
         }
     }
 
-    private class RemoveListener implements ActionListener {
+    private class RemoveAction extends AbstractAction
+	{
+    	
+    	public RemoveAction()
+    	{
+    		putValue(Action.NAME, GUIMediator.getStringResource("LIST_EDITOR_REMOVE_BUTTON"));
+    	}
+    	
         /** Someone tried to remove something from the list. */
         public void actionPerformed(ActionEvent e) {
             //If something is selected, remove it. Notify listeners.
             int i=list.getSelectedIndex();
             if (i!=-1)
                 removeItem(i);
         }
     }
 
-//      public static void main(String args[]) {
 //          Vector model=new Vector();
 //          model.addElement("britney");
 //          model.addElement("n'sync");
 //          model.addElement("money");
 //          model.addElement("spam");
Index: com/limegroup/gnutella/gui/StandardListEditor.java
===================================================================
RCS file: /cvs/gui/com/limegroup/gnutella/gui/StandardListEditor.java,v
retrieving revision 1.11
diff -u -b -B -d -w -U5 -r1.11 StandardListEditor.java
--- com/limegroup/gnutella/gui/StandardListEditor.java	12 Oct 2004 21:45:32 -0000	1.11
+++ com/limegroup/gnutella/gui/StandardListEditor.java	27 Feb 2005 18:02:26 -0000
@@ -1,16 +1,22 @@
 package com.limegroup.gnutella.gui;
 
 import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.File;
 import java.util.Vector;
 
+import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.DefaultListModel;
 import javax.swing.JButton;
 import javax.swing.JList;
+import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.ListSelectionModel;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
@@ -24,11 +30,11 @@
 public final class StandardListEditor {
 
 	/**
 	 * Constant handle to the main panel in the editor.
 	 */
-	private final BoxPanel MAIN_PANEL = new BoxPanel(BoxPanel.X_AXIS);
+	private final JPanel MAIN_PANEL = new JPanel(new GridBagLayout());
 
 	/**
 	 * Constant handle to the underlying <tt>JList</tt> instance.
 	 */
 	private final JList LIST = new JList();
@@ -42,13 +48,23 @@
 	 * Handle to the add button.
 	 */
 	private final JButton ADD_BUTTON;
 
 	/**
-	 * Default listener for the add button.
+	 * Default add action which delegates to the <code>addListener</code> if it is set.
 	 */
-	private ActionListener _defaultAddListener;
+	private AddAction _addAction;
+	
+	/**
+	 * Handle to the remove action used for disabling it when no item in the list is selected.
+	 */
+	private RemoveAction _removeAction;
+	
+	/**
+	 * Handle to the set add listener.
+	 */
+	private ActionListener _addListener = null;
 
 	/**
 	 * Member variable for whether or not the list data has changed
 	 * since the last call to reset this value.
 	 */
@@ -98,41 +114,40 @@
 	 *  for the label in the generic text input component used by default
 	 */
 	public StandardListEditor(final String ADD_BUTTON_KEY, 
 							  final String REMOVE_BUTTON_KEY,
 							  final String INPUT_FIELD_KEY) {	
-		String[] buttonLabelKeys = {
-			ADD_BUTTON_KEY,
-			REMOVE_BUTTON_KEY
-		};
 
-		String[] buttonLabelTips = {
-			"LIST_EDITOR_ADD_BUTTON_TIP",
-			"LIST_EDITOR_REMOVE_BUTTON_TIP"
-		};
-
-		_defaultAddListener = new AddActionListener(INPUT_FIELD_KEY);
-		ActionListener[] buttonListeners = {
-			_defaultAddListener,
-			new RemoveListener()
-		};
-
-		ButtonRow buttons = new ButtonRow(buttonLabelKeys, 
-										  buttonLabelTips,
-										  buttonListeners,
-										  ButtonRow.Y_AXIS,
-										  ButtonRow.BOTTOM_GLUE);
+		_addAction = new AddAction(ADD_BUTTON_KEY, INPUT_FIELD_KEY);
+		_removeAction = new RemoveAction(REMOVE_BUTTON_KEY);
 		
-		ADD_BUTTON = buttons.getButtonAtIndex(0);
-		REMOVE_BUTTON = buttons.getButtonAtIndex(1);
-		REMOVE_BUTTON.setEnabled(false);
 		LIST.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 		LIST.addListSelectionListener(new ListEditorSelectionListener());
 		JScrollPane scrollPane = new JScrollPane(LIST);
+		
+		GridBagConstraints gbc = new GridBagConstraints();
+		gbc.anchor = GridBagConstraints.NORTHWEST;
+		gbc.gridheight = GridBagConstraints.REMAINDER;
+		gbc.weightx = 1;
+		gbc.weighty = 1;
+		gbc.fill = GridBagConstraints.BOTH;
+		((GridBagLayout)MAIN_PANEL.getLayout()).setConstraints(scrollPane, gbc);
 		MAIN_PANEL.add(scrollPane);
-		MAIN_PANEL.add(buttons);	
 		
+		gbc = new GridBagConstraints();
+		gbc.anchor = GridBagConstraints.NORTHWEST;
+		gbc.gridwidth = GridBagConstraints.REMAINDER;
+		gbc.fill = GridBagConstraints.HORIZONTAL;
+		gbc.insets = new Insets(0, 3, ButtonRow.BUTTON_SEP, 0);
+		
+		ADD_BUTTON = new JButton(_addAction);
+		((GridBagLayout)MAIN_PANEL.getLayout()).setConstraints(ADD_BUTTON, gbc);
+		MAIN_PANEL.add(ADD_BUTTON);
+		
+		REMOVE_BUTTON = new JButton(_removeAction);
+		((GridBagLayout)MAIN_PANEL.getLayout()).setConstraints(REMOVE_BUTTON, gbc);
+		MAIN_PANEL.add(REMOVE_BUTTON);
 	}
 
 	/**
 	 * Provides access to the wrapped <tt>Component</tt> of the 
 	 * <tt>StandardListEditor</tt>.  This is the <tt>Component</tt>
@@ -270,12 +285,11 @@
 	 * Sets the <tt>ActionListener</tt> to use for the add button.
 	 *
 	 * @param addAction the <tt>ActionListener</tt> to use for the add button
 	 */
   	private void setAddActionListener(ActionListener addListener) {
-  		ADD_BUTTON.removeActionListener(_defaultAddListener);
-  		ADD_BUTTON.addActionListener(addListener);
+  		this._addListener = addListener;
   	}
 
 	/**
 	 * Returns whether or not the list has changed since the last
 	 * call to reset the list.  Note that this will not be 
@@ -301,32 +315,53 @@
 	/**
 	 * This class responds to a click of the add button and pops
 	 * up a window for the user to enter a new element to add
 	 * to the list.
 	 */
-	private class AddActionListener implements ActionListener {
+	private class AddAction extends AbstractAction {
+		
 		private final String INPUT_FIELD_KEY;
-		public AddActionListener(final String key) {
+		
+		public AddAction(final String name, final String key) {
+			putValue(Action.NAME, GUIMediator.getStringResource(name));
+			putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIST_EDITOR_ADD_BUTTON_TIP"));
 			INPUT_FIELD_KEY = key;
 		}
+		
 		public void actionPerformed(ActionEvent e) {
+			
+			// delegate event if there is a special addListener
+			if (_addListener != null) {
+				_addListener.actionPerformed(e);
+			}
+			else {
+			
 			InputFieldDialog dialog = new InputFieldDialog(INPUT_FIELD_KEY);
 			int returnCode = dialog.showDialog();
 
 			if(returnCode == InputFieldDialog.TEXT_ENTERED) {
 				_listChanged = true;
 				addElement(dialog.getText());
 			}
 		}
 	}
+	}
 
 
 	/**
 	 * This class responds to a click of the remove button and removes
 	 * the selected element from the list.
 	 */
-	private class RemoveListener implements ActionListener {
+	private class RemoveAction extends AbstractAction {
+		
+		public RemoveAction(final String name)
+		{
+			 putValue(Action.NAME, GUIMediator.getStringResource(name));
+			 putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIST_EDITOR_REMOVE_BUTTON_TIP"));
+			 setEnabled(false);
+		}
+		
 		public void actionPerformed(ActionEvent e) {
 			_listChanged = true;
 			// return if nothing is selected
 			if(LIST.isSelectionEmpty()) return;
 			
Index: com/limegroup/gnutella/gui/ButtonRow.java
===================================================================
RCS file: /cvs/gui/com/limegroup/gnutella/gui/ButtonRow.java,v
retrieving revision 1.25
diff -u -b -B -d -w -U5 -r1.25 ButtonRow.java
--- com/limegroup/gnutella/gui/ButtonRow.java	3 Nov 2004 17:01:11 -0000	1.25
+++ com/limegroup/gnutella/gui/ButtonRow.java	27 Feb 2005 18:02:27 -0000
@@ -24,11 +24,11 @@
     private JButton[] _buttons;
 
 	/**
 	 * The number of pixels separating buttons.
 	 */
-    private final int BUTTON_SEP = 6;
+    public static final int BUTTON_SEP = 6;
 
 	/**
 	 * Specifies that the buttons should be aligned along the x axis.
 	 */
     public static final int X_AXIS = BoxLayout.X_AXIS;