/*******************************************************************************
* 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 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.ModelChangeEvent;
import org.eclipse.equinox.p2.authoring.internal.P2AuthoringLabelProvider;
import org.eclipse.equinox.p2.authoring.internal.InstallableUnitBuilder.ProvidedCapabilityBuilder;
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 Provided Capabilities that display's the capabilities in a list and allows for editing
* of elements in the tree. Supports undo of operations.
*
* @author Henrik Lindberg
*
*/
public class ProvidedBodyBlock extends TableMasterDetailsBlock implements IDetailsPageProvider,
IMasterDetailsController, IPageMementoProvider
{
private IDetailsPage m_providedPage;
private IBaseLabelProvider m_labelProvider;
private IStructuredContentProvider m_contentProvider;
private MasterFormPart m_masterFormPart;
public ProvidedBodyBlock(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 "Provided Capabilities";
}
@Override
public String getDescription()
{
return "Edit the capabilities provided by this installable unit.";
}
/**
* Adds a default provided capability for editing. Operation can be undone.
*/
public void add()
{
ProvidedCapabilityBuilder provided = new ProvidedCapabilityBuilder( //
"org.equinox.p2.iu", // $NON-NLS-1$
"provided.name", //
"1.0.0"); // $NON-NLS-1$
addRemove(provided, true);
}
/**
* Method common to both add and remove. Operation can be undone.
*
* @param provided
* what to add or remove
* @param add
* true if provided should be added, false to remove
*/
private void addRemove(ProvidedCapabilityBuilder provided, boolean add)
{
FormToolkit toolkit = m_formPage.getManagedForm().getToolkit();
if(toolkit instanceof IUndoOperationSupport)
{
AddRemoveOperation op = new AddRemoveOperation(provided, 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.addProvidedCapability(provided);
}
}
/**
* 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 provided capability down in the list. Operation can be undone.
*/
public void down()
{
move(1);
}
/**
* Moves selected provided capability up in the list. Operation can be undone.
*/
public void up()
{
move(-1);
}
/**
* Common move operation - moved provided 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)
ProvidedCapabilityBuilder provided = (ProvidedCapabilityBuilder)ssel.getFirstElement();
FormToolkit toolkit = m_formPage.getManagedForm().getToolkit();
if(toolkit instanceof IUndoOperationSupport)
{
MoveOperation op = new MoveOperation(provided, 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 getProvidedPage()
{
// 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_providedPage == null)
m_providedPage = new ProvidedCapabilityPage();
return m_providedPage;
}
/**
* Returns a content provider for provided 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.getProvidedCapabilities();
}
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 getProvidedPage();
}
/**
* Selects a page key for the selected object. See {@link #getPage(Object)}. Currently, there is only one type of
* details page key - "provided".
*/
public Object getPageKey(Object object)
{
return "provided";
}
/**
* Removes the selected provided 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((ProvidedCapabilityBuilder)ssel.getFirstElement(), false);
}
private class MasterFormPart extends AbstractFormPart
{
@Override
public void initialize(IManagedForm form)
{
super.initialize(form);
// register a listener to Provided Capability change events
if(form.getToolkit() instanceof IEditEventBusProvider)
{
((IEditEventBusProvider)form.getToolkit()).getEventBus().addListener(new IEditorListener()
{
public void notify(EventObject o)
{
if(!(o instanceof ModelChangeEvent))
return;
if(((ModelChangeEvent)o).getDetail() instanceof ProvidedCapabilityBuilder)
ProvidedBodyBlock.this.m_viewer.refresh(((ModelChangeEvent)o).getDetail(), true);
}
});
}
}
/**
* Refreshes the viewer with stale model changes
*/
@Override
public void refresh()
{
ProvidedBodyBlock.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 provided body block is.
*/
private void switchFocus(ProvidedCapabilityBuilder 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 provided capability.
*
* @author Henrik Lindberg
*
*/
private class AddRemoveOperation extends AbstractOperation
{
private ProvidedCapabilityBuilder m_provided;
private boolean m_add;
private int m_index;
public AddRemoveOperation(ProvidedCapabilityBuilder provided, boolean add)
{
super((add
? "Add"
: "Remove") + " Provided Capability");
m_provided = provided;
m_add = add;
}
private void updatePageState(boolean select)
{
m_masterFormPart.markStale();
m_masterFormPart.markDirty();
switchFocus(select
? m_provided
: 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.addProvidedCapability(m_provided);
else
m_index = iu.removeProvidedCapability(m_provided);
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.removeProvidedCapability(m_provided);
else
iu.addProvidedCapability(m_provided, m_index);
updatePageState(!m_add);
if(monitor != null)
monitor.done();
return Status.OK_STATUS;
}
}
/**
* Undoable operation class for moving provided capability.
*
* @author Henrik Lindberg
*
*/
private class MoveOperation extends AbstractOperation
{
private ProvidedCapabilityBuilder m_provided;
private int m_delta;
public MoveOperation(ProvidedCapabilityBuilder provided, int delta)
{
super("Move Provided Capability");
m_provided = provided;
m_delta = delta;
}
private void updatePageState()
{
m_masterFormPart.markStale();
m_masterFormPart.markDirty();
switchFocus(m_provided); // 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.moveProvidedCapability(m_provided, 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);
}
}
}