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);
}
}