add base selection dialog - part of refactor in progress
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@983556 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/util/SelectionDialog.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/util/SelectionDialog.java
new file mode 100644
index 0000000..13a26a7
--- /dev/null
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/util/SelectionDialog.java
@@ -0,0 +1,555 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.sigil.eclipse.ui.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.fieldassist.IContentProposal;
+import org.eclipse.jface.fieldassist.IContentProposalListener;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IOpenListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTError;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * @author dave
+ *
+ * @param <E>
+ */
+public class SelectionDialog<E> extends TitleAreaDialog
+{
+
+ private final ILabelProvider DEFAULT_LABEL_PROVIDER = new LabelProvider()
+ {
+ @SuppressWarnings("unchecked")
+ public String getText(Object element)
+ {
+ String result;
+ if (element instanceof WrappedContentProposal<?>)
+ {
+ WrappedContentProposal<E> contentProposal = (org.apache.felix.sigil.eclipse.ui.util.WrappedContentProposal<E>) element;
+ result = contentProposal.getLabel();
+ }
+ else
+ {
+ result = descriptor.getLabel((E) element);
+ }
+ return result;
+ }
+ };
+ private final IElementDescriptor<E> DEFAULT_DESCRIPTOR = new IElementDescriptor<E>()
+ {
+ public String getLabel(E element)
+ {
+ return getName(element);
+ }
+
+ public String getName(E element)
+ {
+ return element == null ? "null" : element.toString();
+ }
+ };
+ protected final String selectionLabel;
+ private IFilter<? super E> filter;
+ private IElementDescriptor<? super E> descriptor = DEFAULT_DESCRIPTOR;
+ private ILabelProvider labelProvider = DEFAULT_LABEL_PROVIDER;
+ protected final boolean multi;
+ protected final List<E> elements;
+ private List<E> selection = null;
+ private String selectedName = null;
+ private TableViewer viewer = null;
+ private Comparator<? super E> comparator;
+
+ private static final void onUIThread(Control control, Runnable r)
+ {
+ if (control != null && !control.isDisposed())
+ {
+ try
+ {
+ Display display = control.getDisplay();
+ if (Thread.currentThread() == display.getThread())
+ {
+ // We are on the UI thread already, just do the work
+ r.run();
+ }
+ else
+ {
+ // Not on the UI thread, need to bung over the runnable
+ display.asyncExec(r);
+ }
+ }
+ catch (SWTError e)
+ {
+ if (e.code == SWT.ERROR_WIDGET_DISPOSED)
+ {
+ // ignore
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ }
+
+ public void setFilter(IFilter<? super E> filter)
+ {
+ this.filter = filter;
+ }
+
+ public void setDescriptor(final IElementDescriptor<? super E> descriptor)
+ {
+ if (descriptor != null)
+ {
+ this.descriptor = descriptor;
+ }
+ else
+ {
+ this.descriptor = DEFAULT_DESCRIPTOR;
+ }
+ }
+
+ public IElementDescriptor<? super E> getDescriptor()
+ {
+ return descriptor;
+ }
+
+ public void setComparator(Comparator<? super E> comparator)
+ {
+ this.comparator = comparator;
+ }
+
+ public void setLabelProvider(ILabelProvider labelProvider)
+ {
+ if (labelProvider != null)
+ {
+ this.labelProvider = labelProvider;
+ }
+ else
+ {
+ this.labelProvider = DEFAULT_LABEL_PROVIDER;
+ }
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ // Create Controls
+ Composite container = (Composite) super.createDialogArea(parent);
+ Composite composite = new Composite(container, SWT.NONE);
+
+ new Label(composite, SWT.NONE).setText(selectionLabel);
+
+ ContentProposalAdapter proposalAdapter = null;
+ Text txtSelection = null;
+
+ Table table = null;
+ if (multi)
+ {
+ table = new Table(composite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
+ viewer = new TableViewer(table);
+ viewer.setContentProvider(new ArrayContentProvider());
+ viewer.addFilter(new ViewerFilter()
+ {
+ public boolean select(Viewer viewer, Object parentElement, Object element)
+ {
+ @SuppressWarnings("unchecked")
+ E castedElement = (E) element;
+ return filter == null || filter.select(castedElement);
+ }
+ });
+ if (comparator != null)
+ {
+ viewer.setSorter(new ViewerSorter()
+ {
+ @Override
+ public int compare(Viewer viewer, Object o1, Object o2)
+ {
+ @SuppressWarnings("unchecked")
+ E e1 = (E) o1;
+ @SuppressWarnings("unchecked")
+ E e2 = (E) o2;
+ return comparator.compare(e1, e2);
+ }
+ });
+ }
+ synchronized (elements)
+ {
+ viewer.setInput(elements);
+ }
+
+ if (labelProvider != null)
+ {
+ viewer.setLabelProvider(labelProvider);
+ }
+ }
+ else
+ {
+ txtSelection = new Text(composite, SWT.BORDER);
+ ControlDecoration selectionDecor = new ControlDecoration(txtSelection,
+ SWT.LEFT | SWT.TOP);
+ FieldDecoration proposalDecor = FieldDecorationRegistry.getDefault().getFieldDecoration(
+ FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
+ selectionDecor.setImage(proposalDecor.getImage());
+ selectionDecor.setDescriptionText(proposalDecor.getDescription());
+
+ ExclusionContentProposalProvider<E> proposalProvider = new ExclusionContentProposalProvider<E>(
+ elements, filter, descriptor);
+
+ proposalAdapter = new ContentProposalAdapter(txtSelection,
+ new TextContentAdapter(), proposalProvider, null, null);
+ proposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
+ if (labelProvider != null)
+ {
+ proposalAdapter.setLabelProvider(labelProvider);
+ }
+
+ if (selectedName != null)
+ {
+ txtSelection.setText(selectedName);
+ }
+ }
+ updateSelection();
+ updateButtons();
+
+ // Hookup listeners
+ if (proposalAdapter != null)
+ {
+ proposalAdapter.addContentProposalListener(new IContentProposalListener()
+ {
+ public void proposalAccepted(IContentProposal proposal)
+ {
+ @SuppressWarnings("unchecked")
+ WrappedContentProposal<E> valueProposal = (org.apache.felix.sigil.eclipse.ui.util.WrappedContentProposal<E>) proposal;
+ E selected = valueProposal.getElement();
+ selection = new ArrayList<E>(1);
+ selection.add(selected);
+
+ elementSelected(selected);
+
+ updateButtons();
+ }
+ });
+ }
+ if (txtSelection != null)
+ {
+ txtSelection.addModifyListener(new ModifyListener()
+ {
+ public void modifyText(ModifyEvent e)
+ {
+ selectedName = ((Text) e.widget).getText();
+ updateButtons();
+ }
+ });
+ }
+ if (viewer != null)
+ {
+ viewer.addSelectionChangedListener(new ISelectionChangedListener()
+ {
+ public void selectionChanged(SelectionChangedEvent event)
+ {
+ IStructuredSelection sel = (IStructuredSelection) event.getSelection();
+ selection = new ArrayList<E>(sel.size());
+ for (Iterator<?> iter = sel.iterator(); iter.hasNext();)
+ {
+ @SuppressWarnings("unchecked")
+ E element = (E) iter.next();
+ selection.add(element);
+ }
+ updateButtons();
+ }
+ });
+ viewer.addOpenListener(new IOpenListener()
+ {
+ public void open(OpenEvent event)
+ {
+ if (canComplete())
+ {
+ setReturnCode(IDialogConstants.OK_ID);
+ close();
+ }
+ }
+ });
+ }
+
+ // Layout
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ if (multi)
+ {
+ composite.setLayout(new GridLayout(1, false));
+ GridData layoutTable = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutTable.heightHint = 200;
+ table.setLayoutData(layoutTable);
+ }
+ else
+ {
+ composite.setLayout(new GridLayout(2, false));
+ txtSelection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ }
+
+ return container;
+ }
+
+ protected void elementSelected(E selection)
+ {
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control bar = super.createButtonBar(parent);
+ updateButtons();
+ return bar;
+ }
+
+ /**
+ * Can be called from any thread
+ */
+ protected final void updateButtons()
+ {
+ Runnable updateButtonsRunnable = new Runnable()
+ {
+ public void run()
+ {
+ Shell shell = getShell();
+ if (shell != null && !shell.isDisposed())
+ {
+ Button okButton = getButton(IDialogConstants.OK_ID);
+ if (okButton != null && !okButton.isDisposed())
+ {
+ okButton.setEnabled(canComplete());
+ }
+ }
+ }
+ };
+ Shell shell = getShell();
+ if (shell != null)
+ {
+ onUIThread(shell, updateButtonsRunnable);
+ }
+ }
+
+ /**
+ * Subclasses may override but must call super.canComplete
+ * @return
+ */
+ protected synchronized boolean canComplete()
+ {
+ boolean result = false;
+
+ if (selection != null)
+ {
+ if (multi)
+ {
+ result = selection.size() > 0;
+ }
+ else
+ {
+ E sel = getSelectedElement();
+ result = sel != null && descriptor.getName(sel).equals(selectedName);
+ }
+ }
+
+ return result;
+ }
+
+ public final void addElement(E added)
+ {
+ addElements(Collections.singleton(added));
+ }
+
+ /**
+ * Can be called from any thread
+ */
+ public final void addElements(Collection<? extends E> added)
+ {
+ final LinkedList<E> toAdd = new LinkedList<E>();
+ synchronized (elements)
+ {
+ for (E e : added)
+ {
+ if (!elements.contains(e))
+ {
+ elements.add(e);
+ toAdd.add(e);
+ }
+ }
+ Collections.sort(elements, comparator);
+ }
+ if (viewer != null)
+ {
+ onUIThread(viewer.getControl(), new Runnable()
+ {
+ public void run()
+ {
+ if (!viewer.getControl().isDisposed())
+ {
+ viewer.add(toAdd.toArray());
+ viewer.refresh();
+ }
+ }
+ });
+ }
+ else
+ {
+
+ }
+ updateSelection();
+ updateButtons();
+ }
+
+ protected void updateSelection()
+ {
+ onUIThread(getShell(), new Runnable()
+ {
+ public void run()
+ {
+ if (selectedName != null)
+ {
+ ArrayList<E> newSelection = new ArrayList<E>();
+ synchronized (elements)
+ {
+ for (E e : elements)
+ {
+ if (selectedName.equals(descriptor.getName(e)))
+ {
+ newSelection.add(e);
+ break;
+ }
+ }
+ }
+ selection = newSelection;
+ }
+ else
+ {
+ selection = Collections.emptyList();
+ }
+ if (viewer != null && !viewer.getControl().isDisposed())
+ {
+ viewer.setSelection(selection.isEmpty() ? StructuredSelection.EMPTY
+ : new StructuredSelection(selection));
+ }
+ }
+ });
+ }
+
+ /**
+ * @param parentShell
+ */
+ public SelectionDialog(Shell parentShell, String selectionLabel, boolean multi)
+ {
+ super(parentShell);
+ this.selectionLabel = selectionLabel;
+ this.multi = multi;
+ this.elements = new ArrayList<E>();
+ }
+
+ public String getSelectedName()
+ {
+ return selectedName;
+ }
+
+ public void setSelectedName(String selectedName)
+ {
+ this.selectedName = selectedName;
+ boolean change = false;
+ if (selectedName == null)
+ {
+ if (selection != null && !selection.isEmpty())
+ {
+ change = true;
+ }
+ }
+ else
+ {
+ if (selection == null)
+ {
+ change = true;
+ }
+ else if (selection.size() != 1
+ || !descriptor.getLabel(selection.get(0)).equals(selectedName))
+ {
+ change = true;
+ }
+ }
+
+ if (change)
+ {
+ updateSelection();
+ updateButtons();
+ }
+ }
+
+ public List<E> getSelectedElements()
+ {
+ return selection;
+ }
+
+ public E getSelectedElement()
+ {
+ E result;
+ if (selection == null || selection.isEmpty())
+ {
+ result = null;
+ }
+ else
+ {
+ result = selection.get(0);
+ }
+ return result;
+ }
+
+}
\ No newline at end of file