/*****************************************************************************
* Copyright (c) 2006-2008 g-Eclipse Consortium
* 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
*
* Initial development of the original code was made for the
* g-Eclipse project founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributors:
* Mathias Stuempert - initial API and implementation
*****************************************************************************/
package eu.geclipse.ui.views;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.util.DelegatingDragAdapter;
import org.eclipse.jface.util.DelegatingDropAdapter;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.ActionGroup;
import org.eclipse.ui.navigator.ICommonMenuConstants;
import org.eclipse.ui.part.ViewPart;
import eu.geclipse.core.model.GridModel;
import eu.geclipse.core.model.IGridElement;
import eu.geclipse.core.model.IGridModelEvent;
import eu.geclipse.core.model.IGridModelListener;
import eu.geclipse.ui.decorators.GridProjectFolderDecorator;
import eu.geclipse.ui.internal.actions.AccessControlActions;
import eu.geclipse.ui.internal.actions.ActionGroupManager;
import eu.geclipse.ui.internal.actions.CommonActions;
import eu.geclipse.ui.internal.actions.FileActions;
import eu.geclipse.ui.internal.actions.MountActions;
import eu.geclipse.ui.internal.actions.OpenActions;
import eu.geclipse.ui.internal.actions.TreeViewerActions;
import eu.geclipse.ui.internal.transfer.SelectionTransferDragAdapter;
import eu.geclipse.ui.internal.transfer.SelectionTransferDropAdapter;
/**
* Abstract superclass of all views that show
* {@link eu.geclipse.core.model.GridModel} related data. Views that
* extend this class mainly consist of a {@link StructuredViewer} and
* may contribute actions to context menus for instance. The root
* element of the viewer has to be an {@link IGridElement} that is returned
* by the {@link #getRootElement()} method. Subclasses also have to
* specified the content and label providers that are used to render
* the data. These providers are specified by the
* {@link #createContentProvider()} and {@link #createLabelProvider()}
* methods.
*/
public abstract class GridModelViewPart
extends ViewPart
implements IGridModelListener {
/**
* The viewer that is used to render the data.
*/
StructuredViewer viewer;
private ActionGroup actions;
private OpenActions openActions;
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl( final Composite parent ) {
// Initialize the viewer
this.viewer = createViewer( parent );
initViewer( this.viewer );
this.getSite().setSelectionProvider( this.viewer );
this.actions = createActions();
fillActionBars( this.actions );
createContextMenu( this.viewer );
GridModel.getRoot().addGridModelListener( this );
updateActionBars();
}
private void updateActionBars() {
if( this.actions != null) {
ISelection selection = this.viewer.getSelection();
this.actions.setContext(new ActionContext(selection));
this.actions.updateActionBars();
}
}
@Override
public void dispose() {
if ( this.actions != null ) {
this.actions.dispose();
}
GridModel.getRoot().removeGridModelListener( this );
super.dispose();
}
/**
* Get the {@link StructuredViewer} that is associated with this
* view.
*
* @return The viewer that is responsible to show the content of this
* view.
*/
public StructuredViewer getViewer() {
return this.viewer;
}
/* (non-Javadoc)
* @see eu.geclipse.core.model.IGridModelListener#gridModelChanged(eu.geclipse.core.model.IGridModelEvent)
*/
public void gridModelChanged( final IGridModelEvent event ) {
if ( ( event.getType() == IGridModelEvent.ELEMENTS_ADDED )
|| ( event.getType() == IGridModelEvent.ELEMENTS_REMOVED ) ) {
refreshViewer( event.getSource() );
} else if ( event.getType() == IGridModelEvent.PROJECT_FOLDER_CHANGED ) {
GridProjectFolderDecorator decorator
= GridProjectFolderDecorator.getDecorator();
if ( decorator != null ) {
decorator.refresh( event.getElements() );
}
}
}
/**
* Determines if drag'n'drop should be made available for the specified
* element.
*
* @param element The element for which drag'n'drop operations should
* be either allowed or forbidden.
* @return True if drag'n'drop should be enabled for the specified
* element, false otherwise.
*/
public boolean isDragSource( final IGridElement element ) {
return !element.isVirtual();
}
/**
* Refresh the associated {@link StructuredViewer}. Calls the
* {@link StructuredViewer#refresh()} method and ensures that
* this method is called in an UI thread.
*
* @see StructuredViewer#refresh()
*/
public void refreshViewer() {
refreshViewer( null );
}
/**
* Refresh the associated {@link StructuredViewer}. Calls the
* {@link StructuredViewer#refresh(Object)} method and ensures that
* this method is called in an UI thread.
*
* @param element The element that should be refreshed recursively.
* @see StructuredViewer#refresh(Object)
*/
public void refreshViewer( final IGridElement element ) {
if ( this.viewer != null ) {
Control control = this.viewer.getControl();
if ( ! control.isDisposed() ) {
Display display = control.getDisplay();
display.asyncExec( new Runnable() {
public void run() {
if ( ! GridModelViewPart.this.viewer.getControl().isDisposed() ) {
if ( element == null ) {
GridModelViewPart.this.viewer.refresh( false );
} else {
GridModelViewPart.this.viewer.refresh( element, false );
}
}
}
} );
}
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
this.viewer.getControl().setFocus();
}
protected void addDragSourceListeners( final DelegatingDragAdapter adapter ) {
adapter.addDragSourceListener( new SelectionTransferDragAdapter( this ) );
}
protected void addDropTargetListeners( final DelegatingDropAdapter adapter ) {
adapter.addDropTargetListener( new SelectionTransferDropAdapter() );
}
protected ActionGroup createActions() {
ActionGroupManager manager = new ActionGroupManager();
contributeAdditionalActions( manager );
contributeStandardActions( manager );
return manager;
}
protected void contributeStandardActions( final ActionGroupManager groups ) {
this.openActions = new OpenActions( this );
groups.addGroup( this.openActions );
FileActions fileActions = new FileActions( this );
groups.addGroup( fileActions );
MountActions mountActions = new MountActions( getSite() );
groups.addGroup( mountActions );
AccessControlActions aclActions = new AccessControlActions( getSite() );
groups.addGroup( aclActions );
CommonActions commonActions = new CommonActions( this );
groups.addGroup( commonActions );
StructuredViewer sViewer = getViewer();
if ( sViewer instanceof TreeViewer ) {
TreeViewer tViewer = ( TreeViewer ) sViewer;
TreeViewerActions treeViewerActions
= new TreeViewerActions( tViewer );
groups.addGroup( treeViewerActions );
}
}
protected void contributeAdditionalActions( @SuppressWarnings("unused")
final ActionGroupManager groups ) {
// empty implementation
}
/**
* Create and return an instance of an {@link IContentProvider} that is
* used to provide the content to be rendered in the viewer. This method
* is called once on initialization and may not be called subsequently.
*
* @return The newly created {@link IContentProvider} that is responsible
* for providing the data rendered in the associated {@link StructuredViewer}.
* @see #createViewer(Composite)
* @see #createLabelProvider()
*/
protected abstract IContentProvider createContentProvider();
/**
* Create the context menu for the specified viewer. This is the viewer obtained
* by {@link #createContentProvider()}. This method is called
* automatically by {@link #createPartControl(Composite)}.
* @param sViewer The {@link StructuredViewer} to be initialised.
* @see #createViewer(Composite)
* @see #createPartControl(Composite)
*/
protected void createContextMenu( final StructuredViewer sViewer ) {
MenuManager manager = new MenuManager();
manager.setRemoveAllWhenShown( true );
manager.addMenuListener( new IMenuListener() {
public void menuAboutToShow( final IMenuManager mgr ) {
fillContextMenu( mgr );
}
} );
Menu menu = manager.createContextMenu( sViewer.getControl() );
sViewer.getControl().setMenu(menu);
getSite().registerContextMenu( manager, sViewer );
}
/**
* Create the standard menu groups in the specified context
* menu. Subclasses may overwrite this method in order to add
* new groups or to completely change the groups.
*
* @param menu The menu manager in which to create the groups.
*/
protected void createContextMenuGroups( final IMenuManager menu ) {
menu.add( new Separator( ICommonMenuConstants.GROUP_NEW ) );
menu.add( new GroupMarker( ICommonMenuConstants.GROUP_GOTO ) );
menu.add( new GroupMarker( ICommonMenuConstants.GROUP_OPEN ) );
menu.add( new GroupMarker( ICommonMenuConstants.GROUP_OPEN_WITH ) );
menu.add( new Separator( ICommonMenuConstants.GROUP_EDIT ) );
menu.add( new GroupMarker( ICommonMenuConstants.GROUP_SHOW ) );
menu.add( new GroupMarker( ICommonMenuConstants.GROUP_REORGANIZE ) );
menu.add( new GroupMarker( ICommonMenuConstants.GROUP_PORT ) );
menu.add( new Separator( ICommonMenuConstants.GROUP_GENERATE ) );
menu.add( new Separator( ICommonMenuConstants.GROUP_SEARCH ) );
menu.add( new Separator( ICommonMenuConstants.GROUP_BUILD ) );
menu.add( new Separator( ICommonMenuConstants.GROUP_ADDITIONS ) );
menu.add( new Separator( ICommonMenuConstants.GROUP_PROPERTIES ) );
}
/**
* Create and return an instance of an {@link IBaseLabelProvider} that is
* used to render the content in the viewer. This method
* is called once on initialization and may not be called subsequently.
*
* @return The newly created {@link IBaseLabelProvider} that is responsible
* for rendering the data in the associated {@link StructuredViewer}.
* @see #createViewer(Composite)
* @see #createContentProvider()
*/
protected abstract IBaseLabelProvider createLabelProvider();
/**
* Create and return an instance of a {@link StructuredViewer} that is
* used to render the data. This method
* is called once on initialization and may not be called subsequently.
*
* @param parent The parent composite.
* @return The newly created {@link StructuredViewer}.
* @see #createContentProvider()
* @see #createLabelProvider()
*/
protected abstract StructuredViewer createViewer( final Composite parent );
/**
* Fill the action bars of this view with the specified action group.
* The group itself holds the functionality to fill the actions bars.
*
* @param group The {@link ActionGroup} that is used to fill the
* action bars.
*/
protected void fillActionBars( final ActionGroup group ) {
IActionBars actionBars = getViewSite().getActionBars();
group.fillActionBars( actionBars );
}
/**
* Fill the context menu from the actions of this view. This is
* called interactively when the menu is about to be shown.
*
* @param menu The menu to be filled.
*/
protected void fillContextMenu( final IMenuManager menu ) {
ISelection selection = this.viewer.getSelection();
ActionContext context = new ActionContext( selection );
createContextMenuGroups( menu );
this.actions.setContext( context );
this.actions.fillContextMenu( menu );
this.actions.setContext( null );
}
/**
* Get the root element that is used as the data for the structured
* viewer.
*
* @return The root data for the {@link StructuredViewer} of this
* view.
*/
protected abstract IGridElement getRootElement();
/**
* Handle a double click event that occurred in the viewer of this
* view.
*
* @param event The associated {@link DoubleClickEvent}.
*/
protected void handleDoubleClick( final DoubleClickEvent event ) {
if ( this.viewer instanceof TreeViewer ) {
TreeViewer treeViewer = ( TreeViewer ) this.viewer;
ISelection selection = event.getSelection();
if ( selection instanceof IStructuredSelection ) {
Object element
= ( ( IStructuredSelection ) selection ).getFirstElement();
if ( treeViewer.isExpandable( element ) ) {
boolean state = treeViewer.getExpandedState( element );
treeViewer.setExpandedState( element, !state );
}
}
}
}
/**
* Handle an open event that occurred in the associated viewer.
*
* @param event The associated {@link OpenEvent}.
*/
protected void handleOpen( final OpenEvent event ) {
this.openActions.delegateOpenEvent( event );
}
protected void initDragAndDrop( final StructuredViewer sViewer ) {
initDrag( sViewer );
initDrop( sViewer );
}
protected void initDrag( final StructuredViewer sViewer ) {
int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
DelegatingDragAdapter adapter = new DelegatingDragAdapter();
addDragSourceListeners( adapter );
sViewer.addDragSupport( operations, adapter.getTransfers(), adapter );
}
protected void initDrop( final StructuredViewer sViewer ) {
int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
DelegatingDropAdapter adapter = new DelegatingDropAdapter();
addDropTargetListeners( adapter );
sViewer.addDropSupport( operations, adapter.getTransfers(), adapter );
}
/**
* Initialize the specified viewer. This is the viewer obtained
* by {@link #createContentProvider()}. This method is called
* automatically by {@link #createPartControl(Composite)}.
*
* @param sViewer The {@link StructuredViewer} to be initialised.
* @see #createViewer(Composite)
* @see #createPartControl(Composite)
*/
protected void initViewer( final StructuredViewer sViewer ) {
sViewer.setLabelProvider( createLabelProvider() );
sViewer.setContentProvider( createContentProvider() );
sViewer.setInput( getRootElement() );
registerViewerListeners( sViewer );
initDragAndDrop( sViewer );
}
/**
* Register the listeners for the specified viewer. This is the viewer obtained
* by {@link #createContentProvider()}. This method is called
* automatically by {@link #createPartControl(Composite)}.
*
* @param sViewer The {@link StructuredViewer} to be initialised.
* @see #createViewer(Composite)
* @see #createPartControl(Composite)
*/
protected void registerViewerListeners( final StructuredViewer sViewer ) {
sViewer.addDoubleClickListener( new IDoubleClickListener() {
public void doubleClick( final DoubleClickEvent event ) {
handleDoubleClick( event );
}
} );
sViewer.addOpenListener( new IOpenListener() {
public void open( final OpenEvent event ) {
handleOpen( event );
}
} );
}
}