Java tutorial
/* * 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.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.jobs.Job; 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; import org.eclipse.ui.progress.IJobRunnable; public class BackgroundLoadingSelectionDialog<E> extends TitleAreaDialog implements IAccumulator<E> { 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(); } }; private final String selectionLabel; private IFilter<? super E> filter; private IElementDescriptor<? super E> descriptor = DEFAULT_DESCRIPTOR; private ILabelProvider labelProvider = DEFAULT_LABEL_PROVIDER; private final boolean multi; private final List<E> elements; private List<E> selection = null; private String selectedName = null; private TableViewer viewer = null; private Comparator<? super E> comparator; private HashMap<String, IJobRunnable> background = new HashMap<String, IJobRunnable>(); public BackgroundLoadingSelectionDialog(Shell parentShell, String selectionLabel, boolean multi) { super(parentShell); elements = new ArrayList<E>(); this.selectionLabel = selectionLabel; this.multi = multi; } 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; } } public void addBackgroundJob(String name, IJobRunnable job) { background.put(name, job); } @Override public int open() { Job[] jobs = scheduleJobs(); try { return super.open(); } finally { for (Job j : jobs) { j.cancel(); } } } private Job[] scheduleJobs() { if (background.isEmpty()) { return new Job[] {}; } else { ArrayList<Job> jobs = new ArrayList<Job>(background.size()); for (Map.Entry<String, IJobRunnable> e : background.entrySet()) { final IJobRunnable run = e.getValue(); Job job = new Job(e.getKey()) { @Override protected IStatus run(IProgressMonitor monitor) { return run.run(monitor); } }; job.schedule(); } return jobs.toArray(new Job[jobs.size()]); } } @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)); } } }); } 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 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; } }