/******************************************************************************* * Copyright (c) 2008 * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the individual * copyright holders listed below, as Initial Contributors under such license. * The text of such license is available at * http://www.eclipse.org/legal/epl-v10.html. * * Contributors: * Henrik Lindberg *******************************************************************************/ package org.eclipse.equinox.p2.authoring; import java.util.EventObject; import javax.swing.event.ChangeEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.operations.AbstractOperation; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.p2.authoring.forms.IMasterDetailsController; import org.eclipse.equinox.p2.authoring.forms.IPageMementoProvider; import org.eclipse.equinox.p2.authoring.forms.TableMasterDetailsBlock; import org.eclipse.equinox.p2.authoring.internal.IEditEventBusProvider; import org.eclipse.equinox.p2.authoring.internal.IEditorListener; import org.eclipse.equinox.p2.authoring.internal.IUndoOperationSupport; import org.eclipse.equinox.p2.authoring.internal.InstallableUnitBuilder; import org.eclipse.equinox.p2.authoring.internal.P2AuthoringLabelProvider; import org.eclipse.equinox.p2.authoring.internal.InstallableUnitBuilder.ArtifactKeyBuilder; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.forms.AbstractFormPart; import org.eclipse.ui.forms.IDetailsPage; import org.eclipse.ui.forms.IDetailsPageProvider; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.forms.widgets.FormToolkit; /** * A MasterDetails block for IU ArtifactKeys that displays the artifacts in a list and allows for editing * of elements in the list. Supports undo of operations. * * @author Henrik Lindberg * */ public class ArtifactsBodyBlock extends TableMasterDetailsBlock implements IDetailsPageProvider, IMasterDetailsController, IPageMementoProvider { private IDetailsPage m_artifactPage; private IBaseLabelProvider m_labelProvider; private IStructuredContentProvider m_contentProvider; private MasterFormPart m_masterFormPart; public ArtifactsBodyBlock(FormPage page, Object layoutData) { super(page, layoutData, 350); } @Override protected void createMasterPart(final IManagedForm managedForm, Composite parent) { super.createMasterPart(managedForm, parent); // create the view m_masterFormPart = new MasterFormPart(); // create the manager of the view data lifecycle managedForm.addPart(m_masterFormPart); // and make it part of the overall lifecycle } @Override public String getName() { return "Artifact Keys"; } @Override public String getDescription() { return "Edit the artifact keys that make up the content of this this installable unit."; } /** * Adds a default ArtifactKey for editing. Operation can be undone. */ public void add() { ArtifactKeyBuilder artifact = new ArtifactKeyBuilder( // "some.classifier", //$NON-NLS-1$ "some.name", // "1.0.0"); // $NON-NLS-1$ addRemove(artifact, true); } /** * Method common to both add and remove. Operation can be undone. * @param artifact what to add or remove * @param add true if required should be added, false to remove */ private void addRemove(ArtifactKeyBuilder artifact, boolean add) { FormToolkit toolkit = m_formPage.getManagedForm().getToolkit(); if(toolkit instanceof IUndoOperationSupport) { AddRemoveOperation op = new AddRemoveOperation(artifact, add); op.addContext(((IUndoOperationSupport)toolkit).getUndoContext()); try { ((IUndoOperationSupport)toolkit).getOperationHistory().execute(op, null, null); } catch(ExecutionException e) { // TODO Proper logging e.printStackTrace(); } } else { // without undo support - just add it... (should not happen) InstallableUnitBuilder iu = ((InstallableUnitEditor)m_formPage.getEditor()).getInstallableUnit(); iu.addArtifactKey(artifact); } } /** * Configures the add button to have a menu with different add types * TODO: clean up popup menu code if it will not be used */ @Override protected void configureAddButton(final Button b) { // Create a listener for menu items so that the correct // type of add operation is performed. // SelectionListener listener = new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { add(); // // example of add menu - keep if there should be more ways to add something... // Object data = e.item.getData(); // if("link".equals(data)) // addLink(); } }; b.addSelectionListener(listener); // // example of add menu // Menu addMenu = new Menu(b.getShell(), SWT.POP_UP); // mi = new MenuItem(addMenu, SWT.PUSH); // mi.setText("Add Link"); // mi.setData("link"); // mi.addSelectionListener(listener); // // // attach menu to button (pops up on right mouse click) // b.setMenu(addMenu); // // attach listener to button so menu pops up on button click (left click) // b.addSelectionListener(new SelectionListener() // { public void widgetDefaultSelected(SelectionEvent e) // { widgetSelected(e); } // public void widgetSelected(SelectionEvent e) // { b.getMenu().setVisible(true);} // }); } /** * Moves selected required capability down in the list. Operation can be undone. */ public void down() { move(1); } /** * Moves selected required capability up in the list. Operation can be undone. */ public void up() { move(-1); } /** * Common move operation - moved required capability up or down in the list. Operation can be undone. */ private void move(int delta) { IStructuredSelection ssel = (IStructuredSelection)m_viewer.getSelection(); if(ssel == null || ssel.size() != 1) return; // nothing to move (or too many) ArtifactKeyBuilder artifact = (ArtifactKeyBuilder)ssel.getFirstElement(); FormToolkit toolkit = m_formPage.getManagedForm().getToolkit(); if(toolkit instanceof IUndoOperationSupport) { MoveOperation op = new MoveOperation(artifact, delta); op.addContext(((IUndoOperationSupport)toolkit).getUndoContext()); try { ((IUndoOperationSupport)toolkit).getOperationHistory().execute(op, null, null); } catch(ExecutionException e) { // TODO Proper logging e.printStackTrace(); } } } @Override public IDetailsPageProvider getDetailsPageProvider() { return this; } public IDetailsPage getArtifactPage() { // TODO: no need to cache? Master detail editor creates this on demand and keeps it, // but then the undo history may refer to deleted (and recreated elements). // if(m_artifactPage == null) m_artifactPage = new ArtifactPage(); return m_artifactPage; } /** * Returns a content provider for required capabilities from the editors installable unit. */ @Override public IStructuredContentProvider getMasterContentProvider() { if(m_contentProvider == null) m_contentProvider = new IStructuredContentProvider() { public Object[] getElements(Object inputElement) { InstallableUnitBuilder iu = ((InstallableUnitEditor)m_formPage.getEditor()).getInstallableUnit(); return iu.getArtifacts(); } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } }; return m_contentProvider; } /** * Returns 'this' as a handler of add, remove, up, down,... */ @Override public IMasterDetailsController getMasterDetailsController() { return this; } /** * Returns a styled label provider using the {@link P2AuthoringLabelProvider} as the base label provider. */ @Override public IBaseLabelProvider getMasterLabelProvider() { if(m_labelProvider == null) m_labelProvider = new DelegatingStyledCellLabelProvider(new P2AuthoringLabelProvider()); return m_labelProvider; } /** * Returns a page for a page key returned by {@link #getPageKey(Object)}. Currently, there is only one type of * details page. */ public IDetailsPage getPage(Object key) { return getArtifactPage(); } /** * Selects a page key for the selected object. See {@link #getPage(Object)}. Currently, there is only one type * of details page key - "required". */ public Object getPageKey(Object object) { return "artifact"; } /** * Removes the selected required capability. The operation can be undone. */ public void remove() { // remove everything selected IStructuredSelection ssel = (IStructuredSelection)m_viewer.getSelection(); if(ssel == null || ssel.getFirstElement() == null) return; // nothing to remove addRemove((ArtifactKeyBuilder)ssel.getFirstElement(), false); } private class MasterFormPart extends AbstractFormPart { @Override public void initialize(IManagedForm form) { super.initialize(form); // register a listener to Required Capability change events if(form.getToolkit() instanceof IEditEventBusProvider) { ((IEditEventBusProvider)form.getToolkit()).getEventBus().addListener(new IEditorListener(){ public void notify(EventObject o) { if(o instanceof ChangeEvent && o.getSource() instanceof ArtifactKeyBuilder) ArtifactsBodyBlock.this.m_viewer.refresh(o.getSource(), true); } }); } } /** * Refreshes the viewer with stale model changes */ @Override public void refresh() { ArtifactsBodyBlock.this.m_viewer.refresh(); super.refresh(); } } /** * Returns a memento that restores this page selection. */ public Object getPageMemento() { return ((IStructuredSelection)m_viewer.getSelection()).getFirstElement(); } /** * Restores this page selection from the memento. */ public void setPageMemento(Object memento) { if(memento != null) m_viewer.setSelection(new StructuredSelection(memento), true); } /** * Switches focus in the editor to the page where this required body block is. */ private void switchFocus(ArtifactKeyBuilder select) { FormEditor editor = m_formPage.getEditor(); IFormPage currentPage = editor.getActivePageInstance(); if(!m_formPage.getId().equals(currentPage.getId())) editor.setActivePage(m_formPage.getId()); if(select != null) m_viewer.setSelection(new StructuredSelection(select), true); } /** * Undoable operation for add/remove of required capability. * @author Henrik Lindberg * */ private class AddRemoveOperation extends AbstractOperation { private ArtifactKeyBuilder m_artifact; private boolean m_add; private int m_index; public AddRemoveOperation(ArtifactKeyBuilder artifact, boolean add) { super((add ? "Add" : "Remove") + " Artifact Key"); m_artifact = artifact; m_add = add; } private void updatePageState(boolean select) { m_masterFormPart.markStale(); m_masterFormPart.markDirty(); switchFocus(select ? m_artifact : null); // switch focus if on another page } @Override public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { return redo(monitor, info); } @Override public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { InstallableUnitBuilder iu = ((InstallableUnitEditor)m_formPage.getEditor()).getInstallableUnit(); if(m_add) m_index = iu.addArtifactKey(m_artifact); else m_index = iu.removeArtifactKey(m_artifact); updatePageState(m_add); if(monitor != null) monitor.done(); return Status.OK_STATUS; } @Override public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { InstallableUnitBuilder iu = ((InstallableUnitEditor)m_formPage.getEditor()).getInstallableUnit(); if(m_add) iu.removeArtifactKey(m_artifact); else iu.addArtifactKey(m_artifact, m_index); updatePageState(!m_add); if(monitor != null) monitor.done(); return Status.OK_STATUS; } } /** * Undoable operation class for moving artifact key. * @author Henrik Lindberg * */ private class MoveOperation extends AbstractOperation { private ArtifactKeyBuilder m_artifact; private int m_delta; public MoveOperation(ArtifactKeyBuilder artifact, int delta) { super("Move Artifact Key"); m_artifact = artifact; m_delta = delta; } private void updatePageState() { m_masterFormPart.markStale(); m_masterFormPart.markDirty(); switchFocus(m_artifact); // switch focus if on another page } @Override public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { return redo(monitor, info); } @Override public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { return xxdo(monitor, info, m_delta); } public IStatus xxdo(IProgressMonitor monitor, IAdaptable info, int delta) throws ExecutionException { InstallableUnitBuilder iu = ((InstallableUnitEditor)m_formPage.getEditor()).getInstallableUnit(); iu.moveArtifactKey(m_artifact, delta); updatePageState(); if(monitor != null) monitor.done(); return Status.OK_STATUS; } @Override public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { return xxdo(monitor, info, -m_delta); } } }