Java tutorial
/******************************************************************************* * Copyright (c) 2010 Symbian Foundation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of the License "Eclipse Public License v1.0" * which accompanies this distribution, and is available * at the URL "http://www.eclipse.org/legal/epl-v10.html". * * Initial Contributors: * Symbian Foundation - initial contribution. * Contributors: * Description: * Overview: * Details: * Platforms/Drives/Compatibility: * Assumptions/Requirement/Pre-requisites: * Failures and causes: *******************************************************************************/ package org.symbian.tools.tmw.internal.ui.wizard; import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdfill; import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdhhint; import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdhspan; import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdwhint; import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gl; import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.glmargins; import static org.eclipse.wst.common.project.facet.ui.internal.util.SwtUtil.getPreferredWidth; import static org.eclipse.wst.common.project.facet.ui.internal.util.SwtUtil.runOnDisplayThread; import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.resource.CompositeImageDescriptor; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; 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.jface.window.ToolTip; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy; import org.eclipse.wst.common.project.facet.core.IProjectFacet; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectEvent; import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectListener; import org.eclipse.wst.common.project.facet.core.events.IProjectFacetsChangedEvent; import org.eclipse.wst.common.project.facet.core.runtime.RuntimeManager; import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleEvent; import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleListener; import org.eclipse.wst.common.project.facet.ui.IDecorationsProvider; import org.eclipse.wst.common.project.facet.ui.internal.FacetUiPlugin; import org.symbian.tools.tmw.core.TMWCore; /** * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ @SuppressWarnings("restriction") public final class FacetsSelectionPanel extends Composite implements ISelectionProvider { private final Composite topComposite; private final SashForm sform1; private final CheckboxTableViewer tableViewer; private final Table table; private final FixedFacetToolTip fixedFacetToolTip; private final TableViewer problemsView; private boolean showToolTips; private final IFacetedProjectWorkingCopy fpjwc; private final List<IFacetedProjectListener> registeredWorkingCopyListeners; private final Map<IProjectFacet, IProjectFacetVersion> selectedVersions; private final List<ISelectionChangedListener> selectionListeners; private Object selection; private final ImageRegistry imageRegistry; private final IRuntimeLifecycleListener runtimeLifecycleListener; private final Text description; private final Composite facets; public FacetsSelectionPanel(final Composite parent, final IFacetedProjectWorkingCopy fpjwc) { super(parent, SWT.NONE); this.fpjwc = fpjwc; this.registeredWorkingCopyListeners = new ArrayList<IFacetedProjectListener>(); this.selectedVersions = new HashMap<IProjectFacet, IProjectFacetVersion>(); this.selection = null; this.selectionListeners = new ArrayList<ISelectionChangedListener>(); this.showToolTips = false; // Initialize the image registry. this.imageRegistry = new ImageRegistry(); // Layout the panel. setLayout(glmargins(new GridLayout(1, false), 0, 0)); this.topComposite = new Composite(this, SWT.NONE); this.topComposite.setLayout(glmargins(new GridLayout(4, false), 0, 0)); this.sform1 = new SashForm(this.topComposite, SWT.VERTICAL | SWT.SMOOTH); this.sform1.setLayoutData(gdhspan(gdfill(), 4)); facets = new Composite(sform1, SWT.NONE); facets.setLayout(new GridLayout(2, false)); this.table = new Table(facets, SWT.BORDER | SWT.CHECK); GridData gd = new GridData(GridData.FILL_VERTICAL); gd.widthHint = 250; table.setLayoutData(gd); description = new Text(facets, SWT.MULTI | SWT.READ_ONLY | SWT.WRAP | SWT.BORDER); gd = new GridData(GridData.FILL_BOTH); description.setLayoutData(gd); this.tableViewer = new CheckboxTableViewer(this.table); this.tableViewer.setLabelProvider(new FacetColumnLabelProvider()); this.tableViewer.setContentProvider(new ContentProvider()); this.tableViewer.setSorter(new Sorter()); this.fixedFacetToolTip = new FixedFacetToolTip(this.table); this.tableViewer.setInput(new Object()); this.tableViewer.setFilters(new ViewerFilter[] { new RuntimeFacetsFilter(fpjwc) }); this.tableViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(final SelectionChangedEvent e) { FacetsSelectionPanel.this.handleSelectionChangedEvent(); } }); this.tableViewer.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(final CheckStateChangedEvent e) { FacetsSelectionPanel.this.handleCheckStateChanged(e); } }); this.table.addListener(SWT.MouseDown, new Listener() { public void handleEvent(final Event event) { handleMouseDownEvent(event); } }); this.problemsView = new TableViewer(this.sform1, SWT.BORDER); this.problemsView.setContentProvider(new ProblemsContentProvider()); this.problemsView.setLabelProvider(new ProblemsLabelProvider()); this.problemsView.setInput(new Object()); addDisposeListener(new DisposeListener() { public void widgetDisposed(final DisposeEvent e) { handleDisposeEvent(); } }); Dialog.applyDialogFont(parent); // Setup runtime lifecycle listener. this.runtimeLifecycleListener = new IRuntimeLifecycleListener() { public void handleEvent(final IRuntimeLifecycleEvent event) { handleValidationProblemsChangedEvent(); } }; RuntimeManager.addListener(this.runtimeLifecycleListener, IRuntimeLifecycleEvent.Type.VALIDATION_STATUS_CHANGED); // Bind to the model. addWorkingCopyListener(new IFacetedProjectListener() { public void handleEvent(final IFacetedProjectEvent event) { handleProjectFacetsChangedEvent(event); } }, IFacetedProjectEvent.Type.PROJECT_FACETS_CHANGED); handleProjectFacetsChangedEvent(null); addWorkingCopyListener(new IFacetedProjectListener() { public void handleEvent(final IFacetedProjectEvent event) { handleValidationProblemsChangedEvent(); } }, IFacetedProjectEvent.Type.VALIDATION_PROBLEMS_CHANGED, IFacetedProjectEvent.Type.PROJECT_MODIFIED); handleValidationProblemsChangedEvent(); addWorkingCopyListener(new IFacetedProjectListener() { public void handleEvent(final IFacetedProjectEvent event) { handleModelChangedEvent(event); } }, IFacetedProjectEvent.Type.FIXED_FACETS_CHANGED, IFacetedProjectEvent.Type.SELECTED_PRESET_CHANGED, IFacetedProjectEvent.Type.TARGETED_RUNTIMES_CHANGED); // Set the preferred dimensions of the panel. final int prefWidthTree = getPreferredWidth(this.table); final int prefWidth = prefWidthTree + 80; this.topComposite.setLayoutData(gdwhint(gdhhint(gdfill(), 200), prefWidth)); this.sform1.setWeights(new int[] { 70, 30 }); // Select the first item in the table. if (this.table.getItemCount() > 0) { final TableItem firstItem = this.table.getItem(0); this.tableViewer.setSelection(new StructuredSelection(firstItem.getData())); } handleSelectionChangedEvent(); } public IFacetedProjectWorkingCopy getFacetedProjectWorkingCopy() { return this.fpjwc; } public boolean isSelectionValid() { return (this.fpjwc.validate().getSeverity() != IStatus.ERROR); } public boolean setFocus() { return this.table.setFocus(); } public void addSelectionChangedListener(final ISelectionChangedListener listener) { this.selectionListeners.add(listener); } public void removeSelectionChangedListener(final ISelectionChangedListener listener) { this.selectionListeners.remove(listener); } public ISelection getSelection() { if (this.selection != null) { return new StructuredSelection(this.selection); } else { return new StructuredSelection(new Object[0]); } } public void setSelection(final ISelection selection) { throw new UnsupportedOperationException(); } private void notifySelectionChangedListeners() { final SelectionChangedEvent event = new SelectionChangedEvent(this, getSelection()); for (ISelectionChangedListener listener : this.selectionListeners) { listener.selectionChanged(event); } } private ImageRegistry getImageRegistry() { return this.imageRegistry; } public Image getImage(final IProjectFacet facet, final boolean showDecorations) { final boolean isFixed = getFacetedProjectWorkingCopy().isFixedProjectFacet(facet); final String id = (isFixed && showDecorations ? "F:" : "f:") + facet.getId(); //$NON-NLS-1$ //$NON-NLS-2$ Image image = getImageRegistry().get(id); if (image == null) { final IDecorationsProvider decprov = (IDecorationsProvider) facet .getAdapter(IDecorationsProvider.class); ImageDescriptor imgdesc = decprov.getIcon(); if (isFixed && showDecorations) { imgdesc = new FixedFacetImageDescriptor(imgdesc); } getImageRegistry().put(id, imgdesc); image = getImageRegistry().get(id); } return image; } private void refresh() { // Somehow the checked state of nested items gets lost when a refresh // is performed, so we have to do this workaround. final Object[] checked = this.tableViewer.getCheckedElements(); this.tableViewer.refresh(); this.tableViewer.setCheckedElements(checked); } public boolean getShowToolTips() { return this.showToolTips; } public void setShowToolTips(final boolean showToolTips) { this.showToolTips = showToolTips; } private void addWorkingCopyListener(final IFacetedProjectListener listener, final IFacetedProjectEvent.Type... types) { this.fpjwc.addListener(listener, types); this.registeredWorkingCopyListeners.add(listener); } public IProjectFacet getSelectedProjectFacet() { final IProjectFacetVersion fv = getSelectedProjectFacetVersion(); if (fv != null) { return fv.getProjectFacet(); } return null; } public IProjectFacetVersion getSelectedProjectFacetVersion() { if (this.selection != null && this.selection instanceof IProjectFacetVersion) { return (IProjectFacetVersion) this.selection; } return null; } private IProjectFacetVersion getSelectedVersion(final IProjectFacet f) { final Set<IProjectFacetVersion> availableVersions = this.fpjwc.getAvailableVersions(f); if (availableVersions.isEmpty()) { throw new IllegalStateException(); } IProjectFacetVersion selectedVersion = this.fpjwc.getProjectFacetVersion(f); if (selectedVersion == null) { selectedVersion = this.selectedVersions.get(f); if (selectedVersion == null) { selectedVersion = f.getDefaultVersion(); } if (!availableVersions.contains(selectedVersion)) { selectedVersion = this.fpjwc.getHighestAvailableVersion(f); } } this.selectedVersions.put(f, selectedVersion); return selectedVersion; } private void handleSelectionChangedEvent() { Object selection = ((IStructuredSelection) this.tableViewer.getSelection()).getFirstElement(); if (selection != null && selection instanceof IProjectFacet) { selection = getSelectedVersion((IProjectFacet) selection); description.setText(((IProjectFacetVersion) selection).getProjectFacet().getDescription()); } if (selection != this.selection) { this.selection = selection; notifySelectionChangedListeners(); } } private void handleCheckStateChanged(final CheckStateChangedEvent event) { final Object el = event.getElement(); final boolean checked = event.getChecked(); final IProjectFacet f = (IProjectFacet) el; if (this.fpjwc.getFixedProjectFacets().contains(f)) { if (!checked) { this.tableViewer.setChecked(el, true); final String msg = MessageFormat.format( "Project facet {0} cannot be deselected. It is critical to the proper function of this project.", f.getLabel()); this.fixedFacetToolTip.setMessage(msg); final Point cursorLocation = getDisplay().getCursorLocation(); this.fixedFacetToolTip.show(this.table.toControl(cursorLocation)); } return; } if (checked) { this.fpjwc.addProjectFacet(getSelectedVersion(f)); } else { this.fpjwc.removeProjectFacet(f); } this.fpjwc.setSelectedPreset(null); } private void handleMouseDownEvent(final Event event) { handleMouseDownEventHelper(event, this.table.getItems()); } private boolean handleMouseDownEventHelper(final Event event, final TableItem[] items) { for (TableItem item : items) { if (item.getBounds(1).contains(event.x, event.y)) { final TableItem[] newSelection = new TableItem[] { item }; if (!Arrays.equals(this.table.getSelection(), newSelection)) { this.table.setSelection(new TableItem[] { item }); this.tableViewer.editElement(item.getData(), 1); } return true; } } return false; } private void handleDisposeEvent() { this.imageRegistry.dispose(); for (IFacetedProjectListener listener : this.registeredWorkingCopyListeners) { this.fpjwc.removeListener(listener); } RuntimeManager.removeListener(this.runtimeLifecycleListener); } private void handleProjectFacetsChangedEvent(final IFacetedProjectEvent event) { if (!Thread.currentThread().equals(getDisplay().getThread())) { final Runnable uiRunnable = new Runnable() { public void run() { handleProjectFacetsChangedEvent(event); } }; getDisplay().asyncExec(uiRunnable); return; } if (event != null) { final IFacetedProjectWorkingCopy fpjwc = event.getWorkingCopy(); final IProjectFacetsChangedEvent evt = (IProjectFacetsChangedEvent) event; for (IProjectFacetVersion fv : evt.getAllAffectedFacets()) { final IProjectFacet f = fv.getProjectFacet(); final boolean checked = fpjwc.hasProjectFacet(fv); this.tableViewer.setChecked(f, checked); this.tableViewer.update(f, null); } } else { final List<IProjectFacet> facets = new ArrayList<IProjectFacet>(); for (IProjectFacetVersion fv : this.fpjwc.getProjectFacets()) { facets.add(fv.getProjectFacet()); } this.tableViewer.setCheckedElements(facets.toArray()); this.tableViewer.update(this.fpjwc.getAvailableFacets().keySet().toArray(), null); } } private void handleValidationProblemsChangedEvent() { if (!Thread.currentThread().equals(getDisplay().getThread())) { final Runnable uiRunnable = new Runnable() { public void run() { handleValidationProblemsChangedEvent(); } }; getDisplay().asyncExec(uiRunnable); return; } this.problemsView.refresh(); if (getFilteredProblems().length == 0) { if (this.sform1.getMaximizedControl() == null) { this.sform1.setMaximizedControl(facets); } } else { if (this.sform1.getMaximizedControl() != null) { this.sform1.setMaximizedControl(null); } } } private void handleModelChangedEvent(final IFacetedProjectEvent event) { switch (event.getType()) { case FIXED_FACETS_CHANGED: case TARGETED_RUNTIMES_CHANGED: { final Runnable runnable = new Runnable() { public void run() { refresh(); } }; runOnDisplayThread(getDisplay(), runnable); break; } } } private IStatus[] getFilteredProblems() { final IStatus[] unfiltered = this.fpjwc.validate().getChildren(); boolean somethingToRemove = false; for (IStatus st : unfiltered) { if (st.getCode() == IFacetedProjectWorkingCopy.PROBLEM_PROJECT_NAME) { somethingToRemove = true; break; } } if (!somethingToRemove) { return unfiltered; } final List<IStatus> filtered = new ArrayList<IStatus>(); for (IStatus st : unfiltered) { if (st.getCode() != IFacetedProjectWorkingCopy.PROBLEM_PROJECT_NAME) { filtered.add(st); } } return filtered.toArray(new IStatus[filtered.size()]); } private final class ContentProvider implements ITreeContentProvider { public Object[] getElements(final Object element) { final IFacetedProjectWorkingCopy fpjwc = getFacetedProjectWorkingCopy(); final List<Object> list = new ArrayList<Object>(); for (Map.Entry<IProjectFacet, SortedSet<IProjectFacetVersion>> entry : fpjwc.getAvailableFacets() .entrySet()) { final IProjectFacet f = entry.getKey(); final SortedSet<IProjectFacetVersion> availableVersions = entry.getValue(); if (f.getCategory() == null && !availableVersions.isEmpty()) { list.add(f); } } return list.toArray(); } public Object[] getChildren(final Object parent) { return new Object[0]; } public Object getParent(final Object element) { if (element instanceof IProjectFacet) { final IProjectFacet f = (IProjectFacet) element; return f.getCategory(); } else { return null; } } public boolean hasChildren(final Object element) { return false; } public void dispose() { } public void inputChanged(final Viewer viewer, final Object oldObject, final Object newObject) { } } private final class FacetColumnLabelProvider extends LabelProvider { @Override public String getText(final Object element) { return ((IProjectFacet) element).getLabel(); } @Override public Image getImage(final Object element) { return FacetsSelectionPanel.this.getImage((IProjectFacet) element, true); } } private static final class FixedFacetImageDescriptor extends CompositeImageDescriptor { private static final String OVERLAY_IMG_LOCATION = "images/lock.gif"; //$NON-NLS-1$ private static final ImageData OVERLAY = FacetUiPlugin.getImageDescriptor(OVERLAY_IMG_LOCATION) .getImageData(); private final ImageData base; private final Point size; public FixedFacetImageDescriptor(final ImageDescriptor base) { this.base = base.getImageData(); this.size = new Point(this.base.width, this.base.height); } protected void drawCompositeImage(final int width, final int height) { drawImage(this.base, 0, 0); drawImage(OVERLAY, 0, height - OVERLAY.height); } protected Point getSize() { return this.size; } } private static final class Sorter extends ViewerSorter { public int compare(final Viewer viewer, final Object a, final Object b) { return getLabel(a).compareToIgnoreCase(getLabel(b)); } private static String getLabel(final Object obj) { return ((IProjectFacet) obj).getLabel(); } } private static final class FixedFacetToolTip extends ToolTip { private static final int FAKE_EVENT_TYPE = -9999; private String message = ""; //$NON-NLS-1$ @Override protected Composite createToolTipContentArea(final Event event, final Composite parent) { final Display display = parent.getDisplay(); final Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(gl(1)); composite.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); final Label label = new Label(composite, SWT.WRAP); label.setLayoutData(gdwhint(gdfill(), 300)); label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); label.setText(this.message); return composite; } public void setMessage(final String message) { this.message = message; } public FixedFacetToolTip(final Control control) { super(control); setPopupDelay(0); setShift(new Point(10, 3)); } public void show(final Point location) { // The JFace ToolTip class does not support alternative methods of tool tip activation. // An enhancement request https://bugs.eclipse.org/bugs/show_bug.cgi?id=174844 tracks // this issue. When that enhancement request has been resolved, this hacky // implementation should be replaced with something more sensible. final Event fakeEvent = new Event(); fakeEvent.type = FAKE_EVENT_TYPE; fakeEvent.x = location.x; fakeEvent.y = location.y; try { final Method method = ToolTip.class.getDeclaredMethod("toolTipCreate", Event.class); //$NON-NLS-1$ method.setAccessible(true); method.invoke(this, fakeEvent); } catch (Exception e) { TMWCore.log(null, e); } } @Override protected final boolean shouldCreateToolTip(final Event event) { return (event.type == FAKE_EVENT_TYPE); } } private final class ProblemsContentProvider implements IStructuredContentProvider { public Object[] getElements(final Object element) { return getFilteredProblems(); } public void inputChanged(final Viewer viewer, final Object oldObject, final Object newObject) { } public void dispose() { } } private static final class ProblemsLabelProvider implements ITableLabelProvider { public String getColumnText(final Object element, final int column) { return ((IStatus) element).getMessage(); } public Image getColumnImage(final Object element, final int column) { final ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages(); final String imageType; if (((IStatus) element).getSeverity() == IStatus.ERROR) { imageType = ISharedImages.IMG_OBJS_ERROR_TSK; } else { imageType = ISharedImages.IMG_OBJS_WARN_TSK; } return sharedImages.getImage(imageType); } public boolean isLabelProperty(final Object obj, final String s) { return false; } public void dispose() { } public void addListener(final ILabelProviderListener listener) { } public void removeListener(ILabelProviderListener listener) { } } }