| /******************************************************************************* |
| * Copyright (c) 2000, 2014 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| * Peter Friese <peter.friese@gentleware.com> - bug 194529, bug 196867 |
| * Sascha Becher <s.becher@qualitype.com> - bug 360894 |
| * Alexander Kurtakov <akurtako@redhat.com> - bug 415649 |
| * Brian de Alwis (MTI) - bug 429420 |
| *******************************************************************************/ |
| package org.eclipse.pde.internal.ui.editor.plugin; |
| |
| import java.util.*; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.jobs.IJobChangeEvent; |
| import org.eclipse.core.runtime.jobs.JobChangeAdapter; |
| import org.eclipse.jface.action.*; |
| import org.eclipse.jface.dialogs.IMessageProvider; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.*; |
| import org.eclipse.jface.wizard.WizardDialog; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.pde.core.IModelChangedEvent; |
| import org.eclipse.pde.core.plugin.*; |
| import org.eclipse.pde.internal.core.PDECore; |
| import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase; |
| import org.eclipse.pde.internal.core.ischema.*; |
| import org.eclipse.pde.internal.core.schema.SchemaRegistry; |
| import org.eclipse.pde.internal.core.text.IDocumentElementNode; |
| import org.eclipse.pde.internal.core.text.plugin.PluginBaseNode; |
| import org.eclipse.pde.internal.core.text.plugin.PluginExtensionNode; |
| import org.eclipse.pde.internal.ui.*; |
| import org.eclipse.pde.internal.ui.editor.*; |
| import org.eclipse.pde.internal.ui.editor.actions.*; |
| import org.eclipse.pde.internal.ui.editor.contentassist.XMLElementProposalComputer; |
| import org.eclipse.pde.internal.ui.elements.DefaultContentProvider; |
| import org.eclipse.pde.internal.ui.parts.TreePart; |
| import org.eclipse.pde.internal.ui.search.ExtensionsPatternFilter; |
| import org.eclipse.pde.internal.ui.search.PluginSearchActionGroup; |
| import org.eclipse.pde.internal.ui.util.*; |
| import org.eclipse.pde.internal.ui.wizards.extension.ExtensionEditorWizard; |
| import org.eclipse.pde.internal.ui.wizards.extension.NewExtensionWizard; |
| import org.eclipse.pde.ui.IExtensionEditorWizard; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.dnd.Clipboard; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.graphics.*; |
| import org.eclipse.swt.internal.BidiUtil; |
| import org.eclipse.swt.widgets.*; |
| import org.eclipse.ui.actions.ActionContext; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| import org.eclipse.ui.forms.widgets.Section; |
| import org.eclipse.ui.progress.WorkbenchJob; |
| |
| public class ExtensionsSection extends TreeSection implements IPropertyChangeListener { |
| private static final int REFRESHJOB_DELAY_TIME = 1200; // milliseconds to wait |
| private static final int ACCELERATED_SCROLLING = 15; // lines to skip |
| |
| // All constants changed for removal of search button |
| private static final int BUTTON_MOVE_DOWN = 4; |
| private static final int BUTTON_MOVE_UP = 3; |
| private static final int BUTTON_EDIT = 2; |
| private static final int BUTTON_REMOVE = 1; |
| private static final int BUTTON_ADD = 0; |
| private TreeViewer fExtensionTree; |
| private Image fExtensionImage; |
| private Image fGenericElementImage; |
| private FormFilteredTree fFilteredTree; |
| private ExtensionsPatternFilter fPatternFilter; |
| private SchemaRegistry fSchemaRegistry; |
| private Hashtable<String, ArrayList<IConfigurationElement>> fEditorWizards; |
| private SortAction fSortAction; |
| private CollapseAction fCollapseAction; |
| private ToggleExpandStateAction fExpandAction; |
| private FilterRelatedExtensionsAction fFilterRelatedAction; |
| private boolean fBypassFilterDelay = false; |
| |
| /** |
| * <code>label, name, class, id, commandId, property, activityId, attribute, value</code> |
| * <br> |
| * While adding elements to the array at the end is possible without concern, changing |
| * previous elements requires to refactor occurrences with indexed access to the array. |
| */ |
| // TODO common label properties might be configured through preferences |
| public static final String[] COMMON_LABEL_ATTRIBUTES = {"label", //$NON-NLS-1$ |
| "name", "locationURI", "class", "id", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| "commandId", "property", "activityId", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| "attribute", "value"}; //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| private static final String[] VALID_IMAGE_TYPES = {"png", "bmp", "ico", "gif", "jpg", "tiff"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
| private static final String MENU_NEW_ID = "NewMenu"; //$NON-NLS-1$ |
| |
| class ExtensionContentProvider extends DefaultContentProvider implements ITreeContentProvider { |
| public Object[] getChildren(Object parent) { |
| Object[] children = null; |
| if (parent instanceof IPluginBase) |
| children = ((IPluginBase) parent).getExtensions(); |
| else if (parent instanceof IPluginExtension) { |
| children = ((IPluginExtension) parent).getChildren(); |
| } else if (parent instanceof IPluginElement) { |
| children = ((IPluginElement) parent).getChildren(); |
| } |
| if (children == null) |
| children = new Object[0]; |
| return children; |
| } |
| |
| public boolean hasChildren(Object parent) { |
| return getChildren(parent).length > 0; |
| } |
| |
| public Object getParent(Object child) { |
| if (child instanceof IPluginExtension) { |
| return ((IPluginModelBase) getPage().getModel()).getPluginBase(); |
| } |
| if (child instanceof IPluginObject) |
| return ((IPluginObject) child).getParent(); |
| return null; |
| } |
| |
| public Object[] getElements(Object parent) { |
| return getChildren(parent); |
| } |
| } |
| |
| class ExtensionLabelProvider extends LabelProvider implements IFontProvider { |
| @Override |
| public String getText(Object obj) { |
| return resolveObjectName(obj); |
| } |
| |
| @Override |
| public Image getImage(Object obj) { |
| return resolveObjectImage(obj); |
| } |
| |
| public Font getFont(Object element) { |
| if (fFilteredTree.isFiltered() && fPatternFilter.getMatchingLeafs().contains(element)) { |
| return JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT); |
| } |
| return null; |
| } |
| } |
| |
| public ExtensionsSection(PDEFormPage page, Composite parent) { |
| super(page, parent, Section.DESCRIPTION, new String[] {/*PDEUIMessages.Actions_search_targetplatform,*/PDEUIMessages.ManifestEditor_DetailExtension_new, PDEUIMessages.ManifestEditor_DetailExtension_remove, PDEUIMessages.ManifestEditor_DetailExtension_edit, PDEUIMessages.ManifestEditor_DetailExtension_up, PDEUIMessages.ManifestEditor_DetailExtension_down}); |
| fHandleDefaultButton = false; |
| } |
| |
| private static void addItemsForExtensionWithSchema(MenuManager menu, IPluginExtension extension, IPluginParent parent) { |
| ISchema schema = getSchema(extension); |
| // Bug 213457 - look up elements based on the schema in which the parent is found |
| ISchemaElement elementInfo = null; |
| if (schema.getIncludes().length == 0 || parent == extension) { |
| String tagName = (parent == extension ? "extension" : parent.getName()); //$NON-NLS-1$ |
| elementInfo = schema.findElement(tagName); |
| } else { |
| Stack<String> stack = new Stack<String>(); |
| IPluginParent parentParent = parent; |
| while (parentParent != extension && parentParent != null) { |
| stack.push(parentParent.getName()); |
| parentParent = (IPluginParent) parentParent.getParent(); |
| } |
| while (!stack.isEmpty()) { |
| elementInfo = schema.findElement(stack.pop()); |
| schema = elementInfo.getSchema(); |
| } |
| } |
| |
| if ((elementInfo != null) && (elementInfo.getType() instanceof ISchemaComplexType) && (parent instanceof IDocumentElementNode)) { |
| // We have a schema complex type. Either the element has attributes |
| // or the element has children. |
| // Generate the list of element proposals |
| TreeSet<ISchemaElement> elementSet = XMLElementProposalComputer.computeElementProposal(elementInfo, (IDocumentElementNode) parent); |
| |
| // Create a corresponding menu entry for each element proposal; |
| // first add non-deprecated elements, then add deprecated elements |
| for (ISchemaElement element : elementSet) { |
| if (!element.isDeprecated()) { |
| Action action = new NewElementAction(element, parent); |
| menu.add(action); |
| } |
| } |
| menu.add(new Separator()); |
| for (ISchemaElement element : elementSet) { |
| if (element.isDeprecated()) { |
| Action action = new NewElementAction(element, parent); |
| menu.add(action); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @param parent |
| */ |
| private static ISchema getSchema(IPluginParent parent) { |
| if (parent instanceof IPluginExtension) { |
| return getSchema((IPluginExtension) parent); |
| } else if (parent instanceof IPluginElement) { |
| return getSchema((IPluginElement) parent); |
| } else { |
| return null; |
| } |
| } |
| |
| private static ISchema getSchema(IPluginExtension extension) { |
| String point = extension.getPoint(); |
| SchemaRegistry registry = PDECore.getDefault().getSchemaRegistry(); |
| return registry.getSchema(point); |
| } |
| |
| /** |
| * @param element |
| */ |
| static ISchemaElement getSchemaElement(IPluginElement element) { |
| ISchema schema = getSchema(element); |
| if (schema != null) { |
| return schema.findElement(element.getName()); |
| } |
| return null; |
| } |
| |
| /** |
| * @param element |
| */ |
| private static ISchema getSchema(IPluginElement element) { |
| IPluginObject parent = element.getParent(); |
| while (parent != null && !(parent instanceof IPluginExtension)) { |
| parent = parent.getParent(); |
| } |
| if (parent != null) { |
| return getSchema((IPluginExtension) parent); |
| } |
| return null; |
| } |
| |
| @Override |
| public void createClient(Section section, FormToolkit toolkit) { |
| initializeImages(); |
| Composite container = createClientContainer(section, 2, toolkit); |
| TreePart treePart = getTreePart(); |
| createViewerPartControl(container, SWT.MULTI | SWT.BORDER, 2, toolkit); |
| |
| fExtensionTree = treePart.getTreeViewer(); |
| fExtensionTree.setContentProvider(new ExtensionContentProvider()); |
| fExtensionTree.setLabelProvider(new ExtensionLabelProvider()); |
| toolkit.paintBordersFor(container); |
| section.setClient(container); |
| section.setDescription(PDEUIMessages.ExtensionsSection_sectionDescExtensionsMaster); |
| // See Bug # 160554: Set text before text client |
| section.setText(PDEUIMessages.ManifestEditor_DetailExtension_title); |
| initialize((IPluginModelBase) getPage().getModel()); |
| createSectionToolbar(section, toolkit); |
| // accelerated tree scrolling enabled |
| fFilteredTree.addMouseWheelListener(new AcceleratedTreeScrolling(fExtensionTree.getTree(), ACCELERATED_SCROLLING)); |
| toolkit.paintBordersFor(fFilteredTree.getParent()); |
| // Create the adapted listener for the filter entry field |
| fFilteredTree.createUIListenerEntryFilter(this); |
| final Text filterText = fFilteredTree.getFilterControl(); |
| if (filterText != null) { |
| filterText.addModifyListener(new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| StructuredViewer viewer = getStructuredViewerPart().getViewer(); |
| IStructuredSelection ssel = (IStructuredSelection) viewer.getSelection(); |
| updateButtons(ssel.size() != 1 ? null : ssel); |
| } |
| }); |
| } |
| } |
| |
| /** |
| * @param section |
| * @param toolkit |
| */ |
| private void createSectionToolbar(Section section, FormToolkit toolkit) { |
| ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT); |
| ToolBar toolbar = toolBarManager.createControl(section); |
| final Cursor handCursor = Display.getCurrent().getSystemCursor(SWT.CURSOR_HAND); |
| toolbar.setCursor(handCursor); |
| // Add sort action to the tool bar |
| fSortAction = new SortAction(fExtensionTree, PDEUIMessages.ExtensionsPage_sortAlpha, null, null, this) { |
| @Override |
| public void run() { |
| Object[] expanded = fFilteredTree.getViewer().getVisibleExpandedElements(); |
| try { |
| fFilteredTree.setRedraw(false); |
| super.run(); |
| // bugfix: retain tree expand state after sort action |
| fFilteredTree.getViewer().setExpandedElements(expanded); |
| } finally { |
| fFilteredTree.setRedraw(true); |
| } |
| } |
| }; |
| toolBarManager.add(fSortAction); |
| // Add expand selected leafs action to the toolbar |
| fExpandAction = new ToggleExpandStateAction(fFilteredTree, fExtensionTree); |
| toolBarManager.add(fExpandAction); |
| // Add collapse action to the tool bar |
| fCollapseAction = new CollapseAction(fExtensionTree, PDEUIMessages.ExtensionsPage_collapseAll); |
| toolBarManager.add(fCollapseAction); |
| |
| // Create filter action for context menu and global find keybinding |
| fFilterRelatedAction = new FilterRelatedExtensionsAction(fExtensionTree, fFilteredTree, this); |
| |
| toolBarManager.update(true); |
| |
| section.setTextClient(toolbar); |
| } |
| |
| @Override |
| protected void selectionChanged(IStructuredSelection selection) { |
| getPage().getPDEEditor().setSelection(selection); |
| updateButtons(selection); |
| getTreePart().getButton(BUTTON_EDIT).setVisible(isSelectionEditable(selection)); |
| } |
| |
| @Override |
| protected void buttonSelected(int index) { |
| switch (index) { |
| case BUTTON_ADD : |
| handleNew(); |
| break; |
| case BUTTON_REMOVE : |
| handleDelete(); |
| break; |
| case BUTTON_EDIT : |
| handleEdit(); |
| break; |
| case BUTTON_MOVE_UP : |
| handleMove(true); |
| break; |
| case BUTTON_MOVE_DOWN : |
| handleMove(false); |
| break; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.forms.AbstractFormPart#dispose() |
| */ |
| @Override |
| public void dispose() { |
| // Explicitly call the dispose method on the extensions tree |
| if (fFilteredTree != null) { |
| fFilteredTree.dispose(); |
| } |
| fEditorWizards = null; |
| IPluginModelBase model = (IPluginModelBase) getPage().getPDEEditor().getAggregateModel(); |
| if (model != null) |
| model.removeModelChangedListener(this); |
| super.dispose(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.PDESection#doGlobalAction(java.lang.String) |
| */ |
| @Override |
| public boolean doGlobalAction(String actionId) { |
| if (actionId.equals(ActionFactory.FIND.getId()) && fFilterRelatedAction != null) { |
| fFilterRelatedAction.run(); |
| return true; |
| } |
| if (!isEditable()) { |
| return false; |
| } |
| if (actionId.equals(ActionFactory.DELETE.getId())) { |
| handleDelete(); |
| return true; |
| } |
| if (actionId.equals(ActionFactory.CUT.getId())) { |
| if (isSingleSelection()) { |
| handleDelete(); |
| } |
| return true; |
| } |
| if (actionId.equals(ActionFactory.PASTE.getId())) { |
| if (isSingleSelection()) { |
| doPaste(); |
| } |
| return true; |
| } |
| if (actionId.equals(ActionFactory.SELECT_ALL.getId())) { |
| handleSelectAll(); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| @Override |
| public boolean setFormInput(Object object) { |
| if (object instanceof IPluginExtension || object instanceof IPluginElement) { |
| fExtensionTree.setSelection(new StructuredSelection(object), true); |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| protected void fillContextMenu(IMenuManager manager) { |
| ISelection selection = fExtensionTree.getSelection(); |
| final IStructuredSelection ssel = (IStructuredSelection) selection; |
| if (ssel.size() == 1) { |
| Object object = ssel.getFirstElement(); |
| if (object instanceof IPluginParent) { |
| IPluginParent parent = (IPluginParent) object; |
| if (parent.getModel().getUnderlyingResource() != null) { |
| boolean removeEnabled = !fFilteredTree.isFiltered() || isRemoveEnabled(ssel); |
| fillContextMenu(getPage(), parent, manager, false, removeEnabled); |
| manager.add(new Separator()); |
| } |
| } |
| manager.add(new Separator()); |
| if (object instanceof IPluginExtension) { |
| PluginSearchActionGroup actionGroup = new PluginSearchActionGroup(); |
| actionGroup.setContext(new ActionContext(selection)); |
| actionGroup.fillContextMenu(manager); |
| manager.add(new Separator()); |
| } |
| } else if (ssel.size() > 1) { |
| // Add delete action |
| Action delAction = new Action() { |
| @Override |
| public ImageDescriptor getImageDescriptor() { |
| return PDEPluginImages.DESC_DELETE; |
| } |
| |
| @Override |
| public ImageDescriptor getDisabledImageDescriptor() { |
| return PDEPluginImages.DESC_REMOVE_ATT_DISABLED; |
| } |
| |
| @Override |
| public void run() { |
| handleDelete(); |
| } |
| }; |
| delAction.setText(PDEUIMessages.ExtensionsSection_Remove); |
| manager.add(delAction); |
| manager.add(new Separator()); |
| delAction.setEnabled(isEditable() && isRemoveEnabled(ssel)); |
| } |
| if (ssel.size() > 0) { |
| if (ExtensionsFilterUtil.isFilterRelatedEnabled(ssel)) { |
| manager.add(fFilterRelatedAction); |
| } |
| } |
| if (fFilteredTree.isFiltered()) { |
| // Add action to clear the current filtering |
| manager.add(new Action() { |
| @Override |
| public String getText() { |
| return PDEUIMessages.ShowAllExtensionsAction_label; |
| } |
| |
| @Override |
| public void run() { |
| Text filterText = fFilteredTree.getFilterControl(); |
| setBypassFilterDelay(true); |
| filterText.setText(""); //$NON-NLS-1$ |
| } |
| |
| }); |
| } |
| |
| manager.add(new Separator()); |
| if (ssel.size() < 2) { // only cut things when the selection is one |
| getPage().getPDEEditor().getContributor().addClipboardActions(manager); |
| } |
| getPage().getPDEEditor().getContributor().contextMenuAboutToShow(manager, false); |
| this.fFilteredTree.update(); |
| } |
| |
| static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager) { |
| return fillContextMenu(page, parent, manager, false); |
| } |
| |
| static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager, boolean addSiblingItems) { |
| return fillContextMenu(page, parent, manager, addSiblingItems, true); |
| } |
| |
| static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager, boolean addSiblingItems, boolean fullMenu) { |
| MenuManager menu = new MenuManager(PDEUIMessages.Menus_new_label, MENU_NEW_ID); |
| IPluginExtension extension = getExtension(parent); |
| ISchema schema = getSchema(extension); |
| if (schema == null) { |
| menu.add(new NewElementAction(null, parent)); |
| } else { |
| addItemsForExtensionWithSchema(menu, extension, parent); |
| if (addSiblingItems) { |
| IPluginObject parentsParent = parent.getParent(); |
| if (!(parentsParent instanceof IPluginExtension)) { |
| IPluginParent pparent = (IPluginParent) parentsParent; |
| menu.add(new Separator()); |
| addItemsForExtensionWithSchema(menu, extension, pparent); |
| } |
| } |
| } |
| manager.add(menu); |
| manager.add(new Separator()); |
| if (fullMenu) { |
| Action deleteAction = new Action(PDEUIMessages.ExtensionsSection_Remove) { |
| @Override |
| public void run() { |
| try { |
| IPluginObject parentsParent = parent.getParent(); |
| if (parent instanceof IPluginExtension) { |
| IPluginBase plugin = (IPluginBase) parentsParent; |
| plugin.remove((IPluginExtension) parent); |
| } else { |
| IPluginParent parentElement = (IPluginParent) parent.getParent(); |
| parentElement.remove(parent); |
| } |
| } catch (CoreException e) { |
| } |
| } |
| |
| @Override |
| public ImageDescriptor getImageDescriptor() { |
| return PDEPluginImages.DESC_DELETE; |
| } |
| |
| @Override |
| public ImageDescriptor getDisabledImageDescriptor() { |
| return PDEPluginImages.DESC_REMOVE_ATT_DISABLED; |
| } |
| }; |
| deleteAction.setEnabled(page.getModel().isEditable()); |
| manager.add(deleteAction); |
| } |
| return menu; |
| } |
| |
| static IPluginExtension getExtension(IPluginParent parent) { |
| while (parent != null && !(parent instanceof IPluginExtension)) { |
| parent = (IPluginParent) parent.getParent(); |
| } |
| return (IPluginExtension) parent; |
| } |
| |
| private void handleDelete() { |
| IStructuredSelection sel = (IStructuredSelection) fExtensionTree.getSelection(); |
| if (sel.isEmpty()) |
| return; |
| for (Iterator<?> iter = sel.iterator(); iter.hasNext();) { |
| IPluginObject object = (IPluginObject) iter.next(); |
| try { |
| IStructuredSelection newSelection = null; |
| boolean sorted = fSortAction != null && fSortAction.isChecked(); |
| if (object instanceof IPluginElement) { |
| IPluginElement ee = (IPluginElement) object; |
| IPluginParent parent = (IPluginParent) ee.getParent(); |
| if (!sorted) { |
| int index = getNewSelectionIndex(parent.getIndexOf(ee), parent.getChildCount()); |
| newSelection = index == -1 ? new StructuredSelection(parent) : new StructuredSelection(parent.getChildren()[index]); |
| } else { |
| IPluginObject original[] = parent.getChildren(); |
| IPluginObject objects[] = new IPluginObject[original.length]; |
| for (int i = 0; i < original.length; i++) |
| objects[i] = original[i]; |
| fExtensionTree.getComparator().sort(fExtensionTree, objects); |
| int index = getNewSelectionIndex(getArrayIndex(objects, ee), objects.length); |
| newSelection = index == -1 ? new StructuredSelection(parent) : new StructuredSelection(objects[index]); |
| } |
| parent.remove(ee); |
| } else if (object instanceof IPluginExtension) { |
| IPluginExtension extension = (IPluginExtension) object; |
| IPluginBase plugin = extension.getPluginBase(); |
| if (!sorted) { |
| int index = getNewSelectionIndex(plugin.getIndexOf(extension), plugin.getExtensions().length); |
| if (index != -1) |
| newSelection = new StructuredSelection(plugin.getExtensions()[index]); |
| } else { |
| IPluginExtension original[] = plugin.getExtensions(); |
| IPluginExtension extensions[] = new IPluginExtension[original.length]; |
| for (int i = 0; i < original.length; i++) |
| extensions[i] = original[i]; |
| fExtensionTree.getComparator().sort(fExtensionTree, extensions); |
| int index = getNewSelectionIndex(getArrayIndex(extensions, extension), extensions.length); |
| if (index != -1) |
| newSelection = new StructuredSelection(extensions[index]); |
| } |
| plugin.remove(extension); |
| } |
| if (newSelection != null) |
| fExtensionTree.setSelection(newSelection); |
| } catch (CoreException e) { |
| PDEPlugin.logException(e); |
| } |
| } |
| } |
| |
| public FormFilteredTree getFormFilteredTree() { |
| return fFilteredTree; |
| } |
| |
| /** |
| * Adds another value to filter text and a preceding separator character if necessary. |
| * Empty values as well as <code>true</code> and <code>false</code> are omitted. |
| * |
| * @param attributeValue Value to be trimmed and added to the filter text |
| * @param clearFilterText When <code>true</code> the filter text is replaced with the attribute value, appended otherwise. |
| */ |
| public void addAttributeToFilter(String attributeValue, boolean clearFilterText) { |
| Text filterControl = fFilteredTree.getFilterControl(); |
| if (filterControl != null && attributeValue != null) { |
| String trimmedValue = attributeValue.trim(); |
| if (trimmedValue.length() > 0 && !ExtensionsFilterUtil.isBoolean(trimmedValue)) { |
| if (trimmedValue.startsWith("%")) {//$NON-NLS-1$ |
| IPluginModelBase model = getPluginModelBase(); |
| trimmedValue = ((model != null) ? model.getResourceString(trimmedValue) : trimmedValue).replaceAll("\"", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| String filterPattern; |
| if (clearFilterText) { |
| filterPattern = trimmedValue; |
| } else { |
| filterPattern = filterControl.getText(); |
| if (filterPattern.length() > 0 && !filterPattern.endsWith("/")) { //$NON-NLS-1$ |
| filterPattern += "/"; //$NON-NLS-1$ |
| } |
| filterPattern += trimmedValue; |
| } |
| if (filterPattern.indexOf('/') != -1) { // quote when |
| filterPattern = "\"" + filterPattern + "\""; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| setBypassFilterDelay(true); // force immediate job run |
| filterControl.setText(filterPattern); |
| } |
| } |
| } |
| |
| private void handleNew() { |
| final IProject project = getPage().getPDEEditor().getCommonProject(); |
| BusyIndicator.showWhile(fExtensionTree.getTree().getDisplay(), new Runnable() { |
| public void run() { |
| ((ManifestEditor) getPage().getEditor()).ensurePluginContextPresence(); |
| NewExtensionWizard wizard = new NewExtensionWizard(project, (IPluginModelBase) getPage().getModel(), (ManifestEditor) getPage().getPDEEditor()) { |
| @Override |
| public boolean performFinish() { |
| return super.performFinish(); |
| } |
| }; |
| WizardDialog dialog = new WizardDialog(PDEPlugin.getActiveWorkbenchShell(), wizard); |
| dialog.create(); |
| SWTUtil.setDialogSize(dialog, 500, 500); |
| dialog.open(); |
| } |
| }); |
| } |
| |
| private void handleEdit(IConfigurationElement element, IStructuredSelection selection) { |
| IProject project = getPage().getPDEEditor().getCommonProject(); |
| IPluginModelBase model = (IPluginModelBase) getPage().getModel(); |
| try { |
| final IExtensionEditorWizard wizard = (IExtensionEditorWizard) element.createExecutableExtension("class"); //$NON-NLS-1$ |
| wizard.init(project, model, selection); |
| BusyIndicator.showWhile(fExtensionTree.getTree().getDisplay(), new Runnable() { |
| public void run() { |
| WizardDialog dialog = new WizardDialog(PDEPlugin.getActiveWorkbenchShell(), wizard); |
| dialog.create(); |
| SWTUtil.setDialogSize(dialog, 500, 500); |
| dialog.open(); |
| } |
| }); |
| } catch (CoreException e) { |
| PDEPlugin.logException(e); |
| } |
| } |
| |
| private void handleEdit() { |
| final IStructuredSelection selection = (IStructuredSelection) fExtensionTree.getSelection(); |
| ArrayList<?> editorWizards = getEditorWizards(selection); |
| if (editorWizards == null) |
| return; |
| if (editorWizards.size() == 1) { |
| // open the wizard directly |
| handleEdit((IConfigurationElement) editorWizards.get(0), selection); |
| } else { |
| IProject project = getPage().getPDEEditor().getCommonProject(); |
| IPluginModelBase model = (IPluginModelBase) getPage().getModel(); |
| final ExtensionEditorWizard wizard = new ExtensionEditorWizard(project, model, selection); |
| BusyIndicator.showWhile(fExtensionTree.getTree().getDisplay(), new Runnable() { |
| public void run() { |
| WizardDialog dialog = new WizardDialog(PDEPlugin.getActiveWorkbenchShell(), wizard); |
| dialog.create(); |
| SWTUtil.setDialogSize(dialog, 500, 500); |
| dialog.open(); |
| } |
| }); |
| } |
| } |
| |
| private void handleSelectAll() { |
| fExtensionTree.getTree().selectAll(); |
| updateButtons(fFilteredTree.getViewer().getSelection()); |
| } |
| |
| private ArrayList<?> getEditorWizards(IStructuredSelection selection) { |
| if (selection.size() != 1) |
| return null; |
| Object obj = selection.getFirstElement(); |
| String pointId = null; |
| if (obj instanceof IPluginExtension) { |
| pointId = ((IPluginExtension) obj).getPoint(); |
| } else if (obj instanceof IPluginElement) { |
| IPluginObject parent = ((IPluginElement) obj).getParent(); |
| while (parent != null) { |
| if (parent instanceof IPluginExtension) { |
| pointId = ((IPluginExtension) parent).getPoint(); |
| break; |
| } |
| parent = parent.getParent(); |
| } |
| } |
| if (pointId == null) |
| return null; |
| if (fEditorWizards == null) |
| loadExtensionWizards(); |
| return fEditorWizards.get(pointId); |
| } |
| |
| private void loadExtensionWizards() { |
| fEditorWizards = new Hashtable<String, ArrayList<IConfigurationElement>>(); |
| IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.pde.ui.newExtension"); //$NON-NLS-1$ |
| for (int i = 0; i < elements.length; i++) { |
| IConfigurationElement element = elements[i]; |
| if (element.getName().equals("editorWizard")) { //$NON-NLS-1$ |
| String pointId = element.getAttribute("point"); //$NON-NLS-1$ |
| if (pointId == null) |
| continue; |
| ArrayList<IConfigurationElement> list = fEditorWizards.get(pointId); |
| if (list == null) { |
| list = new ArrayList<IConfigurationElement>(); |
| fEditorWizards.put(pointId, list); |
| } |
| list.add(element); |
| } |
| } |
| } |
| |
| private boolean isSelectionEditable(IStructuredSelection selection) { |
| if (!getPage().getModel().isEditable()) |
| return false; |
| return getEditorWizards(selection) != null; |
| } |
| |
| public void initialize(IPluginModelBase model) { |
| fExtensionTree.setInput(model.getPluginBase()); |
| selectFirstExtension(); |
| boolean editable = model.isEditable(); |
| TreePart treePart = getTreePart(); |
| treePart.setButtonEnabled(BUTTON_ADD, editable); |
| treePart.setButtonEnabled(BUTTON_REMOVE, false); |
| treePart.setButtonEnabled(BUTTON_EDIT, false); |
| treePart.setButtonEnabled(BUTTON_MOVE_UP, false); |
| treePart.setButtonEnabled(BUTTON_MOVE_DOWN, false); |
| model.addModelChangedListener(this); |
| } |
| |
| private void selectFirstExtension() { |
| Tree tree = fExtensionTree.getTree(); |
| TreeItem[] items = tree.getItems(); |
| if (items.length == 0) |
| return; |
| TreeItem firstItem = items[0]; |
| Object obj = firstItem.getData(); |
| fExtensionTree.setSelection(new StructuredSelection(obj)); |
| } |
| |
| void fireSelection() { |
| fExtensionTree.setSelection(fExtensionTree.getSelection()); |
| } |
| |
| public void initializeImages() { |
| PDELabelProvider provider = PDEPlugin.getDefault().getLabelProvider(); |
| fExtensionImage = provider.get(PDEPluginImages.DESC_EXTENSION_OBJ); |
| fGenericElementImage = provider.get(PDEPluginImages.DESC_GENERIC_XML_OBJ); |
| } |
| |
| @Override |
| public void refresh() { |
| // The model changed but the editor is still open, we should try to retain expansion, selection will be retained on its own |
| Object[] expanded = fExtensionTree.getExpandedElements(); |
| IPluginModelBase model = (IPluginModelBase) getPage().getModel(); |
| int[] indexPath = getTreeIndexPath(fExtensionTree.getTree()); |
| try { |
| fExtensionTree.getControl().setRedraw(false); |
| fExtensionTree.setInput(model.getPluginBase()); |
| fExtensionTree.setExpandedElements(expanded); |
| |
| reportMissingExtensionPointSchemas(model.getPluginBase()); |
| getManagedForm().fireSelectionChanged(ExtensionsSection.this, fExtensionTree.getSelection()); |
| super.refresh(); |
| |
| if (indexPath != null) { |
| // fix for Bug 371066 |
| revealTopItem(fExtensionTree.getTree(), indexPath); |
| } |
| } finally { |
| fExtensionTree.getControl().setRedraw(true); |
| } |
| } |
| |
| private static int[] getTreeIndexPath(Tree tree) { |
| int[] indexPath = null; |
| if (tree != null) { |
| TreeItem item = tree.getTopItem(); |
| int count = 1; |
| while (item != null && (item = item.getParentItem()) != null) { |
| count++; |
| } |
| indexPath = new int[count]; |
| int index = 0; |
| item = tree.getTopItem(); |
| while (item != null && index < count) { |
| TreeItem parent = item.getParentItem(); |
| if (parent != null) { |
| indexPath[index++] = parent.indexOf(item); |
| } else { |
| indexPath[index++] = tree.indexOf(item); |
| } |
| item = parent; |
| } |
| } |
| return indexPath; |
| } |
| |
| private static void revealTopItem(Tree tree, int[] indexPath) { |
| TreeItem itemFound = null; |
| for (int i = indexPath.length - 1; i >= 0; i--) { |
| int index = indexPath[i]; |
| if (itemFound != null) { |
| itemFound = (itemFound.getItemCount() > index) ? itemFound.getItem(indexPath[i]) : null; |
| } else if (i == indexPath.length - 1) { |
| itemFound = (tree.getItemCount() > index) ? tree.getItem(indexPath[i]) : null; |
| } |
| } |
| if (itemFound != null) { |
| tree.setTopItem(itemFound); |
| } |
| } |
| |
| @Override |
| public void modelChanged(IModelChangedEvent event) { |
| if (event.getChangeType() == IModelChangedEvent.WORLD_CHANGED) { |
| markStale(); |
| return; |
| } |
| Object changeObject = event.getChangedObjects()[0]; |
| if (changeObject instanceof IPluginBase && event.getChangeType() == IModelChangedEvent.CHANGE && event.getChangedProperty().equals(IExtensions.P_EXTENSION_ORDER)) { |
| IStructuredSelection sel = (IStructuredSelection) fExtensionTree.getSelection(); |
| IPluginExtension extension = (IPluginExtension) sel.getFirstElement(); |
| fExtensionTree.refresh(); |
| fExtensionTree.setSelection(new StructuredSelection(extension)); |
| return; |
| } |
| if (changeObject instanceof IPluginExtension || (changeObject instanceof IPluginElement && ((IPluginElement) changeObject).getParent() instanceof IPluginParent)) { |
| IPluginObject pobj = (IPluginObject) changeObject; |
| IPluginObject parent = changeObject instanceof IPluginExtension ? ((IPluginModelBase) getPage().getModel()).getPluginBase() : pobj.getParent(); |
| if (event.getChangeType() == IModelChangedEvent.INSERT) { |
| // enables adding extensions while tree is filtered |
| if (fFilteredTree.isFiltered()) { |
| Object[] inserted = event.getChangedObjects(); |
| for (int i = 0; i < inserted.length; i++) { |
| fPatternFilter.addElement(inserted[i]); |
| } |
| if (inserted.length == 1) { |
| fFilteredTree.getViewer().setSelection(new StructuredSelection(inserted[0])); |
| } |
| } |
| |
| // |
| fExtensionTree.refresh(parent); |
| if (changeObject instanceof IPluginExtension) { |
| IPluginExtension ext = (IPluginExtension) changeObject; |
| if (ext.getSchema() == null) |
| reportMissingExtensionPointSchema(ext.getPoint()); |
| } |
| fExtensionTree.setSelection(new StructuredSelection(changeObject), true); |
| fExtensionTree.getTree().setFocus(); |
| } else if (event.getChangeType() == IModelChangedEvent.REMOVE) { |
| if (changeObject instanceof IPluginExtension) { |
| IPluginExtension ext = (IPluginExtension) changeObject; |
| IPluginExtension[] extensions = ((IPluginBase) parent).getExtensions(); |
| boolean found = false; |
| // search if there is at least another extension extending the same point than the one being removed |
| for (int i = 0; i < extensions.length; i++) { |
| String point = extensions[i].getPoint(); |
| if (ext.getPoint().equals(point)) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) |
| getManagedForm().getMessageManager().removeMessage(ext.getPoint()); |
| } |
| fExtensionTree.remove(pobj); |
| } else { |
| if (event.getChangedProperty().equals(IPluginParent.P_SIBLING_ORDER)) { |
| IStructuredSelection sel = (IStructuredSelection) fExtensionTree.getSelection(); |
| IPluginObject child = (IPluginObject) sel.getFirstElement(); |
| fExtensionTree.refresh(child.getParent()); |
| fExtensionTree.setSelection(new StructuredSelection(child)); |
| } else { |
| fExtensionTree.update(changeObject, null); |
| } |
| } |
| } |
| } |
| |
| private Image resolveObjectImage(Object obj) { |
| if (obj instanceof IPluginExtension) { |
| return fExtensionImage; |
| } |
| Image elementImage = fGenericElementImage; |
| if (obj instanceof IPluginElement) { |
| IPluginElement element = (IPluginElement) obj; |
| Image customImage = getCustomImage(element); |
| if (customImage == null) |
| customImage = PDEPlugin.getDefault().getLabelProvider().getImage(obj); |
| if (customImage != null) |
| elementImage = customImage; |
| } |
| return elementImage; |
| } |
| |
| private static boolean isStorageModel(IPluginObject object) { |
| IPluginModelBase modelBase = object.getPluginModel(); |
| return modelBase.getInstallLocation() == null; |
| } |
| |
| static Image getCustomImage(IPluginElement element) { |
| if (isStorageModel(element)) |
| return null; |
| ISchemaElement elementInfo = getSchemaElement(element); |
| if (elementInfo != null && elementInfo.getIconProperty() != null) { |
| String iconProperty = elementInfo.getIconProperty(); |
| IPluginAttribute att = element.getAttribute(iconProperty); |
| String iconPath = null; |
| if (att != null && att.getValue() != null) { |
| iconPath = att.getValue(); |
| } |
| // we have a value from a resource attribute |
| if (iconPath != null) { |
| String ext = new Path(iconPath).getFileExtension(); |
| // if the resource targets a folder, the file extension will be null |
| if (ext == null) |
| return null; |
| boolean valid = false; |
| // ensure the resource is an image |
| for (int i = 0; i < VALID_IMAGE_TYPES.length; i++) { |
| if (ext.equalsIgnoreCase(VALID_IMAGE_TYPES[i])) { |
| valid = true; |
| break; |
| } |
| } |
| // if the resource is an image, get the image, otherwise return null |
| return valid ? getImageFromPlugin(element, iconPath) : null; |
| } |
| } |
| return null; |
| } |
| |
| private static Image getImageFromPlugin(IPluginElement element, String iconPathName) { |
| // 39283 - ignore icon paths that |
| // point at plugin.properties |
| if (iconPathName.startsWith("%")) //$NON-NLS-1$ |
| return null; |
| |
| IPluginModelBase model = element.getPluginModel(); |
| if (model == null) |
| return null; |
| |
| return PDEPlugin.getDefault().getLabelProvider().getImageFromPlugin(model, iconPathName); |
| } |
| |
| private String resolveObjectName(Object obj) { |
| return resolveObjectName(getSchemaRegistry(), obj); |
| } |
| |
| private SchemaRegistry getSchemaRegistry() { |
| if (fSchemaRegistry == null) |
| fSchemaRegistry = PDECore.getDefault().getSchemaRegistry(); |
| return fSchemaRegistry; |
| } |
| |
| public static String resolveObjectName(SchemaRegistry schemaRegistry, Object obj) { |
| boolean fullNames = PDEPlugin.isFullNameModeEnabled(); |
| if (obj instanceof IPluginExtension) { |
| IPluginExtension extension = (IPluginExtension) obj; |
| if (!fullNames) { |
| return extension.getPoint(); |
| } |
| if (extension.getName() != null) |
| return extension.getTranslatedName(); |
| ISchema schema = schemaRegistry.getSchema(extension.getPoint()); |
| // try extension point schema definition |
| if (schema != null) { |
| // exists |
| return schema.getName(); |
| } |
| return extension.getPoint(); |
| } else if (obj instanceof IPluginElement) { |
| IPluginElement element = (IPluginElement) obj; |
| String baseName = element.getName(); |
| String fullName = null; |
| ISchemaElement elementInfo = getSchemaElement(element); |
| IPluginAttribute labelAtt = null; |
| if (elementInfo != null && elementInfo.getLabelProperty() != null) { |
| labelAtt = element.getAttribute(elementInfo.getLabelProperty()); |
| } |
| if (labelAtt == null) { |
| // try some hard-coded attributes that |
| // are used frequently |
| for (int i = 0; i < COMMON_LABEL_ATTRIBUTES.length; i++) { |
| labelAtt = element.getAttribute(COMMON_LABEL_ATTRIBUTES[i]); |
| if (labelAtt != null && labelAtt.getValue().length() > 0) |
| break; |
| } |
| if (labelAtt == null) { |
| // Last try - if there is only one attribute, |
| // use that |
| if (element.getAttributeCount() == 1) |
| labelAtt = element.getAttributes()[0]; |
| } |
| } |
| if (labelAtt != null && labelAtt.getValue() != null) { |
| fullName = stripShortcuts(labelAtt.getValue()); |
| if (labelAtt.getName().equals(COMMON_LABEL_ATTRIBUTES[3])) { // remove package from handler class |
| fullName = fullName.substring(fullName.lastIndexOf('.') + 1, fullName.length()); |
| } |
| } |
| fullName = element.getResourceString(fullName); |
| |
| if (fullNames) |
| return fullName != null ? fullName : baseName; |
| if (fullName == null) |
| return baseName; |
| // Bug 183417 - Bidi3.3: Elements' labels in the extensions page in the fragment manifest characters order is incorrect |
| // add RTL zero length character just before the ( and the LTR character just after to ensure: |
| // 1. The leading parenthesis takes proper orientation when running in BiDi configuration |
| // Assumption: baseName (taken from the schema definition), is only Latin characters and is therefore always displayed LTR |
| if (BidiUtil.isBidiPlatform()) |
| return fullName + " \u200f(\u200e" + baseName + ")"; //$NON-NLS-1$ //$NON-NLS-2$ |
| return fullName + " (" + baseName + ')'; //$NON-NLS-1$ |
| } |
| if (obj != null) { |
| return obj.toString(); |
| } |
| return new String(); |
| } |
| |
| @Override |
| public void setFocus() { |
| if (fExtensionTree != null) |
| fExtensionTree.getTree().setFocus(); |
| } |
| |
| /** |
| * Temporarily bypasses default {@link FormFilteredTree#getRefreshJobDelay()} for several actions to immediately start tree |
| * filtering. Only the next job to call <code>getRefreshJobDelay()</code> will be affected and reset this value. |
| * |
| * @param bypassFilterDelay <code>true</code> bypasses the refresh job delay by overriding it with <code>0</code> |
| */ |
| public void setBypassFilterDelay(boolean bypassFilterDelay) { |
| fBypassFilterDelay = bypassFilterDelay; |
| } |
| |
| public static String stripShortcuts(String input) { |
| StringBuffer output = new StringBuffer(); |
| for (int i = 0; i < input.length(); i++) { |
| char c = input.charAt(i); |
| if (c == '&') |
| continue; |
| else if (c == '@') |
| break; |
| output.append(c); |
| } |
| return output.toString(); |
| } |
| |
| @Override |
| public boolean canCopy(ISelection selection) { |
| // Partial fix for Bug 360079, enables Ctrl+C in filter text if plugin model is editable |
| if (fFilteredTree.getFilterControl().isFocusControl() && !selection.isEmpty()) { |
| return true; |
| } |
| // TODO enable copy also when plug-in model is not editable |
| return super.canCopy(selection); |
| } |
| |
| @Override |
| public boolean canPaste(Clipboard clipboard) { |
| // Partial fix for Bug 360079, enables Ctrl+V in filter text if plugin model is editable |
| if (fFilteredTree.getFilterControl().isFocusControl()) { |
| return true; |
| } |
| // TODO enable paste also when plug-in model is not editable |
| return super.canPaste(clipboard); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canPaste(java.lang.Object, java.lang.Object[]) |
| */ |
| @Override |
| protected boolean canPaste(Object targetObject, Object[] sourceObjects) { |
| // Note: Multi-select in is enabled and this function can support |
| // multiple source object but it needs to be investigated |
| // Rule: Element source objects are always pasted as children of the |
| // target object (if allowable) |
| // Rule: Extension source objects are always pasted and are independent |
| // of the target object |
| // Ensure all the sourceObjects are either extensions or elements |
| boolean allExtensions = true; |
| boolean allElements = true; |
| for (int i = 0; i < sourceObjects.length; i++) { |
| if (sourceObjects[i] instanceof IPluginExtension) { |
| allElements = false; |
| } else if (sourceObjects[i] instanceof IPluginElement) { |
| allExtensions = false; |
| } else { |
| return false; |
| } |
| } |
| // Because of the extension rule, we can paste all extension source |
| // objects |
| if (allExtensions) { |
| return true; |
| } |
| // Pasting a mixture of elements and extensions is not supported |
| // (or wise from the users perspective) |
| if (allElements == false) { |
| return false; |
| } |
| // Ensure the target object can have children |
| if ((targetObject instanceof IPluginParent) == false) { |
| return false; |
| } else if ((targetObject instanceof IDocumentElementNode) == false) { |
| return false; |
| } |
| // Retrieve the schema corresponding to the target object |
| IPluginParent targetParent = (IPluginParent) targetObject; |
| ISchema schema = getSchema(targetParent); |
| // If there is no schema, then a source object can be pasted as a |
| // child of any target object |
| if (schema == null) { |
| return true; |
| } |
| // Determine the element name of the target object |
| String tagName = ((IDocumentElementNode) targetParent).getXMLTagName(); |
| // Retrieve the element schema for the target object |
| ISchemaElement schemaElement = schema.findElement(tagName); |
| // Ensure we found a schema element and it is a schema complex type |
| if (schemaElement == null) { |
| // Something is seriously wrong, we have a schema |
| return false; |
| } else if ((schemaElement.getType() instanceof ISchemaComplexType) == false) { |
| // Something is seriously wrong, we are a plugin parent |
| return false; |
| } |
| // We have a schema complex type. Either the target object has |
| // attributes or the element has children. |
| // Generate the list of element proposals |
| TreeSet<?> elementSet = XMLElementProposalComputer.computeElementProposal(schemaElement, (IDocumentElementNode) targetObject); |
| // Determine whether we can paste the source elements as children of |
| // the target object |
| if (sourceObjects.length > 1) { |
| IPluginElement[] sourcePluginElements = new IPluginElement[sourceObjects.length]; |
| System.arraycopy(sourceObjects, 0, sourcePluginElements, 0, sourceObjects.length); |
| return canPasteSourceElements(sourcePluginElements, elementSet); |
| } |
| return canPasteSourceElement((IPluginElement) sourceObjects[0], elementSet); |
| } |
| |
| /** |
| * @param sourceElements |
| * @param targetElementSet |
| */ |
| private boolean canPasteSourceElements(IPluginElement[] sourceElements, TreeSet<?> targetElementSet) { |
| // Performance optimisation |
| // HashSet of schema elements is not comparable for the source |
| // objects (schema elements are transient) |
| // Create a new HashSet with element names for comparison |
| HashSet<String> targetElementNameSet = new HashSet<String>(); |
| Iterator<?> iterator = targetElementSet.iterator(); |
| while (iterator.hasNext()) { |
| targetElementNameSet.add(((ISchemaElement) iterator.next()).getName()); |
| } |
| // Paste will be enabled only if all source objects can be pasted |
| // as children into the target element |
| // Limitation: Multiplicity checks will be compromised because we |
| // are pasting multiple elements as a single transaction. The |
| // multiplicity check is computed on the current static state of the |
| // target object with the assumption one new element will be added. |
| // Obviously, adding more than one element can invalidate the check |
| // due to choice, sequence multiplicity constraints. Even if source |
| // elements that are pasted violate multiplicity constraints the |
| // extensions builder will flag them with errors |
| for (int i = 0; i < sourceElements.length; i++) { |
| String sourceTagName = sourceElements[i].getName(); |
| if (targetElementNameSet.contains(sourceTagName) == false) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * @param sourceElement |
| * @param targetElementSet |
| */ |
| private boolean canPasteSourceElement(IPluginElement sourceElement, TreeSet<?> targetElementSet) { |
| boolean canPaste = false; |
| // Get the source element tag name |
| String sourceTagName = sourceElement.getName(); |
| // Iterate over set of valid element proposals |
| Iterator<?> iterator = targetElementSet.iterator(); |
| while (iterator.hasNext()) { |
| // Get the proposal element tag name |
| String targetTagName = ((ISchemaElement) iterator.next()).getName(); |
| // Only a source element that is found within the set of element |
| // proposals can be pasted |
| if (sourceTagName.equals(targetTagName)) { |
| canPaste = true; |
| break; |
| } |
| } |
| return canPaste; |
| } |
| |
| private IPluginModelBase getPluginModelBase() { |
| // Note: This method will work with fragments as long as a fragment.xml |
| // is defined first. Otherwise, paste will not work out of the box. |
| // Get the model |
| IPluginModelBase model = (IPluginModelBase) getPage().getModel(); |
| // Ensure the model is a bundle plug-in model |
| if ((model instanceof IBundlePluginModelBase) == false) { |
| return null; |
| } |
| // Get the extension model |
| ISharedExtensionsModel extensionModel = ((IBundlePluginModelBase) model).getExtensionsModel(); |
| // Ensure the extension model is defined |
| if ((extensionModel == null) || ((extensionModel instanceof IPluginModelBase) == false)) { |
| return null; |
| } |
| return ((IPluginModelBase) extensionModel); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doPaste(java.lang.Object, java.lang.Object[]) |
| */ |
| @Override |
| protected void doPaste(Object targetObject, Object[] sourceObjects) { |
| // By default, fragment.xml does not exist until the first extension |
| // or extension point is created. |
| // Ensure the file exists before pasting because the model will be |
| // null and the paste will fail if it does not exist |
| ((ManifestEditor) getPage().getEditor()).ensurePluginContextPresence(); |
| // Note: Multi-select in tree viewer is disabled; but, this function |
| // can support multiple source objects |
| // Get the model |
| IPluginModelBase model = getPluginModelBase(); |
| // Ensure the model is defined |
| if (model == null) { |
| return; |
| } |
| IPluginBase pluginBase = model.getPluginBase(); |
| try { |
| // Paste all source objects into the target object |
| for (int i = 0; i < sourceObjects.length; i++) { |
| Object sourceObject = sourceObjects[i]; |
| |
| if ((sourceObject instanceof IPluginExtension) && (pluginBase instanceof IDocumentElementNode)) { |
| // Extension object |
| IDocumentElementNode extension = (IDocumentElementNode) sourceObject; |
| // Adjust all the source object transient field values to |
| // acceptable values |
| extension.reconnect((IDocumentElementNode) pluginBase, model); |
| // Add the extension to the plug-in parent (plug-in) |
| pluginBase.add((IPluginExtension) extension); |
| |
| } else if ((sourceObject instanceof IPluginElement) && (targetObject instanceof IPluginParent) && (targetObject instanceof IDocumentElementNode)) { |
| // Element object |
| IDocumentElementNode element = (IDocumentElementNode) sourceObject; |
| // Adjust all the source object transient field values to |
| // acceptable values |
| element.reconnect((IDocumentElementNode) targetObject, model); |
| // Add the element to the plug-in parent (extension or |
| // element) |
| ((IPluginParent) targetObject).add((IPluginElement) element); |
| } |
| } |
| } catch (CoreException e) { |
| PDEPlugin.logException(e); |
| } |
| } |
| |
| private void handleMove(boolean up) { |
| IStructuredSelection sel = (IStructuredSelection) fExtensionTree.getSelection(); |
| IPluginObject object = (IPluginObject) sel.getFirstElement(); |
| if (object instanceof IPluginElement) { |
| IPluginParent parent = (IPluginParent) object.getParent(); |
| IPluginObject[] children = parent.getChildren(); |
| int index = parent.getIndexOf(object); |
| int newIndex = up ? index - 1 : index + 1; |
| IPluginObject child2 = children[newIndex]; |
| try { |
| parent.swap(object, child2); |
| } catch (CoreException e) { |
| PDEPlugin.logException(e); |
| } |
| } else if (object instanceof IPluginExtension) { |
| IPluginExtension extension = (IPluginExtension) object; |
| IPluginBase plugin = extension.getPluginBase(); |
| IPluginExtension[] extensions = plugin.getExtensions(); |
| int index = plugin.getIndexOf(extension); |
| int newIndex = up ? index - 1 : index + 1; |
| IPluginExtension e2 = extensions[newIndex]; |
| try { |
| plugin.swap(extension, e2); |
| } catch (CoreException e) { |
| PDEPlugin.logException(e); |
| } |
| } |
| } |
| |
| private void updateButtons(Object item) { |
| if (fExpandAction != null) { |
| fExpandAction.setEnabled(ToggleExpandStateAction.isExpandable((IStructuredSelection) fExtensionTree.getSelection())); |
| } |
| if (fFilterRelatedAction != null) { |
| boolean filterRelatedEnabled = false; |
| if (fExtensionTree != null) { |
| filterRelatedEnabled = ExtensionsFilterUtil.isFilterRelatedEnabled((IStructuredSelection) fExtensionTree.getSelection()); |
| } |
| fFilterRelatedAction.setEnabled(filterRelatedEnabled); |
| } |
| |
| if (getPage().getModel().isEditable() == false) |
| return; |
| boolean sorted = fSortAction != null && fSortAction.isChecked(); |
| if (sorted) { |
| getTreePart().setButtonEnabled(BUTTON_MOVE_UP, false); |
| getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, false); |
| return; |
| } |
| IStructuredSelection selection = (item instanceof IStructuredSelection) ? (IStructuredSelection) item : null; |
| |
| boolean filtered = fFilteredTree.isFiltered(); |
| boolean addEnabled = true; |
| boolean removeEnabled = true; |
| boolean upEnabled = false; |
| boolean downEnabled = false; |
| |
| if (filtered) { |
| // Fix for bug 194529 and bug 194828 |
| // Update: adding during filtering enabled by additional filter capability |
| addEnabled = true; |
| upEnabled = false; |
| downEnabled = false; |
| removeEnabled = isRemoveEnabled(selection); |
| } else { |
| if (selection != null && selection.size() == 1) { |
| Object selected = selection.getFirstElement(); |
| if (selected instanceof IPluginElement) { |
| IPluginElement element = (IPluginElement) selected; |
| IPluginParent parent = (IPluginParent) element.getParent(); |
| // check up |
| int index = parent.getIndexOf(element); |
| if (index > 0) |
| upEnabled = true; |
| if (index < parent.getChildCount() - 1) |
| downEnabled = true; |
| } else if (selected instanceof IPluginExtension) { |
| IPluginExtension extension = (IPluginExtension) selected; |
| IExtensions extensions = (IExtensions) extension.getParent(); |
| int index = extensions.getIndexOf(extension); |
| int size = extensions.getExtensions().length; |
| if (index > 0) |
| upEnabled = true; |
| if (index < size - 1) |
| downEnabled = true; |
| } |
| } |
| } |
| getTreePart().setButtonEnabled(BUTTON_ADD, addEnabled); |
| getTreePart().setButtonEnabled(BUTTON_REMOVE, removeEnabled); |
| getTreePart().setButtonEnabled(BUTTON_MOVE_UP, upEnabled); |
| getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, downEnabled); |
| } |
| |
| /** |
| * Since filtering potentially hides children of extensions, removing them when they still have children is intransparent. |
| * Needs to be called only when the tree is filtered. |
| * |
| * @param selection selection to be tested |
| * @return whether removing the selected elements is enabled |
| */ |
| boolean isRemoveEnabled(IStructuredSelection selection) { |
| if (selection != null) { |
| for (Iterator<?> iterator = selection.iterator(); iterator.hasNext();) { |
| Object element = iterator.next(); |
| if (element instanceof PluginExtensionNode) { |
| return ((PluginExtensionNode) element).getChildCount() == 0; |
| } |
| } |
| } |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.TreeSection#createTreeViewer(org.eclipse.swt.widgets.Composite, int) |
| */ |
| @Override |
| protected TreeViewer createTreeViewer(Composite parent, int style) { |
| fPatternFilter = new ExtensionsPatternFilter(); |
| fFilteredTree = new FormFilteredTree(parent, style, fPatternFilter) { |
| @Override |
| protected WorkbenchJob doCreateRefreshJob() { |
| final WorkbenchJob job = super.doCreateRefreshJob(); |
| job.addJobChangeListener(new JobChangeAdapter() { |
| private ISelection selection; |
| private boolean aboutToRunPassed = false; |
| |
| @Override |
| public void scheduled(IJobChangeEvent event) { |
| ((ExtensionsPatternFilter) fFilteredTree.getPatternFilter()).clearMatchingLeafs(); |
| selection = fExtensionTree.getSelection(); |
| } |
| |
| @Override |
| public void aboutToRun(IJobChangeEvent event) { |
| aboutToRunPassed = true; |
| } |
| |
| /* |
| * Restores selection after tree refresh and expands tree up to matching leafs only |
| */ |
| @Override |
| public void done(IJobChangeEvent event) { |
| if (aboutToRunPassed) { // restoring is only required if the job actually ran |
| try { |
| fFilteredTree.setRedraw(false); |
| ExtensionsPatternFilter extensionsPatternFilter = ((ExtensionsPatternFilter) fFilteredTree.getPatternFilter()); |
| fExtensionTree.collapseAll(); |
| Object[] leafs = extensionsPatternFilter.getMatchingLeafsAsArray(); |
| for (int i = 0; i < leafs.length; i++) { |
| fExtensionTree.expandToLevel(leafs[i], 0); |
| } |
| if (selection != null && !(selection.isEmpty())) { |
| fExtensionTree.setSelection(selection, true); |
| } |
| } finally { |
| fFilteredTree.setRedraw(true); |
| } |
| } |
| } |
| }); |
| return job; |
| } |
| |
| @Override |
| protected long getRefreshJobDelay() { |
| // Prolonged job delay time is required because of the attribute search being more costly in nature. |
| // This can block input to the filter text severely. Thus it shouldn't happen when typing slowly. |
| // The delay of 1500ms is bypassed by some actions that use the filter text to initiate searches or clear the text. |
| long delay = (fBypassFilterDelay) ? 0 : REFRESHJOB_DELAY_TIME; |
| setBypassFilterDelay(false); // reset afterwards |
| return delay; |
| } |
| |
| @Override |
| protected void clearText() { |
| // bugfix: additional notification with textChanged() would cause a needless 2nd refresh job run |
| // which in turn would have a longer delay time than the 1st run. |
| setFilterText(""); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected void textChanged() { |
| String filterText = getFilterString(); |
| if (filterText != null && filterText.length() == 0) { |
| // clearing the filter text doesn't require a refresh job delay |
| setBypassFilterDelay(true); |
| } |
| super.textChanged(); |
| } |
| }; |
| parent.setData("filtered", Boolean.TRUE); //$NON-NLS-1$ |
| return fFilteredTree.getViewer(); |
| } |
| |
| public void propertyChange(PropertyChangeEvent event) { |
| if (fSortAction.equals(event.getSource()) && IAction.RESULT.equals(event.getProperty())) { |
| StructuredViewer viewer = getStructuredViewerPart().getViewer(); |
| IStructuredSelection ssel = (IStructuredSelection) viewer.getSelection(); |
| updateButtons(ssel); |
| } |
| } |
| |
| protected void selectExtensionElement(ISelection selection) { |
| fExtensionTree.setSelection(selection, true); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#isDragAndDropEnabled() |
| */ |
| @Override |
| protected boolean isDragAndDropEnabled() { |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canDragMove(java.lang.Object[]) |
| */ |
| @Override |
| public boolean canDragMove(Object[] sourceObjects) { |
| // Validate source objects |
| if (validateDragMoveSanity(sourceObjects) == false) { |
| return false; |
| } else if (fFilteredTree.isFiltered()) { |
| return false; |
| } else if (isTreeViewerSorted()) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * @param targetObject |
| * @param sourceObjects |
| */ |
| private boolean validateDropMoveSanity(Object targetObject, Object[] sourceObjects) { |
| // Validate target object |
| if ((targetObject instanceof IPluginParent) == false) { |
| return false; |
| } else if ((targetObject instanceof IDocumentElementNode) == false) { |
| return false; |
| } |
| // Validate source objects |
| if (validateDragMoveSanity(sourceObjects) == false) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * @param sourceObjects |
| */ |
| private boolean validateDragMoveSanity(Object[] sourceObjects) { |
| // Validate source |
| if (sourceObjects == null) { |
| // No objects |
| return false; |
| } else if (sourceObjects.length != 1) { |
| // Multiple selection not supported |
| return false; |
| } else if ((sourceObjects[0] instanceof IDocumentElementNode) == false) { |
| // Must be the right type |
| return false; |
| } else if ((sourceObjects[0] instanceof IPluginParent) == false) { |
| // Must be the right type |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * @param sourcePluginObject |
| * @param targetPluginObject |
| */ |
| private boolean validateDropMoveModel(IPluginParent sourcePluginObject, IPluginParent targetPluginObject) { |
| // Objects have to be from the same model |
| ISharedPluginModel sourceModel = sourcePluginObject.getModel(); |
| ISharedPluginModel targetModel = targetPluginObject.getModel(); |
| if (sourceModel.equals(targetModel)) { |
| return true; |
| } |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canDropMove(java.lang.Object, java.lang.Object[], int) |
| */ |
| @Override |
| public boolean canDropMove(Object targetObject, Object[] sourceObjects, int targetLocation) { |
| // Sanity check |
| if (validateDropMoveSanity(targetObject, sourceObjects) == false) { |
| return false; |
| } |
| // Multiple selection not supported |
| IPluginParent sourcePluginObject = (IPluginParent) sourceObjects[0]; |
| IPluginParent targetPluginObject = (IPluginParent) targetObject; |
| // Validate model |
| if (validateDropMoveModel(sourcePluginObject, targetPluginObject) == false) { |
| return false; |
| } |
| // Validate move |
| if (sourcePluginObject instanceof IPluginExtension) { |
| IPluginExtension sourceExtensionObject = (IPluginExtension) sourcePluginObject; |
| if (targetPluginObject instanceof IPluginExtension) { |
| // Source: Extension |
| // Target: Extension |
| IPluginExtension targetExtensionObject = (IPluginExtension) targetPluginObject; |
| return canDropMove(targetExtensionObject, sourceExtensionObject, targetLocation); |
| } else if (targetPluginObject instanceof IPluginElement) { |
| // Source: Extension |
| // Target: Element |
| return false; |
| } |
| } else if (sourcePluginObject instanceof IPluginElement) { |
| IPluginElement sourceElementObject = (IPluginElement) sourcePluginObject; |
| if (targetPluginObject instanceof IPluginExtension) { |
| // Source: Element |
| // Target: Extension |
| IPluginExtension targetExtensionObject = (IPluginExtension) targetPluginObject; |
| return canDropMove(targetExtensionObject, sourceElementObject, targetLocation); |
| } else if (targetPluginObject instanceof IPluginElement) { |
| // Source: Element |
| // Target: Element |
| IPluginElement targetElementObject = (IPluginElement) targetPluginObject; |
| return canDropMove(targetElementObject, sourceElementObject, targetLocation); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @param targetElementObject |
| * @param sourceElementObject |
| * @param targetLocation |
| */ |
| private boolean canDropMove(IPluginElement targetElementObject, IPluginElement sourceElementObject, int targetLocation) { |
| |
| // Verify that the source is not the parent of the target |
| if (validateDropMoveParent(targetElementObject, sourceElementObject) == false) { |
| return false; |
| } |
| |
| if (targetLocation == ViewerDropAdapter.LOCATION_BEFORE) { |
| IDocumentElementNode previousNode = ((IDocumentElementNode) targetElementObject).getPreviousSibling(); |
| if (sourceElementObject.equals(previousNode)) { |
| return false; |
| } |
| IPluginObject targetParentObject = targetElementObject.getParent(); |
| if ((targetParentObject instanceof IPluginParent) == false) { |
| return false; |
| } |
| // Paste element as a sibling of the other element (before) |
| return validateDropMoveSchema((IPluginParent) targetParentObject, sourceElementObject); |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) { |
| IDocumentElementNode nextNode = ((IDocumentElementNode) sourceElementObject).getPreviousSibling(); |
| if (targetElementObject.equals(nextNode)) { |
| return false; |
| } |
| IPluginObject targetParentObject = targetElementObject.getParent(); |
| if ((targetParentObject instanceof IPluginParent) == false) { |
| return false; |
| } |
| // Paste element as a sibling of the other element (after) |
| return validateDropMoveSchema((IPluginParent) targetParentObject, sourceElementObject); |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) { |
| IDocumentElementNode targetExtensionNode = (IDocumentElementNode) targetElementObject; |
| int childCount = targetExtensionNode.getChildCount(); |
| if (childCount != 0) { |
| IDocumentElementNode lastNode = targetExtensionNode.getChildAt(childCount - 1); |
| if (sourceElementObject.equals(lastNode)) { |
| return false; |
| } |
| } |
| // Paste element as the last child of the element |
| return validateDropMoveSchema(targetElementObject, sourceElementObject); |
| } |
| return false; |
| } |
| |
| /** |
| * @param targetElementObject |
| * @param sourceElementObject |
| */ |
| private boolean validateDropMoveParent(IPluginElement targetElementObject, IPluginElement sourceElementObject) { |
| |
| IPluginObject currentParent = targetElementObject.getParent(); |
| while (true) { |
| if (currentParent == null) { |
| return true; |
| } else if ((currentParent instanceof IPluginElement) == false) { |
| return true; |
| } else if (sourceElementObject.equals(currentParent)) { |
| return false; |
| } |
| currentParent = currentParent.getParent(); |
| } |
| } |
| |
| /** |
| * @param targetExtensionObject |
| * @param sourceElementObject |
| * @param targetLocation |
| */ |
| private boolean canDropMove(IPluginExtension targetExtensionObject, IPluginElement sourceElementObject, int targetLocation) { |
| |
| if (targetLocation == ViewerDropAdapter.LOCATION_BEFORE) { |
| return false; |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) { |
| return false; |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) { |
| IDocumentElementNode targetExtensionNode = (IDocumentElementNode) targetExtensionObject; |
| int childCount = targetExtensionNode.getChildCount(); |
| if (childCount != 0) { |
| IDocumentElementNode lastNode = targetExtensionNode.getChildAt(childCount - 1); |
| if (sourceElementObject.equals(lastNode)) { |
| return false; |
| } |
| } |
| // Paste element as the last child of the extension |
| return validateDropMoveSchema(targetExtensionObject, sourceElementObject); |
| } |
| return false; |
| } |
| |
| /** |
| * @param targetPluginObject |
| * @param sourcePluginObject |
| */ |
| private boolean validateDropMoveSchema(IPluginParent targetPluginObject, IPluginParent sourcePluginObject) { |
| IDocumentElementNode targetPluginNode = (IDocumentElementNode) targetPluginObject; |
| // If the target is the source's parent, then the move is always |
| // valid. No need to check the schema. Order does not matter |
| if (targetPluginObject.equals(sourcePluginObject.getParent())) { |
| return true; |
| } |
| // Retrieve the schema corresponding to the target object |
| ISchema schema = getSchema(targetPluginObject); |
| // If there is no schema, then a source object can be pasted as a |
| // child of any target object |
| if (schema == null) { |
| return true; |
| } |
| // Determine the element name of the target object |
| String targetNodeTagName = targetPluginNode.getXMLTagName(); |
| // Retrieve the element schema for the target object |
| ISchemaElement schemaElement = schema.findElement(targetNodeTagName); |
| // Ensure we found a schema element and it is a schema complex type |
| if (schemaElement == null) { |
| // Something is seriously wrong, we have a schema |
| return false; |
| } else if ((schemaElement.getType() instanceof ISchemaComplexType) == false) { |
| // Something is seriously wrong, we are a plug-in parent |
| return false; |
| } |
| // We have a schema complex type. Either the target object has |
| // attributes or the element has children. |
| // Generate the list of element proposals |
| TreeSet<?> elementSet = XMLElementProposalComputer.computeElementProposal(schemaElement, targetPluginNode); |
| // Iterate over set of valid element proposals |
| Iterator<?> iterator = elementSet.iterator(); |
| while (iterator.hasNext()) { |
| // Get the proposal element tag name |
| String targetTagName = ((ISchemaElement) iterator.next()).getName(); |
| // Only a source element that is found within the set of element |
| // proposals can be pasted |
| String sourceNodeTagName = ((IDocumentElementNode) sourcePluginObject).getXMLTagName(); |
| if (sourceNodeTagName.equals(targetTagName)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @param targetExtensionObject |
| * @param sourceExtensionObject |
| * @param targetLocation |
| */ |
| private boolean canDropMove(IPluginExtension targetExtensionObject, IPluginExtension sourceExtensionObject, int targetLocation) { |
| |
| if (targetLocation == ViewerDropAdapter.LOCATION_BEFORE) { |
| IDocumentElementNode previousNode = ((IDocumentElementNode) targetExtensionObject).getPreviousSibling(); |
| if (sourceExtensionObject.equals(previousNode)) { |
| return false; |
| } |
| // Paste extension as sibling of extension (before) |
| return true; |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) { |
| IDocumentElementNode nextNode = ((IDocumentElementNode) sourceExtensionObject).getPreviousSibling(); |
| if (targetExtensionObject.equals(nextNode)) { |
| return false; |
| } |
| // Paste extension as sibling of extension (after) |
| return true; |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) { |
| return false; |
| } |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doDragRemove(java.lang.Object[]) |
| */ |
| @Override |
| public void doDragRemove(Object[] sourceObjects) { |
| // Validate source objects |
| if (validateDragMoveSanity(sourceObjects) == false) { |
| return; |
| } |
| IPluginParent pluginParentObject = (IPluginParent) sourceObjects[0]; |
| // Remove the object from the model |
| try { |
| if (pluginParentObject instanceof IPluginExtension) { |
| IPluginExtension extension = (IPluginExtension) pluginParentObject; |
| IPluginBase pluginBase = pluginParentObject.getPluginBase(); |
| if (pluginBase != null) { |
| pluginBase.remove(extension); |
| } |
| } else if (pluginParentObject instanceof IPluginElement) { |
| IPluginElement element = (IPluginElement) pluginParentObject; |
| IPluginObject object = element.getParent(); |
| if (object instanceof IPluginParent) { |
| ((IPluginParent) object).remove(element); |
| } |
| } |
| // Applicable for move operations |
| // Flush the text edit operations associated with the move operation |
| // to the source page |
| // Move involves add new cloned object x and remove of original object |
| // x |
| // Without flushing, multiple move operations up and down cause the |
| // text edit operations to get completely screwed up (e.g. mark-up |
| // in wrong position or getting lost) |
| // TODO: MP: Undo: What are the implications of this? |
| ((PDEFormEditor) getPage().getEditor()).getContextManager().getPrimaryContext().flushEditorInput(); |
| } catch (CoreException e) { |
| PDEPlugin.logException(e); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doDropMove(java.lang.Object, java.lang.Object[], int) |
| */ |
| @Override |
| public void doDropMove(Object targetObject, Object[] sourceObjects, int targetLocation) { |
| // Sanity check |
| if (validateDropMoveSanity(targetObject, sourceObjects) == false) { |
| Display.getDefault().beep(); |
| return; |
| } |
| // Multiple selection not supported |
| IPluginParent sourcePluginObject = (IPluginParent) sourceObjects[0]; |
| IPluginParent targetPluginObject = (IPluginParent) targetObject; |
| // Validate move |
| try { |
| if (sourcePluginObject instanceof IPluginExtension) { |
| IPluginExtension sourceExtensionObject = (IPluginExtension) sourcePluginObject; |
| if (targetPluginObject instanceof IPluginExtension) { |
| // Source: Extension |
| // Target: Extension |
| IPluginExtension targetExtensionObject = (IPluginExtension) targetPluginObject; |
| doDropMove(targetExtensionObject, sourceExtensionObject, targetLocation); |
| } else if (targetPluginObject instanceof IPluginElement) { |
| // Source: Extension |
| // Target: Element |
| return; |
| } |
| } else if (sourcePluginObject instanceof IPluginElement) { |
| IPluginElement sourceElementObject = (IPluginElement) sourcePluginObject; |
| if (targetPluginObject instanceof IPluginExtension) { |
| // Source: Element |
| // Target: Extension |
| IPluginExtension targetExtensionObject = (IPluginExtension) targetPluginObject; |
| doDropMove(targetExtensionObject, sourceElementObject, targetLocation); |
| } else if (targetPluginObject instanceof IPluginElement) { |
| // Source: Element |
| // Target: Element |
| IPluginElement targetElementObject = (IPluginElement) targetPluginObject; |
| doDropMove(targetElementObject, sourceElementObject, targetLocation); |
| } |
| } |
| } catch (CoreException e) { |
| PDEPlugin.logException(e); |
| } |
| } |
| |
| /** |
| * @param targetExtensionObject |
| * @param sourceExtensionObject |
| * @param targetLocation |
| */ |
| private void doDropMove(IPluginExtension targetExtensionObject, IPluginExtension sourceExtensionObject, int targetLocation) throws CoreException { |
| // Get the model |
| IPluginModelBase model = getPluginModelBase(); |
| // Ensure the model is defined |
| if (model == null) { |
| return; |
| } |
| // Get the plug-in base |
| IPluginBase pluginBase = model.getPluginBase(); |
| // Ensure the plug-in base is a document node |
| if ((pluginBase instanceof IDocumentElementNode) == false) { |
| return; |
| } else if ((pluginBase instanceof PluginBaseNode) == false) { |
| return; |
| } |
| // Plug-in base node |
| IDocumentElementNode pluginBaseNode = (IDocumentElementNode) pluginBase; |
| // Source extension node |
| IDocumentElementNode sourceExtensionNode = (IDocumentElementNode) sourceExtensionObject; |
| // Target extension node |
| IDocumentElementNode targetExtensionNode = (IDocumentElementNode) targetExtensionObject; |
| // Do drop move |
| if (targetLocation == ViewerDropAdapter.LOCATION_BEFORE) { |
| // Adjust all the source object transient field values to |
| // acceptable values |
| sourceExtensionNode.reconnect(pluginBaseNode, model); |
| // Get index of target extension |
| int index = (pluginBaseNode.indexOf(targetExtensionNode)); |
| // Ensure the target index was found |
| if (index == -1) { |
| return; |
| } |
| // Paste extension as sibling of extension (before) |
| ((PluginBaseNode) pluginBaseNode).add(sourceExtensionObject, index); |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) { |
| // Adjust all the source object transient field values to |
| // acceptable values |
| sourceExtensionNode.reconnect(pluginBaseNode, model); |
| // Get index of target extension |
| int index = (pluginBaseNode.indexOf(targetExtensionNode)); |
| // Ensure the target index was found |
| if (index == -1) { |
| return; |
| } |
| // Paste extension as sibling of extension (after) |
| ((PluginBaseNode) pluginBaseNode).add(sourceExtensionObject, index + 1); |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) { |
| // NO-OP |
| } |
| } |
| |
| /** |
| * @param targetExtensionObject |
| * @param sourceElementObject |
| * @param targetLocation |
| */ |
| private void doDropMove(IPluginExtension targetExtensionObject, IPluginElement sourceElementObject, int targetLocation) throws CoreException { |
| // Get the model |
| IPluginModelBase model = getPluginModelBase(); |
| // Ensure the model is defined |
| if (model == null) { |
| return; |
| } |
| // Target extension node |
| IDocumentElementNode targetExtensionNode = (IDocumentElementNode) targetExtensionObject; |
| // Source extension node |
| IDocumentElementNode sourceElementNode = (IDocumentElementNode) sourceElementObject; |
| // Do drop move |
| if (targetLocation == ViewerDropAdapter.LOCATION_BEFORE) { |
| // NO-OP |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) { |
| // NO-OP |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) { |
| // Adjust all the source object transient field values to |
| // acceptable values |
| sourceElementNode.reconnect(targetExtensionNode, model); |
| // Paste element as the last child of the extension |
| targetExtensionObject.add(sourceElementObject); |
| } |
| } |
| |
| /** |
| * @param targetElementObject |
| * @param sourceElementObject |
| * @param targetLocation |
| */ |
| private void doDropMove(IPluginElement targetElementObject, IPluginElement sourceElementObject, int targetLocation) throws CoreException { |
| // Get the model |
| IPluginModelBase model = getPluginModelBase(); |
| // Ensure the model is defined |
| if (model == null) { |
| return; |
| } |
| // Target extension node |
| IDocumentElementNode targetElementNode = (IDocumentElementNode) targetElementObject; |
| // Source extension node |
| IDocumentElementNode sourceElementNode = (IDocumentElementNode) sourceElementObject; |
| // Do drop move |
| if (targetLocation == ViewerDropAdapter.LOCATION_BEFORE) { |
| // Get the target's parent |
| IPluginObject targetParentObject = targetElementObject.getParent(); |
| if ((targetParentObject instanceof IPluginParent) == false) { |
| return; |
| } else if ((targetParentObject instanceof IDocumentElementNode) == false) { |
| return; |
| } |
| IDocumentElementNode targetParentNode = (IDocumentElementNode) targetParentObject; |
| // Adjust all the source object transient field values to |
| // acceptable values |
| sourceElementNode.reconnect(targetParentNode, model); |
| // Get index of target element |
| int index = (targetParentNode.indexOf(targetElementNode)); |
| // Ensure the target index was found |
| if (index == -1) { |
| return; |
| } |
| // Paste element as a sibling of the other element (before) |
| ((IPluginParent) targetParentObject).add(index, sourceElementObject); |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) { |
| // Get the target's parent |
| IPluginObject targetParentObject = targetElementObject.getParent(); |
| if ((targetParentObject instanceof IPluginParent) == false) { |
| return; |
| } else if ((targetParentObject instanceof IDocumentElementNode) == false) { |
| return; |
| } |
| IDocumentElementNode targetParentNode = (IDocumentElementNode) targetParentObject; |
| // Adjust all the source object transient field values to |
| // acceptable values |
| sourceElementNode.reconnect(targetParentNode, model); |
| // Get index of target element |
| int index = (targetParentNode.indexOf(targetElementNode)); |
| // Ensure the target index was found |
| if (index == -1) { |
| return; |
| } |
| // Paste element as a sibling of the other element (after) |
| ((IPluginParent) targetParentObject).add(index + 1, sourceElementObject); |
| } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) { |
| // Adjust all the source object transient field values to |
| // acceptable values |
| sourceElementNode.reconnect(targetElementNode, model); |
| // Paste element as the last child of the element |
| targetElementObject.add(sourceElementObject); |
| } |
| |
| } |
| |
| private boolean isTreeViewerSorted() { |
| if (fSortAction == null) { |
| return false; |
| } |
| return fSortAction.isChecked(); |
| } |
| |
| private boolean isSingleSelection() { |
| IStructuredSelection selection = (IStructuredSelection) fExtensionTree.getSelection(); |
| return selection.size() == 1; |
| } |
| |
| private void reportMissingExtensionPointSchemas(IPluginBase pluginBase) { |
| IPluginExtension[] extensions = pluginBase.getExtensions(); |
| for (int i = 0; i < extensions.length; i++) { |
| IPluginExtension ext = extensions[i]; |
| if (ext.getSchema() == null) |
| reportMissingExtensionPointSchema(ext.getPoint()); |
| } |
| } |
| |
| private void reportMissingExtensionPointSchema(String point) { |
| getManagedForm().getMessageManager().addMessage(point, NLS.bind(PDEUIMessages.ManifestEditor_DetailExtension_missingExtPointSchema, point), null, IMessageProvider.WARNING); |
| } |
| } |