Bug 150528 - [JFace] org.eclipse.jface.preference.ListEditor ought to allow multiple selection as an option
Summary: [JFace] org.eclipse.jface.preference.ListEditor ought to allow multiple selec...
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P5 enhancement (vote)
Target Milestone: ---   Edit
Assignee: Platform UI Triaged CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-07-13 12:12 EDT by brian fjeldstad CLA
Modified: 2019-09-06 16:18 EDT (History)
0 users

See Also:


Attachments
ListEditor that allows multiple items to be selected (15.50 KB, patch)
2006-07-24 16:32 EDT, brian fjeldstad CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description brian fjeldstad CLA 2006-07-13 12:12:55 EDT
Certainly, it's not a big deal, but, org.eclipse.jface.preference.ListEditor ought to allow multiple selection as an option.
Comment 1 brian fjeldstad CLA 2006-07-13 13:09:06 EDT
Here's some code that I modified to allow it in a configurable way...there's probably more error checking that needs to be done:


	class MultiSelectListEditor extends FieldEditor {
		/** style settings to allow add button */
		public static int ALLOW_ADD = 1 >> 0;
		/** style settings to allow remove button */
		public static int ALLOW_REMOVE = 1 << 1;
		/** style settings to allow up button */
		public static int ALLOW_UP = 1 << 2;
		/** style settings to allow down button */
		public static int ALLOW_DOWN = 1 << 3;
		/** style settings to allow all buttons */
		public static int ALLOW_ALL = ALLOW_ADD | ALLOW_REMOVE | ALLOW_UP | ALLOW_DOWN;
		
		/** Controls which buttons are displayed */
		private int allowButtons = ALLOW_ALL;
		
		/** Controls whether the list allows multiple items to be selected */
		private boolean multipleSelections;
		
		/**
	     * The list widget; <code>null</code> if none
	     * (before creation or after disposal).
	     */
	    private List list;

	    /**
	     * The button box containing the Add, Remove, Up, and Down buttons;
	     * <code>null</code> if none (before creation or after disposal).
	     */
	    private Composite buttonBox;

	    /**
	     * The Add button.
	     */
	    private Button addButton;

	    /**
	     * The Remove button.
	     */
	    private Button removeButton;

	    /**
	     * The Up button.
	     */
	    private Button upButton;

	    /**
	     * The Down button.
	     */
	    private Button downButton;

	    /**
	     * The selection listener.
	     */
	    private SelectionListener selectionListener;

	    /**
	     * Creates a new list field editor 
	     */
	    protected MultiSelectListEditor() {
	    }

	    /**
	     * Creates a list field editor.
	     * 
	     * @param name the name of the preference this field editor works on
	     * @param labelText the label text of the field editor
	     * @param parent the parent of the field editor's control
	     * @param buttons controls which buttons are visible.  To show all, 
	     * use 0 or ALLOW_ALL.
	     * @param mutltiSelect controls whether the list allows mutliple 
	     * selections 
	     */
	    protected MultiSelectListEditor(String name, String labelText, Composite parent, 
	    								int buttons, boolean multiSelect) {
	    	allowButtons = buttons;
	    	multipleSelections = multiSelect;
	    	
	        init(name, labelText);
	        createControl(parent);
	    }

	    /**
	     * Create a list field editor with mutliple selection allowed and add, remove, up, down buttons
	     * 
	     * @param name the name of the preference this field editor works on
	     * @param labelText the label text of the field editor
	     * @param parent the parent of the field editor's control
	     */
	    protected MultiSelectListEditor(String name, String labelText, Composite parent) {
	    	this(name, labelText, parent, ALLOW_ALL, true);
	    }

	    /**
	     * Notifies that the Add button has been pressed.
	     */
	    private void addPressed() {
	        setPresentsDefaultValue(false);
	        String input = getNewInputObject();

	        if (input != null) {
	            int index = list.getSelectionIndex();
	            if (index >= 0) {
					list.add(input, index + 1);
				} else {
					list.add(input, 0);
				}
	            selectionChanged();
	        }
	    }

	    /* (non-Javadoc)
	     * Method declared on FieldEditor.
	     */
	    protected void adjustForNumColumns(int numColumns) {
	        Control control = getLabelControl();
	        ((GridData) control.getLayoutData()).horizontalSpan = numColumns;
	        ((GridData) list.getLayoutData()).horizontalSpan = numColumns - 1;
	    }

	    /**
	     * Creates the Add, Remove, Up, and Down button in the given button box.
	     *
	     * @param box the box for the buttons
	     */
	    private void createButtons(Composite box) {
	        if ((allowButtons&ALLOW_ADD)==ALLOW_ADD) addButton = createPushButton(box, "ListEditor.add");//$NON-NLS-1$
	        if ((allowButtons&ALLOW_REMOVE)==ALLOW_REMOVE) removeButton = createPushButton(box, "ListEditor.remove");//$NON-NLS-1$
	        if ((allowButtons&ALLOW_UP)==ALLOW_UP) upButton = createPushButton(box, "ListEditor.up");//$NON-NLS-1$
	        if ((allowButtons&ALLOW_DOWN)==ALLOW_DOWN) downButton = createPushButton(box, "ListEditor.down");//$NON-NLS-1$
	    }

	    /**
	     * Combines the given list of items into a single string.
	     * This method is the converse of <code>parseString</code>. 
	     * <p>
	     * Subclasses must implement this method.
	     * </p>
	     *
	     * @param items the list of items
	     * @return the combined string
	     * @see #parseString
	     */
	    protected abstract String createList(String[] items);

	    /**
	     * Helper method to create a push button.
	     * 
	     * @param parent the parent control
	     * @param key the resource name used to supply the button's label text
	     * @return Button
	     */
	    private Button createPushButton(Composite parent, String key) {
	        Button button = new Button(parent, SWT.PUSH);
	        button.setText(JFaceResources.getString(key));
	        button.setFont(parent.getFont());
	        GridData data = new GridData(GridData.FILL_HORIZONTAL);
	        int widthHint = convertHorizontalDLUsToPixels(button,
	                IDialogConstants.BUTTON_WIDTH);
	        data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT,
	                SWT.DEFAULT, true).x);
	        button.setLayoutData(data);
	        button.addSelectionListener(getSelectionListener());
	        return button;
	    }

	    /**
	     * Creates a selection listener.
	     */
	    public void createSelectionListener() {
	        selectionListener = new SelectionAdapter() {
	            public void widgetSelected(SelectionEvent event) {
	                Widget widget = event.widget;
	                if (widget == addButton) {
	                    addPressed();
	                } else if (widget == removeButton) {
	                    removePressed();
	                } else if (widget == upButton) {
	                    upPressed();
	                } else if (widget == downButton) {
	                    downPressed();
	                } else if (widget == list) {
	                    selectionChanged();
	                }
	            }
	        };
	    }

	    /* (non-Javadoc)
	     * Method declared on FieldEditor.
	     */
	    protected void doFillIntoGrid(Composite parent, int numColumns) {
	        Control control = getLabelControl(parent);
	        GridData gd = new GridData();
	        gd.horizontalSpan = numColumns;
	        control.setLayoutData(gd);

	        list = getListControl(parent);
	        gd = new GridData(GridData.FILL_HORIZONTAL);
	        gd.verticalAlignment = GridData.FILL;
	        gd.horizontalSpan = numColumns - 1;
	        gd.grabExcessHorizontalSpace = true;
	        list.setLayoutData(gd);

	        buttonBox = getButtonBoxControl(parent);
	        gd = new GridData();
	        gd.verticalAlignment = GridData.BEGINNING;
	        buttonBox.setLayoutData(gd);
	    }

	    /* (non-Javadoc)
	     * Method declared on FieldEditor.
	     */
	    protected void doLoad() {
	        if (list != null) {
	            String s = getPreferenceStore().getString(getPreferenceName());
	            String[] array = parseString(s);
	            for (int i = 0; i < array.length; i++) {
	                list.add(array[i]);
	            }
	        }
	    }

	    /* (non-Javadoc)
	     * Method declared on FieldEditor.
	     */
	    protected void doLoadDefault() {
	        if (list != null) {
	            list.removeAll();
	            String s = getPreferenceStore().getDefaultString(
	                    getPreferenceName());
	            String[] array = parseString(s);
	            for (int i = 0; i < array.length; i++) {
	                list.add(array[i]);
	            }
	        }
	    }

	    /* (non-Javadoc)
	     * Method declared on FieldEditor.
	     */
	    protected void doStore() {
	        String s = createList(list.getItems());
	        if (s != null) {
				getPreferenceStore().setValue(getPreferenceName(), s);
			}
	    }

	    /**
	     * Notifies that the Down button has been pressed.
	     */
	    private void downPressed() {
	        swap(false);
	    }

	    /**
	     * Returns this field editor's button box containing the Add, Remove,
	     * Up, and Down button.
	     *
	     * @param parent the parent control
	     * @return the button box
	     */
	    public Composite getButtonBoxControl(Composite parent) {
	        if (buttonBox == null) {
	            buttonBox = new Composite(parent, SWT.NULL);
	            GridLayout layout = new GridLayout();
	            layout.marginWidth = 0;
	            buttonBox.setLayout(layout);
	            createButtons(buttonBox);
	            buttonBox.addDisposeListener(new DisposeListener() {
	                public void widgetDisposed(DisposeEvent event) {
	                    addButton = null;
	                    removeButton = null;
	                    upButton = null;
	                    downButton = null;
	                    buttonBox = null;
	                }
	            });

	        } else {
	            checkParent(buttonBox, parent);
	        }

	        selectionChanged();
	        return buttonBox;
	    }

	    /**
	     * Returns this field editor's list control.
	     *
	     * @param parent the parent control
	     * @return the list control
	     */
	    public List getListControl(Composite parent) {
	        if (list == null) {
	        	int listStyle = SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL;
	        	if (multipleSelections) listStyle |= SWT.MULTI;
	        	else listStyle |= SWT.SINGLE;
	            list = new List(parent, listStyle);
	            list.setFont(parent.getFont());
	            list.addSelectionListener(getSelectionListener());
	            list.addDisposeListener(new DisposeListener() {
	                public void widgetDisposed(DisposeEvent event) {
	                    list = null;
	                }
	            });
	        } else {
	            checkParent(list, parent);
	        }
	        return list;
	    }

	    /**
	     * Creates and returns a new item for the list.
	     * <p>
	     * Subclasses must implement this method.
	     * </p>
	     *
	     * @return a new item
	     */
	    protected abstract String getNewInputObject();

	    /* (non-Javadoc)
	     * Method declared on FieldEditor.
	     */
	    public int getNumberOfControls() {
	        return 2;
	    }

	    /**
	     * Returns this field editor's selection listener.
	     * The listener is created if nessessary.
	     *
	     * @return the selection listener
	     */
	    private SelectionListener getSelectionListener() {
	        if (selectionListener == null) {
				createSelectionListener();
			}
	        return selectionListener;
	    }

	    /**
	     * Returns this field editor's shell.
	     * <p>
	     * This method is internal to the framework; subclassers should not call
	     * this method.
	     * </p>
	     *
	     * @return the shell
	     */
	    protected Shell getShell() {
	    	if (addButton != null) return addButton.getShell();
	    	if (removeButton != null) return removeButton.getShell();
	    	if (upButton != null) return upButton.getShell();
	    	if (downButton != null) return downButton.getShell();
			return null;
	    }

	    /**
	     * Splits the given string into a list of strings.
	     * This method is the converse of <code>createList</code>. 
	     * <p>
	     * Subclasses must implement this method.
	     * </p>
	     *
	     * @param stringList the string
	     * @return an array of <code>String</code>
	     * @see #createList
	     */
	    protected abstract String[] parseString(String stringList);

	    /**
	     * Notifies that the Remove button has been pressed.
	     */
	    private void removePressed() {
	        setPresentsDefaultValue(false);
	        int [] indices = list.getSelectionIndices();
	        if (indices != null && indices.length != 0) {
	        	for (int i=indices.length-1; i>=0; i--) {
	        		list.remove(indices[i]);
	        	}
	            selectionChanged();
	        }
	    }

	    /**
	     * Notifies that the list selection has changed.
	     */
	    private void selectionChanged() {

	        int [] indices = list.getSelectionIndices();
	        int size = list.getItemCount();

	        boolean hasSelection = indices!=null && indices.length!=0;
	        int firstSel = (hasSelection) ? indices[0] : -1;
	        int lastSel = (hasSelection) ? indices[indices.length-1] : -1;
	        
	        if (removeButton != null) removeButton.setEnabled(hasSelection);
	        if (upButton != null) upButton.setEnabled(hasSelection && size > 1 && firstSel > 0);
	        if (downButton != null) downButton.setEnabled(hasSelection && size > 1 && lastSel < size - 1);
	    }

	    /* (non-Javadoc)
	     * Method declared on FieldEditor.
	     */
	    public void setFocus() {
	        if (list != null) {
	            list.setFocus();
	        }
	    }

	    /**
	     * Moves the currently selected item up or down.
	     *
	     * @param up <code>true</code> if the item should move up,
	     *  and <code>false</code> if it should move down
	     */
	    private void swap(boolean up) {
	        setPresentsDefaultValue(false);
	        int [] indices = list.getSelectionIndices();
	        int target = up ? -1 : 1;

	        if (indices != null && indices.length != 0) {
	        	int i = (up) ? 0 : indices.length-1;
	        	while (true) {
	        		// get and remove index
	        		String item1 = list.getItem(indices[i]);
	        		String item2 = list.getItem(indices[i] + target);

	        		// swap items
	        		list.setItem(indices[i] + target, item1);
	        		list.setItem(indices[i], item2);
	        		
	        		// adjust index and add item
	        		indices[i] += target;
	        		
	        		if ((up && i==indices.length-1) || (!up && i==0)) break;
	        		i -= target;
	        	}
	        	
	        	//adjust all the selections
	        	list.setSelection(indices);
	        }
	        selectionChanged();
	    }

	    /**
	     * Notifies that the Up button has been pressed.
	     */
	    private void upPressed() {
	        swap(true);
	    }

	    /*
	     * @see FieldEditor.setEnabled(boolean,Composite).
	     */
	    public void setEnabled(boolean enabled, Composite parent) {
	        super.setEnabled(enabled, parent);
	        getListControl(parent).setEnabled(enabled);
	        if (addButton != null) addButton.setEnabled(enabled);
	        if (removeButton != null) removeButton.setEnabled(enabled);
	        if (upButton != null) upButton.setEnabled(enabled);
	        if (downButton != null) downButton.setEnabled(enabled);
	    }
	}
