blob: 0d1926df03cc3c128120fdc733c471216b5a461d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 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
* Alexander Kurtakov <akurtako@redhat.com> - bug 415649
* Fabian Miehe - Bug 440420
* Simon Scholz <simon.scholz@vogella.com> - Bug 444808
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 487943
* Martin Karpisek <martin.karpisek@gmail.com> - Bug 351356
*******************************************************************************/
package org.eclipse.pde.internal.ui.editor.feature;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.*;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.Window;
import org.eclipse.pde.core.IModel;
import org.eclipse.pde.core.IModelChangedEvent;
import org.eclipse.pde.internal.core.*;
import org.eclipse.pde.internal.core.feature.FeatureChild;
import org.eclipse.pde.internal.core.ifeature.*;
import org.eclipse.pde.internal.ui.PDEPlugin;
import org.eclipse.pde.internal.ui.PDEUIMessages;
import org.eclipse.pde.internal.ui.dialogs.FeatureSelectionDialog;
import org.eclipse.pde.internal.ui.editor.*;
import org.eclipse.pde.internal.ui.editor.actions.SortAction;
import org.eclipse.pde.internal.ui.parts.TablePart;
import org.eclipse.pde.internal.ui.wizards.ListUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
public class IncludedFeaturesSection extends TableSection implements IFeatureModelListener, IPropertyChangeListener {
private static final int NEW = 0;
private static final int REMOVE = 1;
private static final int SYNC = 2;
private static final int UP = 3;
private static final int DOWN = 4;
private TableViewer fIncludesViewer;
private Action fNewAction;
private Action fOpenAction;
private Action fDeleteAction;
private SortAction fSortAction;
class IncludedFeaturesContentProvider implements IStructuredContentProvider {
@Override
public Object[] getElements(Object parent) {
if (parent instanceof IFeature) {
return ((IFeature) parent).getIncludedFeatures();
}
return new Object[0];
}
}
public IncludedFeaturesSection(PDEFormPage page, Composite parent) {
super(page, parent, Section.DESCRIPTION, new String[] { PDEUIMessages.FeatureEditor_IncludedFeatures_new,
PDEUIMessages.FeatureEditor_IncludedFeatures_remove,
PDEUIMessages.FeatureEditor_SpecSection_synchronize, PDEUIMessages.FeatureEditor_IncludedFeatures_up,
PDEUIMessages.FeatureEditor_IncludedFeatures_down });
getSection().setText(PDEUIMessages.FeatureEditor_IncludedFeatures_title);
getSection().setDescription(PDEUIMessages.FeatureEditor_IncludedFeatures_desc);
getTablePart().setEditable(false);
getSection().setLayoutData(new GridData(GridData.FILL_BOTH));
}
@Override
public void commit(boolean onSave) {
super.commit(onSave);
}
@Override
public void createClient(Section section, FormToolkit toolkit) {
section.setLayout(FormLayoutFactory.createClearGridLayout(false, 1));
GridData data = new GridData(GridData.FILL_BOTH);
section.setLayoutData(data);
Composite container = createClientContainer(section, 2, toolkit);
createViewerPartControl(container, SWT.MULTI, 2, toolkit);
TablePart tablePart = getTablePart();
fIncludesViewer = tablePart.getTableViewer();
fIncludesViewer.setContentProvider(new IncludedFeaturesContentProvider());
fIncludesViewer.setLabelProvider(PDEPlugin.getDefault().getLabelProvider());
fIncludesViewer.setComparator(ListUtil.NAME_COMPARATOR);
toolkit.paintBordersFor(container);
makeActions();
section.setClient(container);
initialize();
createSectionToolbar(section, toolkit);
}
/**
* @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(getStructuredViewerPart().getViewer(), PDEUIMessages.FeatureEditor_IncludedFeatures_sortAlpha, ListUtil.NAME_COMPARATOR, null, this);
toolBarManager.add(fSortAction);
toolBarManager.update(true);
section.setTextClient(toolbar);
}
@Override
protected void handleDoubleClick(IStructuredSelection selection) {
fOpenAction.run();
}
@Override
protected void buttonSelected(int index) {
switch (index) {
case NEW :
handleNew();
break;
case REMOVE :
handleDelete();
break;
case SYNC:
handleSynchronize();
break;
case UP :
handleUp();
break;
case DOWN :
handleDown();
break;
}
}
private void handleSynchronize() {
final FeatureEditorContributor contributor = (FeatureEditorContributor) getPage().getPDEEditor()
.getContributor();
BusyIndicator.showWhile(fIncludesViewer.getControl().getDisplay(),
() -> contributor.getSynchronizeAction().run());
}
@Override
public void dispose() {
IFeatureModel model = (IFeatureModel) getPage().getModel();
if (model != null)
model.removeModelChangedListener(this);
FeatureModelManager mng = PDECore.getDefault().getFeatureModelManager();
mng.removeFeatureModelListener(this);
super.dispose();
}
@Override
public boolean setFormInput(Object object) {
if (object instanceof IFeatureChild) {
fIncludesViewer.setSelection(new StructuredSelection(object), true);
return true;
}
return false;
}
@Override
protected void fillContextMenu(IMenuManager manager) {
manager.add(fOpenAction);
manager.add(new Separator());
manager.add(fNewAction);
manager.add(fDeleteAction);
manager.add(new Separator());
getPage().getPDEEditor().getContributor().contextMenuAboutToShow(manager);
}
private void handleUp() {
int index = getTablePart().getTableViewer().getTable().getSelectionIndex();
if (index < 1)
return;
swap(index, index - 1);
}
private void handleDown() {
Table table = getTablePart().getTableViewer().getTable();
int index = table.getSelectionIndex();
if (index == table.getItemCount() - 1)
return;
swap(index, index + 1);
}
private void handleNew() {
BusyIndicator.showWhile(fIncludesViewer.getTable().getDisplay(), () -> {
IFeatureModel[] allModels = PDECore.getDefault().getFeatureModelManager().getModels();
ArrayList<IFeatureModel> newModels = new ArrayList<>();
for (IFeatureModel model : allModels) {
if (canAdd(model))
newModels.add(model);
}
IFeatureModel[] candidateModels = newModels.toArray(new IFeatureModel[newModels.size()]);
FeatureSelectionDialog dialog = new FeatureSelectionDialog(fIncludesViewer.getTable().getShell(),
candidateModels, true);
if (dialog.open() == Window.OK) {
Object[] models = dialog.getResult();
try {
doAdd(models);
} catch (CoreException e) {
PDEPlugin.log(e);
}
}
});
}
public void swap(int index1, int index2) {
Table table = getTablePart().getTableViewer().getTable();
IFeatureChild feature1 = ((IFeatureChild) table.getItem(index1).getData());
IFeatureChild feature2 = ((IFeatureChild) table.getItem(index2).getData());
IFeatureModel model = (IFeatureModel) getPage().getModel();
IFeature feature = model.getFeature();
feature.swap(feature1, feature2);
}
private void doAdd(Object[] candidates) throws CoreException {
IFeatureModel model = (IFeatureModel) getPage().getModel();
IFeature feature = model.getFeature();
IFeatureChild[] added = new IFeatureChild[candidates.length];
for (int i = 0; i < candidates.length; i++) {
IFeatureModel candidate = (IFeatureModel) candidates[i];
FeatureChild child = (FeatureChild) model.getFactory().createChild();
child.loadFrom(candidate.getFeature());
child.setVersion(ICoreConstants.DEFAULT_VERSION);
added[i] = child;
}
feature.addIncludedFeatures(added);
}
private boolean canAdd(IFeatureModel candidate) {
IFeature cfeature = candidate.getFeature();
IFeatureModel model = (IFeatureModel) getPage().getModel();
IFeature feature = model.getFeature();
if (cfeature.getId().equals(feature.getId()) && cfeature.getVersion().equals(feature.getVersion())) {
return false;
}
boolean isPatchEditor = ((FeatureEditor) getPage().getEditor()).isPatchEditor();
if (isPatchEditor && !isFeaturePatch(candidate.getFeature())) {
return false;
}
IFeatureChild[] features = feature.getIncludedFeatures();
for (IFeatureChild featureChild : features) {
if (featureChild.getId().equals(cfeature.getId()) && featureChild.getVersion().equals(cfeature.getVersion()))
return false;
}
return true;
}
private static boolean isFeaturePatch(IFeature feature) {
IFeatureImport[] imports = feature.getImports();
for (IFeatureImport featureImport : imports) {
if (featureImport.isPatch())
return true;
}
return false;
}
private void handleDelete() {
IStructuredSelection ssel = fIncludesViewer.getStructuredSelection();
if (ssel.isEmpty())
return;
IFeatureModel model = (IFeatureModel) getPage().getModel();
if (!model.isEditable()) {
return;
}
IFeature feature = model.getFeature();
try {
IFeatureChild[] removed = new IFeatureChild[ssel.size()];
int i = 0;
for (Iterator<?> iter = ssel.iterator(); iter.hasNext();) {
IFeatureChild iobj = (IFeatureChild) iter.next();
removed[i++] = iobj;
}
feature.removeIncludedFeatures(removed);
} catch (CoreException e) {
PDEPlugin.logException(e);
}
}
@Override
public boolean doGlobalAction(String actionId) {
if (actionId.equals(ActionFactory.DELETE.getId())) {
BusyIndicator.showWhile(fIncludesViewer.getTable().getDisplay(), () -> handleDelete());
return true;
}
if (actionId.equals(ActionFactory.SELECT_ALL.getId())) {
BusyIndicator.showWhile(fIncludesViewer.getTable().getDisplay(), () -> handleSelectAll());
return true;
}
if (actionId.equals(ActionFactory.CUT.getId())) {
// delete here and let the editor transfer
// the selection to the clipboard
handleDelete();
return false;
}
if (actionId.equals(ActionFactory.PASTE.getId())) {
doPaste();
return true;
}
return false;
}
@Override
protected void selectionChanged(IStructuredSelection selection) {
getPage().getPDEEditor().setSelection(selection);
updateButtons();
}
public void initialize() {
IFeatureModel model = (IFeatureModel) getPage().getModel();
refresh();
getTablePart().setButtonEnabled(0, model.isEditable());
model.addModelChangedListener(this);
FeatureModelManager mng = PDECore.getDefault().getFeatureModelManager();
mng.addFeatureModelListener(this);
}
@Override
public void modelChanged(IModelChangedEvent e) {
if (e.getChangeType() == IModelChangedEvent.WORLD_CHANGED) {
markStale();
return;
}
Object obj = e.getChangedObjects()[0];
if (obj instanceof IFeatureChild) {
if (e.getChangeType() == IModelChangedEvent.CHANGE) {
fIncludesViewer.refresh();
} else if (e.getChangeType() == IModelChangedEvent.INSERT) {
fIncludesViewer.add(e.getChangedObjects());
if (e.getChangedObjects().length > 0) {
fIncludesViewer.setSelection(new StructuredSelection(e.getChangedObjects()[0]));
}
} else if (e.getChangeType() == IModelChangedEvent.REMOVE) {
fIncludesViewer.remove(e.getChangedObjects());
}
}
}
private void makeActions() {
IModel model = (IModel) getPage().getModel();
fNewAction = new Action() {
@Override
public void run() {
handleNew();
}
};
fNewAction.setText(PDEUIMessages.Menus_new_label);
fNewAction.setEnabled(model.isEditable());
fDeleteAction = new Action() {
@Override
public void run() {
BusyIndicator.showWhile(fIncludesViewer.getTable().getDisplay(), () -> handleDelete());
}
};
fDeleteAction.setEnabled(model.isEditable());
fDeleteAction.setText(PDEUIMessages.Actions_delete_label);
fOpenAction = new OpenReferenceAction(fIncludesViewer);
}
@Override
public void modelsChanged(final IFeatureModelDelta delta) {
getSection().getDisplay().asyncExec(() -> {
if (getSection().isDisposed()) {
return;
}
IFeatureModel[] added = delta.getAdded();
IFeatureModel[] removed = delta.getRemoved();
IFeatureModel[] changed = delta.getChanged();
if (hasModels(added) || hasModels(removed) || hasModels(changed))
markStale();
});
}
private boolean hasModels(IFeatureModel[] models) {
if (models == null)
return false;
IFeatureModel thisModel = (IFeatureModel) getPage().getModel();
if (thisModel == null)
return false;
for (IFeatureModel model : models) {
if (model != thisModel) {
return true;
}
}
return false;
}
@Override
public void setFocus() {
if (fIncludesViewer != null)
fIncludesViewer.getTable().setFocus();
}
@Override
public void refresh() {
IFeatureModel model = (IFeatureModel) getPage().getModel();
IFeature feature = model.getFeature();
fIncludesViewer.setInput(feature);
updateButtons();
super.refresh();
}
private void updateButtons() {
TablePart tablePart = getTablePart();
Table table = tablePart.getTableViewer().getTable();
TableItem[] tableSelection = table.getSelection();
boolean hasSelection = tableSelection.length > 0;
//delete
tablePart.setButtonEnabled(REMOVE, isEditable() && hasSelection);
// up/down buttons
boolean canMove = table.getItemCount() > 1 && tableSelection.length == 1 && !fSortAction.isChecked();
tablePart.setButtonEnabled(UP, canMove && isEditable() && hasSelection && table.getSelectionIndex() > 0);
tablePart.setButtonEnabled(DOWN, canMove && hasSelection && isEditable() && table.getSelectionIndex() < table.getItemCount() - 1);
}
/**
* @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canPaste(Clipboard)
*/
@Override
public boolean canPaste(Clipboard clipboard) {
Object[] objects = (Object[]) clipboard.getContents(ModelDataTransfer.getInstance());
if (objects != null && objects.length > 0) {
return canPaste(null, objects);
}
return false;
}
/**
* @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canPaste(Object,
* Object[])
*/
@Override
protected boolean canPaste(Object target, Object[] objects) {
for (int i = 0; i < objects.length; i++) {
if (!(objects[i] instanceof FeatureChild))
return false;
}
return true;
}
/**
* @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doPaste()
*/
@Override
protected void doPaste() {
Clipboard clipboard = getPage().getPDEEditor().getClipboard();
ModelDataTransfer modelTransfer = ModelDataTransfer.getInstance();
Object[] objects = (Object[]) clipboard.getContents(modelTransfer);
if (objects != null) {
doPaste(null, objects);
}
}
/**
* @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doPaste(Object,
* Object[])
*/
@Override
protected void doPaste(Object target, Object[] objects) {
IFeatureModel model = (IFeatureModel) getPage().getModel();
IFeature feature = model.getFeature();
if (!model.isEditable()) {
return;
}
FeatureChild[] fChildren = new FeatureChild[objects.length];
try {
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof FeatureChild) {
FeatureChild fChild = (FeatureChild) objects[i];
fChild.setModel(model);
fChild.setParent(feature);
fChildren[i] = fChild;
}
}
feature.addIncludedFeatures(fChildren);
} catch (CoreException e) {
PDEPlugin.logException(e);
}
}
void fireSelection() {
IStructuredSelection sel = fIncludesViewer.getStructuredSelection();
if (!sel.isEmpty()) {
fIncludesViewer.setSelection(fIncludesViewer.getStructuredSelection());
} else if (fIncludesViewer.getElementAt(0) != null) {
fIncludesViewer.setSelection(new StructuredSelection(fIncludesViewer.getElementAt(0)));
}
}
@Override
protected boolean createCount() {
return true;
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if (fSortAction.equals(event.getSource()) && IAction.RESULT.equals(event.getProperty())) {
updateButtons();
}
}
}