Java tutorial
/****************************************************************************** * Copyright (c) 2010, 2014 Oracle and Others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Konstantin Komissarchik - initial implementation and ongoing maintenance * Rastislav Wagner - [444850] FacetsSelectionPanel wont disable menu when it should ******************************************************************************/ package org.eclipse.wst.common.project.facet.ui.internal; import static java.lang.Math.max; 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.gdhfill; 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.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; 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.core.runtime.Platform; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.resource.CompositeImageDescriptor; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.EditingSupport; 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.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.jface.window.ToolTip; import org.eclipse.osgi.util.NLS; 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.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; 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.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.common.project.facet.core.ICategory; import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy; import org.eclipse.wst.common.project.facet.core.IPreset; 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.ProjectFacetsManager; 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.internal.ProjectFacet; 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.ModifyFacetedProjectWizard; import org.eclipse.wst.common.project.facet.ui.internal.util.BasicToolTip; import org.eclipse.wst.common.project.facet.ui.internal.util.HeaderToolTip; import org.eclipse.wst.common.project.facet.ui.internal.util.ReadOnlyComboBoxCellEditor; import org.osgi.framework.Bundle; /** * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ public final class FacetsSelectionPanel extends Composite implements ISelectionProvider { private static final String IMG_DOWN_ARROW = "##down-arrow##"; //$NON-NLS-1$ private final Composite topComposite; private final SashForm sform1; private final SashForm sform2; private final Label presetsLabel; private final Combo presetsCombo; private final Button savePresetButton; private final Button deletePresetButton; private final CheckboxTreeViewer treeViewer; private final Tree tree; private final TreeViewerColumn colFacet; private final TreeViewerColumn colVersion; private final FixedFacetToolTip fixedFacetToolTip; private final Menu popupMenu; private final MenuItem popupMenuLockUnlock; private final MenuItem popupMenuChangeVersion; private final TableViewer problemsView; private final TabItem detailsTabItem; private final DetailsPanel detailsPanel; private final TabItem runtimesTabItem; private final RuntimesPanel runtimesPanel; 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; /** * Holds images used throughout the panel. */ private final ImageRegistry imageRegistry; private final IRuntimeLifecycleListener runtimeLifecycleListener; public interface IFilter { boolean check(IProjectFacetVersion fv); } 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(); final Bundle bundle = Platform.getBundle(FacetUiPlugin.PLUGIN_ID); URL url = bundle.getEntry("images/down-arrow.gif"); //$NON-NLS-1$ this.imageRegistry.put(IMG_DOWN_ARROW, ImageDescriptor.createFromURL(url)); // Layout the panel. setLayout(glmargins(gl(1), 0, 0)); this.topComposite = new Composite(this, SWT.NONE); this.topComposite.setLayout(glmargins(gl(4), 0, 0)); this.presetsLabel = new Label(this.topComposite, SWT.NONE); this.presetsLabel.setText(Resources.presetsLabel); this.presetsCombo = new Combo(this.topComposite, SWT.READ_ONLY); this.presetsCombo.setLayoutData(gdhfill()); this.savePresetButton = new Button(this.topComposite, SWT.PUSH); this.savePresetButton.setText(Resources.saveButtonLabel); GridDataFactory.defaultsFor(this.savePresetButton).applyTo(this.savePresetButton); this.savePresetButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(final SelectionEvent e) { handleSavePreset(); } }); this.deletePresetButton = new Button(this.topComposite, SWT.PUSH); this.deletePresetButton.setText(Resources.deleteButtonLabel); GridDataFactory.defaultsFor(this.deletePresetButton).applyTo(this.deletePresetButton); this.deletePresetButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(final SelectionEvent e) { handleDeletePreset(); } }); this.sform1 = new SashForm(this.topComposite, SWT.VERTICAL | SWT.SMOOTH); this.sform1.setLayoutData(gdhspan(gdfill(), 4)); this.sform2 = new SashForm(this.sform1, SWT.HORIZONTAL | SWT.SMOOTH); this.sform2.setLayoutData(gdhspan(gdfill(), 4)); this.treeViewer = new CheckboxTreeViewer(this.sform2, SWT.BORDER); this.tree = this.treeViewer.getTree(); this.tree.setHeaderVisible(true); this.treeViewer.setContentProvider(new ContentProvider()); this.treeViewer.setSorter(new Sorter()); this.colFacet = new TreeViewerColumn(this.treeViewer, SWT.NONE); this.colFacet.getColumn().setText(Resources.facetColumnLabel); this.colFacet.getColumn().setResizable(true); this.colFacet.setLabelProvider(new FacetColumnLabelProvider()); this.colFacet.getColumn().setWidth(computeDefaultFacetColumnWidth()); this.colVersion = new TreeViewerColumn(this.treeViewer, SWT.NONE); this.colVersion.getColumn().setText(Resources.versionColumnLabel); this.colVersion.getColumn().setResizable(true); this.colVersion.setLabelProvider(new FacetVersionColumnLabelProvider()); this.colVersion.setEditingSupport(new FacetVersionColumnEditingSupport(this.treeViewer)); this.colVersion.getColumn().setWidth(computeDefaultVersionColumnWidth()); this.popupMenu = new Menu(getShell(), SWT.POP_UP); this.popupMenuChangeVersion = new MenuItem(this.popupMenu, SWT.PUSH); this.popupMenuChangeVersion.setText(Resources.changeVersionMenuItem); this.popupMenuChangeVersion.addSelectionListener(new SelectionAdapter() { public void widgetSelected(final SelectionEvent e) { handleChangeVersionMenuSelected(); } }); this.popupMenuLockUnlock = new MenuItem(this.popupMenu, SWT.PUSH); this.popupMenuLockUnlock.addSelectionListener(new SelectionAdapter() { public void widgetSelected(final SelectionEvent e) { handleFacetLockUnlock(); } }); new FacetToolTip(this.tree); new CategoryToolTip(this.tree); this.fixedFacetToolTip = new FixedFacetToolTip(this.tree); this.treeViewer.setInput(new Object()); this.treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(final SelectionChangedEvent e) { FacetsSelectionPanel.this.handleSelectionChangedEvent(); } }); this.treeViewer.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(final CheckStateChangedEvent e) { FacetsSelectionPanel.this.handleCheckStateChanged(e); } }); this.tree.addListener(SWT.PaintItem, new Listener() { public void handleEvent(final Event event) { handlePaintItemEvent(event); } }); this.tree.addListener(SWT.MouseDown, new Listener() { public void handleEvent(final Event event) { handleMouseDownEvent(event); } }); this.tree.addMenuDetectListener(new MenuDetectListener() { public void menuDetected(MenuDetectEvent arg0) { updatePopupMenu(); } }); final TabFolder tabFolder = new TabFolder(this.sform2, SWT.NONE); tabFolder.setLayoutData(gdhhint(gdhfill(), 80)); this.detailsPanel = new DetailsPanel(tabFolder, this); this.detailsTabItem = new TabItem(tabFolder, SWT.NULL); this.detailsTabItem.setControl(this.detailsPanel); this.detailsTabItem.setText(Resources.detailsTabLabel); this.runtimesPanel = new RuntimesPanel(tabFolder, this.fpjwc); this.runtimesTabItem = new TabItem(tabFolder, SWT.NULL); this.runtimesTabItem.setControl(this.runtimesPanel); this.runtimesTabItem.setText(Resources.runtimesTabLabel); 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) { handleSelectedPresetChangedEvent(); } }, IFacetedProjectEvent.Type.SELECTED_PRESET_CHANGED); ModifyFacetedProjectWizard.syncWithPresetsModel(this.fpjwc, this.presetsCombo); 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.tree); int prefWidthRuntimesPanel = getPreferredWidth(this.runtimesPanel); prefWidthRuntimesPanel = max(prefWidthRuntimesPanel, 300); final int prefWidth = prefWidthTree + prefWidthRuntimesPanel + 80; this.topComposite.setLayoutData(gdwhint(gdhhint(gdfill(), 500), prefWidth)); this.sform1.setWeights(new int[] { 70, 30 }); this.sform2.setWeights(new int[] { prefWidthTree, prefWidthRuntimesPanel }); // Select the first item in the table. if (this.tree.getItemCount() > 0) { final TreeItem firstItem = this.tree.getItem(0); this.treeViewer.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.tree.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; } public Image getImage(final ICategory category) { final String id = "c:" + category.getId(); //$NON-NLS-1$ Image image = getImageRegistry().get(id); if (image == null) { final IDecorationsProvider decprov = (IDecorationsProvider) category .getAdapter(IDecorationsProvider.class); final ImageDescriptor imgdesc = decprov.getIcon(); 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.treeViewer.getCheckedElements(); this.treeViewer.refresh(); this.treeViewer.setCheckedElements(checked); } public void setCategoryExpandedState(final ICategory category, final boolean expanded) { this.treeViewer.setExpandedState(category, expanded); } public boolean getShowToolTips() { return this.showToolTips; } public void setShowToolTips(final boolean showToolTips) { this.showToolTips = showToolTips; } private void refreshCategoryState(final ICategory category) { if (category == null) { return; } int available = 0; int selected = 0; for (IProjectFacet f : category.getProjectFacets()) { if (this.fpjwc.isFacetAvailable(f)) { available++; } if (this.fpjwc.hasProjectFacet(f)) { selected++; } } if (selected == 0) { this.treeViewer.setChecked(category, false); this.treeViewer.setGrayed(category, false); } else if (selected == available) { this.treeViewer.setChecked(category, true); this.treeViewer.setGrayed(category, false); } else { this.treeViewer.setGrayChecked(category, true); } } 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 setSelectedVersion(final IProjectFacet f, final IProjectFacetVersion fv) { if (this.fpjwc.getProjectFacetVersion(f) != null) { this.fpjwc.changeProjectFacetVersion(fv); } this.selectedVersions.put(f, fv); if (f == this.getSelectedProjectFacet()) { this.selection = fv; notifySelectionChangedListeners(); } } private void handleSelectionChangedEvent() { Object selection = getCurrentSelection(); if (selection != this.selection) { this.selection = selection; notifySelectionChangedListeners(); } } private void handleCheckStateChanged(final CheckStateChangedEvent event) { final Object el = event.getElement(); final boolean checked = event.getChecked(); if (el instanceof IProjectFacet) { final IProjectFacet f = (IProjectFacet) el; if (this.fpjwc.getFixedProjectFacets().contains(f)) { if (!checked) { this.treeViewer.setChecked(el, true); final String msg = NLS.bind(Resources.couldNotDeselectFixedFacetMessage, f.getLabel()); this.fixedFacetToolTip.setMessage(msg); final Point cursorLocation = getDisplay().getCursorLocation(); this.fixedFacetToolTip.show(this.tree.toControl(cursorLocation)); } return; } if (checked) { this.fpjwc.addProjectFacet(getSelectedVersion(f)); } else { this.fpjwc.removeProjectFacet(f); } refreshCategoryState(f.getCategory()); } else { final ContentProvider cp = (ContentProvider) this.treeViewer.getContentProvider(); final Set<IProjectFacetVersion> facets = new HashSet<IProjectFacetVersion>( this.fpjwc.getProjectFacets()); final Object[] children = cp.getChildren(el); int selected = 0; for (Object child : children) { final IProjectFacet f = (IProjectFacet) child; if (!this.fpjwc.getFixedProjectFacets().contains(f)) { final IProjectFacetVersion fv = getSelectedVersion(f); if (checked) { facets.add(fv); } else { facets.remove(fv); } this.treeViewer.setChecked(f, checked); } if (this.fpjwc.hasProjectFacet(f)) { selected++; } } if (selected == 0 || selected == children.length) { this.treeViewer.setGrayed(el, false); } else { this.treeViewer.setGrayChecked(el, true); } this.fpjwc.setProjectFacets(facets); } this.fpjwc.setSelectedPreset(null); } private void handleMouseDownEvent(final Event event) { handleMouseDownEventHelper(event, this.tree.getItems()); } private boolean handleMouseDownEventHelper(final Event event, final TreeItem[] items) { for (TreeItem item : items) { if (item.getBounds(1).contains(event.x, event.y)) { final TreeItem[] newSelection = new TreeItem[] { item }; if (!Arrays.equals(this.tree.getSelection(), newSelection)) { this.tree.setSelection(new TreeItem[] { item }); this.treeViewer.editElement(item.getData(), 1); } return true; } else if (handleMouseDownEventHelper(event, item.getItems())) { return true; } } return false; } private void handlePaintItemEvent(final Event event) { final TreeItem item = (TreeItem) event.item; final Object itemData = item.getData(); if (itemData instanceof IProjectFacet && event.index == 1) { final IProjectFacet f = (IProjectFacet) itemData; if (this.fpjwc.getAvailableVersions(f).size() > 1) { final Image arrowImage = getImageRegistry().get(IMG_DOWN_ARROW); final Rectangle arrowImageBounds = arrowImage.getBounds(); final int columnWidth = this.colVersion.getColumn().getWidth(); final int itemHeight = this.tree.getItemHeight(); int x, y; x = event.x + columnWidth - arrowImageBounds.width - 10; y = event.y; event.gc.fillRectangle(x, y, arrowImageBounds.width + 10, itemHeight); y = event.y + (itemHeight - arrowImageBounds.height) / 2; event.gc.drawImage(arrowImage, x, y); } } } private void handleDisposeEvent() { this.imageRegistry.dispose(); for (IFacetedProjectListener listener : this.registeredWorkingCopyListeners) { this.fpjwc.removeListener(listener); } RuntimeManager.removeListener(this.runtimeLifecycleListener); } private void handleSavePreset() { final Set<IProjectFacetVersion> facets = this.fpjwc.getProjectFacets(); final IPreset preset = SavePresetDialog.showDialog(getShell(), facets); if (preset != null) { this.fpjwc.setSelectedPreset(preset.getId()); } } private void handleDeletePreset() { final IPreset preset = this.fpjwc.getSelectedPreset(); this.fpjwc.setSelectedPreset(null); ProjectFacetsManager.deletePreset(preset); } 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; } final Set<ICategory> affectedCategories = new HashSet<ICategory>(); 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.treeViewer.setChecked(f, checked); this.treeViewer.update(f, null); final ICategory category = f.getCategory(); if (category != null) { affectedCategories.add(category); } } } else { final List<IProjectFacet> facets = new ArrayList<IProjectFacet>(); for (IProjectFacetVersion fv : this.fpjwc.getProjectFacets()) { facets.add(fv.getProjectFacet()); } this.treeViewer.setCheckedElements(facets.toArray()); for (IProjectFacet facet : this.fpjwc.getAvailableFacets().keySet()) { final ICategory category = facet.getCategory(); if (category != null) { affectedCategories.add(category); } } this.treeViewer.update(this.fpjwc.getAvailableFacets().keySet().toArray(), null); } for (ICategory category : affectedCategories) { refreshCategoryState(category); } } 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(this.sform2); } } else { if (this.sform1.getMaximizedControl() != null) { this.sform1.setMaximizedControl(null); } } } private void handleSelectedPresetChangedEvent() { final IPreset preset = this.fpjwc.getSelectedPreset(); if (preset == null) { this.savePresetButton.setEnabled(true); this.deletePresetButton.setEnabled(false); } else { this.savePresetButton.setEnabled(false); this.deletePresetButton.setEnabled(preset.getType() == IPreset.Type.USER_DEFINED); } } 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 void handleChangeVersionMenuSelected() { final IProjectFacet f = getSelectedProjectFacet(); final IProjectFacetVersion fv = getSelectedVersion(f); final SortedSet<IProjectFacetVersion> versions = this.fpjwc.getAvailableVersions(f); final IProjectFacetVersion newVersion = ChangeFacetVersionDialog.showDialog(getShell(), f, fv, versions); if (newVersion != null) { this.fpjwc.changeProjectFacetVersion(newVersion); } } private void handleFacetLockUnlock() { final IProjectFacet f = getSelectedProjectFacet(); final Set<IProjectFacet> fixedFacets = new HashSet<IProjectFacet>(this.fpjwc.getFixedProjectFacets()); if (fixedFacets.contains(f)) { fixedFacets.remove(f); } else { fixedFacets.add(f); } this.fpjwc.setFixedProjectFacets(fixedFacets); } private void updatePopupMenu() { Object selection = getCurrentSelection(); if (selection instanceof IProjectFacetVersion) { this.tree.setMenu(this.popupMenu); final IProjectFacet f = ((IProjectFacetVersion) selection).getProjectFacet(); if (this.fpjwc.isFixedProjectFacet(f)) { this.popupMenuLockUnlock.setText(Resources.unlockMenuItem); } else { this.popupMenuLockUnlock.setText(Resources.lockMenuItem); } this.popupMenuLockUnlock.setEnabled(this.fpjwc.hasProjectFacet(f)); final int numAvailableVersions = this.fpjwc.getAvailableVersions(f).size(); this.popupMenuChangeVersion.setEnabled(numAvailableVersions > 1); } else { this.tree.setMenu(null); } } private Object getCurrentSelection() { Object selection = ((IStructuredSelection) this.treeViewer.getSelection()).getFirstElement(); if (selection != null && selection instanceof IProjectFacet) { return getSelectedVersion((IProjectFacet) selection); } return null; } private TreeItem getTreeItem(final int x, final int y) { return getTreeItemHelper(x, y, this.tree.getItems()); } private static TreeItem getTreeItemHelper(final int x, final int y, final TreeItem[] items) { for (TreeItem item : items) { if (item.getBounds().contains(x, y)) { return item; } final TreeItem res = getTreeItemHelper(x, y, item.getItems()); if (res != null) { return res; } } return null; } private int computeDefaultFacetColumnWidth() { final GC gc = new GC(this.getDisplay()); int maxFacetLabelWidth = 0; try { gc.setFont(this.tree.getFont()); for (IProjectFacet f : ProjectFacetsManager.getProjectFacets()) { maxFacetLabelWidth = max(maxFacetLabelWidth, gc.textExtent(f.getLabel()).x); } } finally { gc.dispose(); } return max(maxFacetLabelWidth + 100, 200); } private int computeDefaultVersionColumnWidth() { final GC gc = new GC(this.getDisplay()); int maxVersionStringWidth = 0; final int columnLabelWidth; try { gc.setFont(this.tree.getFont()); for (IProjectFacet f : ProjectFacetsManager.getProjectFacets()) { for (IProjectFacetVersion fv : f.getVersions()) { final int textExtent = gc.textExtent(fv.getVersionString()).x; maxVersionStringWidth = max(maxVersionStringWidth, textExtent + 30); } } columnLabelWidth = gc.textExtent(Resources.versionColumnLabel).x + 30; } finally { gc.dispose(); } return max(maxVersionStringWidth, columnLabelWidth); } 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>(); final Set<ICategory> categories = ProjectFacetsManager.getCategories(); for (ICategory cat : categories) { boolean visible = false; for (IProjectFacet f : cat.getProjectFacets()) { if (!fpjwc.getAvailableVersions(f).isEmpty()) { visible = true; break; } } if (visible) { list.add(cat); } } 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) { if (parent instanceof ICategory) { final IFacetedProjectWorkingCopy fpjwc = getFacetedProjectWorkingCopy(); final ICategory category = (ICategory) parent; final List<IProjectFacet> facets = new ArrayList<IProjectFacet>(); for (IProjectFacet f : category.getProjectFacets()) { if (!fpjwc.getAvailableVersions(f).isEmpty()) { facets.add(f); } } return facets.toArray(); } else { 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 (element instanceof ICategory) && !((ICategory) element).getProjectFacets().isEmpty(); } public void dispose() { } public void inputChanged(final Viewer viewer, final Object oldObject, final Object newObject) { } } private final class FacetColumnLabelProvider extends ColumnLabelProvider { @Override public String getText(final Object element) { if (element instanceof ICategory) { return ((ICategory) element).getLabel(); } else { return ((IProjectFacet) element).getLabel(); } } @Override public Image getImage(final Object element) { if (element instanceof IProjectFacet) { return FacetsSelectionPanel.this.getImage((IProjectFacet) element, true); } else { return FacetsSelectionPanel.this.getImage((ICategory) element); } } } private final class FacetVersionColumnLabelProvider extends ColumnLabelProvider { @Override public String getText(final Object element) { if (element instanceof IProjectFacet) { final ProjectFacet f = (ProjectFacet) element; if (!f.isVersionHidden()) { return getSelectedVersion(f).getVersionString(); } } return null; } } private final class FacetVersionColumnEditingSupport extends EditingSupport { private final ReadOnlyComboBoxCellEditor ceditor; private final IFacetedProjectWorkingCopy fpjwc; public FacetVersionColumnEditingSupport(final TreeViewer treeViewer) { super(treeViewer); this.ceditor = new ReadOnlyComboBoxCellEditor(treeViewer.getTree(), new String[0], SWT.DROP_DOWN | SWT.READ_ONLY); this.fpjwc = getFacetedProjectWorkingCopy(); } @Override public boolean canEdit(final Object element) { return element instanceof IProjectFacet && this.fpjwc.getAvailableVersions((IProjectFacet) element).size() > 1; } @Override protected CellEditor getCellEditor(final Object element) { final IProjectFacet f = (IProjectFacet) element; if (f == null) { throw new IllegalStateException(); } final SortedSet<IProjectFacetVersion> versions = this.fpjwc.getAvailableVersions(f); final String[] verstrs = new String[versions.size()]; Integer value = null; int i = 0; for (IProjectFacetVersion fv : versions) { verstrs[i] = fv.getVersionString(); if (fv == getSelectedVersion(f)) { value = new Integer(i); } i++; } this.ceditor.setItems(verstrs); this.ceditor.setValue(value); return this.ceditor; } @Override public Object getValue(final Object element) { final IProjectFacet f = (IProjectFacet) element; int i = 0; for (IProjectFacetVersion fv : this.fpjwc.getAvailableVersions(f)) { if (fv == getSelectedVersion(f)) { return new Integer(i); } i++; } return new IllegalStateException(); } @Override public void setValue(final Object element, final Object value) { final IProjectFacet f = (IProjectFacet) element; final int index = ((Integer) value).intValue(); if (index != -1) { int i = 0; for (IProjectFacetVersion fv : this.fpjwc.getAvailableVersions(f)) { if (i == index) { setSelectedVersion(f, fv); FacetsSelectionPanel.this.treeViewer.update(f, null); break; } i++; } } } } 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) { if (obj instanceof IProjectFacet) { return ((IProjectFacet) obj).getLabel(); } else { return ((ICategory) obj).getLabel(); } } } private final class FacetToolTip extends HeaderToolTip { public FacetToolTip(final Control control) { super(control); } @Override protected final boolean shouldCreateToolTip(final Event event) { if (getShowToolTips() == false) { return false; } final TreeItem treeItem = getTreeItem(event.x, event.y); String description = null; if (treeItem != null && treeItem.getBounds(0).contains(event.x, event.y)) { final Object treeItemData = treeItem.getData(); if (treeItemData instanceof IProjectFacet) { description = ((IProjectFacet) treeItemData).getDescription(); } } return (description != null && description.trim().length() > 0); } @Override protected String getToolTipTitle(final Event event) { final IProjectFacet f = (IProjectFacet) getTreeItem(event.x, event.y).getData(); return getSelectedVersion(f).toString(); } @Override protected Composite createContentArea(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(gdfill()); label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); final IProjectFacet f = (IProjectFacet) getTreeItem(event.x, event.y).getData(); label.setText(f.getDescription()); return composite; } } private final class CategoryToolTip extends HeaderToolTip { public CategoryToolTip(final Control control) { super(control); } @Override protected final boolean shouldCreateToolTip(final Event event) { if (getShowToolTips() == false) { return false; } final TreeItem treeItem = getTreeItem(event.x, event.y); String description = null; if (treeItem != null && treeItem.getBounds(0).contains(event.x, event.y)) { final Object treeItemData = treeItem.getData(); if (treeItemData instanceof ICategory) { description = ((ICategory) treeItemData).getDescription(); } } return (description != null && description.trim().length() > 0); } @Override protected String getToolTipTitle(final Event event) { return ((ICategory) getTreeItem(event.x, event.y).getData()).getLabel(); } @Override protected Composite createContentArea(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(gdfill()); label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); final ICategory category = (ICategory) getTreeItem(event.x, event.y).getData(); label.setText(category.getDescription()); return composite; } } private final class FixedFacetToolTip extends BasicToolTip { private static final int FAKE_EVENT_TYPE = -9999; public FixedFacetToolTip(final Control control) { super(control); setPopupDelay(0); } 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) { FacetUiPlugin.log(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 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) { } } private static final class Resources extends NLS { public static String presetsLabel; public static String saveButtonLabel; public static String deleteButtonLabel; public static String facetColumnLabel; public static String versionColumnLabel; public static String couldNotDeselectFixedFacetMessage; public static String detailsTabLabel; public static String runtimesTabLabel; public static String lockMenuItem; public static String unlockMenuItem; public static String changeVersionMenuItem; static { initializeMessages(FacetsSelectionPanel.class.getName(), Resources.class); } } }