/******************************************************************************* * Copyright (c) 2011, 2014 Wind River Systems, Inc. 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: * Wind River Systems - initial API and implementation * Tobias Schwarz (Wind River) - [368243] [UI] Allow dynamic new wizard contributions *******************************************************************************/ package org.eclipse.tcf.te.ui.wizards.newWizard; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.expressions.EvaluationContext; import org.eclipse.core.expressions.EvaluationResult; import org.eclipse.core.expressions.Expression; import org.eclipse.core.expressions.ExpressionConverter; import org.eclipse.core.expressions.IEvaluationContext; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IBasicPropertyConstants; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.wizard.IWizard; import org.eclipse.jface.wizard.IWizardContainer; import org.eclipse.jface.wizard.IWizardNode; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.tcf.te.ui.activator.UIPlugin; import org.eclipse.tcf.te.ui.interfaces.IUIConstants; import org.eclipse.tcf.te.ui.nls.Messages; import org.eclipse.ui.ISelectionService; import org.eclipse.ui.ISources; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.activities.ITriggerPoint; import org.eclipse.ui.activities.WorkbenchActivityHelper; import org.eclipse.ui.dialogs.FilteredTree; import org.eclipse.ui.dialogs.PatternFilter; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints; import org.eclipse.ui.internal.dialogs.WizardPatternFilter; import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.wizards.IWizardCategory; import org.eclipse.ui.wizards.IWizardDescriptor; /** * The New Target creation wizard selection page implementation. */ @SuppressWarnings("restriction") public class NewWizardSelectionPage extends WizardPage { // The wizards settings storage id where the expanded categories are remembered private static final String EXPANDED_CATEGORIES_SETTINGS_ID = "filteredTree.expandedCatogryIds"; //$NON-NLS-1$ // The wizards settings storage id where the selected wizard descriptor id is remembered private static final String SELECTED_WIZARD_DESCRIPTOR_SETTINGS_ID = "filteredTree.selectedWizardDescriptorId"; //$NON-NLS-1$ // The default expanded category id's private static final String[] DEFAULT_EXPANDED_CATEGORY_IDS = new String[] { "org.eclipse.tcf.te.ui.newWizards.category.general" }; //$NON-NLS-1$ // The new target wizard registry private NewWizardRegistry wizardRegistry; private IWizardCategory category; // References to the page subcontrol's private FilteredTree filteredTree; private PatternFilter filteredTreeFilter; // The selected wizard descriptor private IWizardDescriptor selectedWizardDescriptor; // The wizard nodes per wizard descriptor private final Map<IWizardDescriptor, IWizardNode> wizardNodes = new HashMap<IWizardDescriptor, IWizardNode>(); // The workbench instance as passed in by init(...) private IWorkbench workbench; // The selection as passed in by init(...) private IStructuredSelection selection; /** * Internal class. The wizard viewer comparator is responsible for * the sorting in the tree. Current implementation is not prioritizing * categories. */ /* default */ static class NewWizardViewerComparator extends ViewerComparator { /* (non-Javadoc) * @see org.eclipse.jface.viewers.ViewerComparator#isSorterProperty(java.lang.Object, java.lang.String) */ @Override public boolean isSorterProperty(Object element, String property) { // The comparator is affected if the label of the elements should change. return property.equals(IBasicPropertyConstants.P_TEXT); } } /** * Internal class. The wizard viewer filter is responsible for filtering * wizard contributions based on their enablement expression. */ /* default */ static class NewWizardViewerFilter extends ViewerFilter { /* (non-Javadoc) * @see org.eclipse.jface.viewers.ViewerFilter#select(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof WorkbenchWizardElement) { IConfigurationElement configElement = ((WorkbenchWizardElement)element).getConfigurationElement(); // Determine the value of the "hideWizard" attribute first boolean isHidden = false; String value = configElement.getAttribute("hideWizard"); //$NON-NLS-1$ if (value != null && !"".equals(value)) isHidden = Boolean.parseBoolean(value); //$NON-NLS-1$ if (isHidden) return false; // Determine the visibility from the enablement IConfigurationElement[] children = configElement.getChildren("enablement"); //$NON-NLS-1$ // Either 0 or 1 enablement child elements are allowed if (children != null && children.length > 0) { try { Expression expression = ExpressionConverter.getDefault().perform(children[0]); if (expression != null) { // The selection passed to the expression is the "System Management" view tree selection ISelectionService selectionService = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); ISelection selection = selectionService != null ? selectionService.getSelection("org.eclipse.tcf.te.ui.views.View") : StructuredSelection.EMPTY; //$NON-NLS-1$ if (selection == null) { return false; } IEvaluationContext currentState = ((IHandlerService)PlatformUI.getWorkbench().getService(IHandlerService.class)).getCurrentState(); EvaluationContext evalContext = new EvaluationContext(currentState, selection); evalContext.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection); evalContext.setAllowPluginActivation(true); if (!expression.evaluate(evalContext).equals(EvaluationResult.TRUE)) { return false; } } } catch (CoreException e) { if (Platform.inDebugMode()) { IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), NLS.bind(Messages.NewWizardViewerFilter_error_evaluationFailed, e.getLocalizedMessage()), e); UIPlugin.getDefault().getLog().log(status); } } } } return true; } } /** * Constructor. * * @param wizardRegistry The new target wizard registry. Must not be <code>null</code>. */ public NewWizardSelectionPage(NewWizardRegistry wizardRegistry, IWizardCategory category) { super(NewWizardSelectionPage.class.getSimpleName()); setTitle(getDefaultTitle()); setDescription(getDefaultDescription()); Assert.isNotNull(wizardRegistry); this.wizardRegistry = wizardRegistry; this.category = category; } /** * Returns the default page title. * * @return The default page title. Must be never <code>null</code>. */ protected String getDefaultTitle() { return Messages.NewWizardSelectionPage_title; } /** * Returns the default page description. * * @return The default page description. Must be never <code>null</code>. */ protected String getDefaultDescription() { return Messages.NewWizardSelectionPage_description; } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) */ @Override public void createControl(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout()); composite.setLayoutData(new GridData(GridData.FILL_BOTH)); Label label = new Label(composite, SWT.NONE); label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); label.setText(Messages.NewWizardSelectionPage_wizards); label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); filteredTreeFilter = new WizardPatternFilter(); filteredTree = new FilteredTree(composite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER, filteredTreeFilter, true); filteredTree.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); GridData layoutData = new GridData(GridData.FILL_BOTH); layoutData.heightHint = 325; layoutData.widthHint = 450; filteredTree.setLayoutData(layoutData); final TreeViewer treeViewer = filteredTree.getViewer(); treeViewer.setContentProvider(new NewWizardContentProvider()); treeViewer.setLabelProvider(WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider()); treeViewer.setComparator(new NewWizardViewerComparator()); treeViewer.addFilter(new NewWizardViewerFilter()); treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { onSelectionChanged(); } }); treeViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { // Double-click on a connection type is triggering the sub wizard if (event.getSelection() instanceof IStructuredSelection) { IStructuredSelection selection = (IStructuredSelection)event.getSelection(); // The tree is single selection, so look for the first element only. Object element = selection.getFirstElement(); if (element instanceof IWizardDescriptor) { // Double-click on a connection type is triggering the sub wizard if (canFlipToNextPage()) { getWizard().getContainer().showPage(getNextPage()); } } else if (event.getViewer() instanceof TreeViewer) { TreeViewer viewer = (TreeViewer)event.getViewer(); if (viewer.isExpandable(element)) { viewer.setExpandedState(element, !viewer.getExpandedState(element)); } } } } }); treeViewer.setInput(category != null ? category : wizardRegistry); // apply the standard dialog font Dialog.applyDialogFont(composite); setControl(composite); // Restore the tree action restoreWidgetValues(); // Initialize the context help id PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IUIConstants.HELP_NEW_WIZARD_SELECTION_PAGE); } /** * Initialize the page with the current workbench instance and the * current workbench selection. * * @param workbench The current workbench. * @param selection The current object selection. */ public void init(IWorkbench workbench, IStructuredSelection selection) { this.workbench = workbench; this.selection = selection; } /** * Returns the current workbench. * * @return The current workbench or <code>null</code> if not set. */ public IWorkbench getWorkbench() { return workbench; } /** * Returns the current object selection. * * @return The current object selection or <code>null</code> if not set. */ public IStructuredSelection getSelection() { return selection; } /** * Called from the selection listener to propagate the current * system type selection to the underlying wizard. */ protected void onSelectionChanged() { if (filteredTree.getViewer().getSelection() instanceof IStructuredSelection) { IStructuredSelection filteredTreeSelection = (IStructuredSelection)filteredTree.getViewer().getSelection(); if (filteredTreeSelection.getFirstElement() instanceof IWizardDescriptor) { selectedWizardDescriptor = (IWizardDescriptor)filteredTreeSelection.getFirstElement(); // Update the description if the current wizard descriptor has one if (selectedWizardDescriptor.getDescription() != null && !"".equals(selectedWizardDescriptor.getDescription())) { //$NON-NLS-1$ setDescription(selectedWizardDescriptor.getDescription()); } else { if (!getDefaultDescription().equals(getDescription())) { setDescription(getDefaultDescription()); } } } else { selectedWizardDescriptor = null; } // Create the wizard node for the selected descriptor if not yet done // if (selectedWizardDescriptor != null && !wizardNodes.containsKey(selectedWizardDescriptor)) { // wizardNodes.put(selectedWizardDescriptor, new NewWizardNode(this, selectedWizardDescriptor)); // } } // Update the wizard container UI elements IWizardContainer container = getContainer(); if (container != null && container.getCurrentPage() != null) { container.updateWindowTitle(); container.updateTitleBar(); container.updateButtons(); } } /* (non-Javadoc) * @see org.eclipse.jface.wizard.WizardPage#getNextPage() */ @Override public IWizardPage getNextPage() { ITriggerPoint triggerPoint = workbench.getActivitySupport().getTriggerPointManager().getTriggerPoint(WorkbenchTriggerPoints.NEW_WIZARDS); if (triggerPoint == null || WorkbenchActivityHelper.allowUseOf(triggerPoint, getSelectedNode())) { IWizardNode selectedNode = getSelectedNode(); if (selectedNode != null) { // Determine if the content got create before(!) triggering // the wizard creation boolean isCreated = selectedNode.isContentCreated(); // Get the wizard from the selected node (triggers wizard creation if needed) IWizard wizard = selectedNode.getWizard(); if (wizard != null) { // If the wizard got created by the call to getWizard(), // then allow the wizard to create its pages if (!isCreated) { wizard.addPages(); } // Return the starting page of the wizard return wizard.getStartingPage(); } } } return null; } /* (non-Javadoc) * @see org.eclipse.jface.wizard.WizardPage#canFlipToNextPage() */ @Override public boolean canFlipToNextPage() { if (selectedWizardDescriptor != null && selectedWizardDescriptor.hasPages()) { if (wizardNodes.get(selectedWizardDescriptor) != null) { super.canFlipToNextPage(); } return true; } return false; } /** * Returns if or if not the wizard can be finished early. * * @return <code>True</code> if the wizard can be finished early, <code>false</code> otherwise. */ public boolean canFinishEarly() { return selectedWizardDescriptor != null && selectedWizardDescriptor.canFinishEarly(); } /** * Returns the wizard node for the currently selected * wizard descriptor. * * @return The wizard node or <code>null</code> if none. */ public IWizardNode getSelectedNode() { IWizardNode node = null; if (selectedWizardDescriptor != null) { node = wizardNodes.get(selectedWizardDescriptor); if (node == null) { node = new NewWizardNode(this, selectedWizardDescriptor); wizardNodes.put(selectedWizardDescriptor, node); } } return node; } /* (non-Javadoc) * @see org.eclipse.jface.wizard.WizardPage#getDialogSettings() */ @Override protected IDialogSettings getDialogSettings() { // If the wizard is set and returns dialog settings, we re-use them here IDialogSettings settings = super.getDialogSettings(); // If the dialog settings could not set from the wizard, fallback to the plugin's // dialog settings store. if (settings == null) { settings = UIPlugin.getDefault().getDialogSettings(); } String sectionName = this.getClass().getName(); if (settings.getSection(sectionName) == null) { settings.addNewSection(sectionName); } settings = settings.getSection(sectionName); return settings; } /** * Restore the tree action from the dialog settings. */ public void restoreWidgetValues() { IDialogSettings settings = getDialogSettings(); if (settings != null) { if (category == null) { String[] expandedCategories = settings.getArray(EXPANDED_CATEGORIES_SETTINGS_ID); // by default we expand always the "General" category. if (expandedCategories == null) { expandedCategories = DEFAULT_EXPANDED_CATEGORY_IDS; } if (expandedCategories != null) { List<IWizardCategory> expanded = new ArrayList<IWizardCategory>(); for (String expandedCategorie : expandedCategories) { String categoryId = expandedCategorie; if (categoryId != null && !"".equals(categoryId.trim())) { //$NON-NLS-1$ IWizardCategory category = wizardRegistry.findCategory(categoryId); if (category != null && !expanded.contains(category) && category.getWizards().length > 0) { expanded.add(category); } } } if (expanded.size() > 0) { filteredTree.getViewer().setExpandedElements(expanded.toArray()); } } } String selectedWizardDescriptorId = settings.get(SELECTED_WIZARD_DESCRIPTOR_SETTINGS_ID); if (selectedWizardDescriptorId != null && !"".equals(selectedWizardDescriptorId.trim())) { //$NON-NLS-1$ IWizardDescriptor descriptor = wizardRegistry.findWizard(selectedWizardDescriptorId); if (descriptor != null) { filteredTree.getViewer().setSelection(new StructuredSelection(descriptor), true); } } } } /** * Saves the tree action to the wizards settings store. */ public void saveWidgetValues() { IDialogSettings settings = getDialogSettings(); if (settings != null) { List<String> expandedCategories = new ArrayList<String>(); Object[] expanded = filteredTree.getViewer().getVisibleExpandedElements(); for (Object element : expanded) { if (element instanceof IWizardCategory) { expandedCategories.add(((IWizardCategory)element).getId()); } } settings.put(EXPANDED_CATEGORIES_SETTINGS_ID, expandedCategories.toArray(new String[expandedCategories.size()])); if (selectedWizardDescriptor != null) { settings.put(SELECTED_WIZARD_DESCRIPTOR_SETTINGS_ID, selectedWizardDescriptor.getId()); } else { settings.put(SELECTED_WIZARD_DESCRIPTOR_SETTINGS_ID, ""); //$NON-NLS-1$ } } } }