Comment 2 Felipe Heidrich CLA 2006-07-17 16:59:04 EDT
moving to JFace guys.
Comment 3 Eric Moffatt CLA 2006-07-24 15:40:49 EDT
Susan, I'll give this to you first. Punt it back if its really a 'Preferences' issue and I'll re-assign.

P.S. Congradulations!!
Comment 4 Susan McCourt CLA 2006-07-24 16:19:33 EDT
Brian can you attach the code as a patch file?  will be easier to deal with.  Thanks.
Comment 5 brian fjeldstad CLA 2006-07-24 16:32:05 EDT
Created attachment 46729 [details]
ListEditor that allows multiple items to be selected
Comment 6 Susan McCourt CLA 2006-07-24 16:36:27 EDT
marking 3.3 so this gets looked at...
thanks, Brian.
Comment 7 Susan McCourt CLA 2007-05-01 18:40:16 EDT
missed the window for introducing new API. Sorry, Brian, I was on leave for a big chunk of this release and just didn't get to this in time.
Comment 8 Susan McCourt CLA 2007-07-02 19:51:57 EDT
changing prio and status per platform ui bug guidelines
Comment 9 Susan McCourt CLA 2009-07-09 17:18:02 EDT
As per http://wiki.eclipse.org/Platform_UI/Bug_Triage_Change_2009
Comment 10 Eclipse Webmaster CLA 2019-09-06 16:18:53 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.