package org.rubypeople.rdt.internal.ui.dialogs; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.util.Assert; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.rubypeople.rdt.internal.ui.util.FilteredList; /** * An abstract class to select elements out of a list of elements. */ public abstract class AbstractElementListSelectionDialog extends SelectionStatusDialog { private ILabelProvider fRenderer; private boolean fIgnoreCase= true; private boolean fIsMultipleSelection= false; private boolean fMatchEmptyString= true; private boolean fAllowDuplicates= true; private Label fMessage; protected FilteredList fFilteredList; private Text fFilterText; private ISelectionValidator fValidator; private String fFilter= null; private String fEmptyListMessage= ""; //$NON-NLS-1$ private String fEmptySelectionMessage= ""; //$NON-NLS-1$ private int fWidth= 60; private int fHeight= 18; private Object[] fSelection= new Object[0]; /** * Constructs a list selection dialog. * @param renderer The label renderer used * @param ignoreCase Decides if the match string ignores lower/upppr case * @param multipleSelection Allow multiple selection */ protected AbstractElementListSelectionDialog(Shell parent, ILabelProvider renderer) { super(parent); fRenderer= renderer; int shellStyle= getShellStyle(); setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); } /** * Handles default selection (double click). * By default, the OK button is pressed. */ protected void handleDefaultSelected() { if (validateCurrentSelection()) buttonPressed(IDialogConstants.OK_ID); } /** * Specifies if sorting, filtering and folding is case sensitive. */ public void setIgnoreCase(boolean ignoreCase) { fIgnoreCase= ignoreCase; } /** * Returns if sorting, filtering and folding is case sensitive. */ public boolean isCaseIgnored() { return fIgnoreCase; } /** * Specifies whether everything or nothing should be filtered on * empty filter string. */ public void setMatchEmptyString(boolean matchEmptyString) { fMatchEmptyString= matchEmptyString; } /** * Specifies if multiple selection is allowed. */ public void setMultipleSelection(boolean multipleSelection) { fIsMultipleSelection= multipleSelection; } /** * Specifies whether duplicate entries are displayed or not. */ public void setAllowDuplicates(boolean allowDuplicates) { fAllowDuplicates= allowDuplicates; } /** * Sets the list size in unit of characters. * @param width the width of the list. * @param height the height of the list. */ public void setSize(int width, int height) { fWidth= width; fHeight= height; } /** * Sets the message to be displayed if the list is empty. * @param message the message to be displayed. */ public void setEmptyListMessage(String message) { fEmptyListMessage= message; } /** * Sets the message to be displayed if the selection is empty. * @param message the message to be displayed. */ public void setEmptySelectionMessage(String message) { fEmptySelectionMessage= message; } /** * Sets an optional validator to check if the selection is valid. * The validator is invoked whenever the selection changes. * @param validator the validator to validate the selection. */ public void setValidator(ISelectionValidator validator) { fValidator= validator; } /** * Sets the elements of the list (widget). * To be called within open(). * @param elements the elements of the list. */ protected void setListElements(Object[] elements) { Assert.isNotNull(fFilteredList); fFilteredList.setElements(elements); } /** * Sets the filter pattern. * @param filter the filter pattern. */ public void setFilter(String filter) { if (fFilterText == null) fFilter= filter; else fFilterText.setText(filter); } /** * Returns the current filter pattern. * @return returns the current filter pattern or <code>null<code> if filter was not set. */ public String getFilter() { if (fFilteredList == null) return fFilter; return fFilteredList.getFilter(); } /** * Returns the indices referring the current selection. * To be called within open(). * @return returns the indices of the current selection. */ protected int[] getSelectionIndices() { Assert.isNotNull(fFilteredList); return fFilteredList.getSelectionIndices(); } /** * Returns an index referring the first current selection. * To be called within open(). * @return returns the indices of the current selection. */ protected int getSelectionIndex() { Assert.isNotNull(fFilteredList); return fFilteredList.getSelectionIndex(); } /** * Sets the selection referenced by an array of elements. * To be called within open(). * @param selection the indices of the selection. */ protected void setSelection(Object[] selection) { Assert.isNotNull(fFilteredList); fFilteredList.setSelection(selection); } /** * Returns an array of the currently selected elements. * To be called within or after open(). * @return returns an array of the currently selected elements. */ protected Object[] getSelectedElements() { Assert.isNotNull(fFilteredList); return fFilteredList.getSelection(); } /** * Returns all elements which are folded together to one entry in the list. * @param index the index selecting the entry in the list. * @return returns an array of elements folded together. */ public Object[] getFoldedElements(int index) { Assert.isNotNull(fFilteredList); return fFilteredList.getFoldedElements(index); } /** * Creates the message text widget and sets layout data. * @param composite the parent composite of the message area. */ protected Label createMessageArea(Composite composite) { Label label= super.createMessageArea(composite); GridData data= new GridData(); data.grabExcessVerticalSpace= false; data.grabExcessHorizontalSpace= true; data.horizontalAlignment= GridData.FILL; data.verticalAlignment= GridData.BEGINNING; label.setLayoutData(data); fMessage= label; return label; } /** * Handles a selection changed event. * By default, the current selection is validated. */ protected void handleSelectionChanged() { validateCurrentSelection(); } /** * Validates the current selection and updates the status line * accordingly. */ protected boolean validateCurrentSelection() { Assert.isNotNull(fFilteredList); IStatus status; Object[] elements= getSelectedElements(); if (elements.length > 0) { if (fValidator != null) { status= fValidator.validate(elements); } else { status= new StatusInfo(); } } else { if (fFilteredList.isEmpty()) { status= new StatusInfo(IStatus.ERROR, fEmptyListMessage); } else { status= new StatusInfo(IStatus.ERROR, fEmptySelectionMessage); } } updateStatus(status); return status.isOK(); } /* * @see Dialog#cancelPressed */ protected void cancelPressed() { setResult(null); super.cancelPressed(); } /** * Creates a filtered list. * @param parent the parent composite. * @return returns the filtered list widget. */ protected FilteredList createFilteredList(Composite parent) { int flags= SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | (fIsMultipleSelection ? SWT.MULTI : SWT.SINGLE); FilteredList list= new FilteredList(parent, flags, fRenderer, fIgnoreCase, fAllowDuplicates, fMatchEmptyString); GridData data= new GridData(); data.widthHint= convertWidthInCharsToPixels(fWidth); data.heightHint= convertHeightInCharsToPixels(fHeight); data.grabExcessVerticalSpace= true; data.grabExcessHorizontalSpace= true; data.horizontalAlignment= GridData.FILL; data.verticalAlignment= GridData.FILL; list.setLayoutData(data); list.setFilter((fFilter == null ? "" : fFilter)); //$NON-NLS-1$ list.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { handleDefaultSelected(); } public void widgetSelected(SelectionEvent e) { handleWidgetSelected(); } }); fFilteredList= list; return list; } // 3515 private void handleWidgetSelected() { Object[] newSelection= fFilteredList.getSelection(); if (newSelection.length != fSelection.length) { fSelection= newSelection; handleSelectionChanged(); } else { for (int i= 0; i != newSelection.length; i++) { if (!newSelection[i].equals(fSelection[i])) { fSelection= newSelection; handleSelectionChanged(); break; } } } } protected Text createFilterText(Composite parent) { Text text= new Text(parent, SWT.BORDER); GridData data= new GridData(); data.grabExcessVerticalSpace= false; data.grabExcessHorizontalSpace= true; data.horizontalAlignment= GridData.FILL; data.verticalAlignment= GridData.BEGINNING; text.setLayoutData(data); text.setText((fFilter == null ? "" : fFilter)); //$NON-NLS-1$ Listener listener= new Listener() { public void handleEvent(Event e) { fFilteredList.setFilter(fFilterText.getText()); } }; text.addListener(SWT.Modify, listener); text.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { if (e.keyCode == SWT.ARROW_DOWN) fFilteredList.setFocus(); } public void keyReleased(KeyEvent e) {} }); fFilterText= text; return text; } /* * @see Window#open() */ public int open() { BusyIndicator.showWhile(null, new Runnable() { public void run() { access$superOpen(); } }); return getReturnCode(); } private void access$superOpen() { super.open(); } /* * @see Window#create(Shell) */ public void create() { super.create(); Assert.isNotNull(fFilteredList); if (fFilteredList.isEmpty()) { handleEmptyList(); } else { validateCurrentSelection(); fFilterText.selectAll(); fFilterText.setFocus(); } } /** * Handles empty list by disabling widgets. */ protected void handleEmptyList() { fMessage.setEnabled(false); fFilterText.setEnabled(false); fFilteredList.setEnabled(false); } }