blob: 1591175de33e65c36e4d53d808f4d18114e0c9c7 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2008 Oracle
* 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:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.wst.common.project.facet.ui;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework;
import org.eclipse.wst.common.project.facet.core.FacetedProjectFrameworkException;
import org.eclipse.wst.common.project.facet.core.IActionDefinition;
import org.eclipse.wst.common.project.facet.core.ICategory;
import org.eclipse.wst.common.project.facet.core.IFacetedProject;
import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy;
import org.eclipse.wst.common.project.facet.core.IPreset;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
import org.eclipse.wst.common.project.facet.core.IFacetedProject.Action;
import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectEvent;
import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectListener;
import org.eclipse.wst.common.project.facet.core.util.IFilter;
import org.eclipse.wst.common.project.facet.core.util.IFilter.IFilterEvent;
import org.eclipse.wst.common.project.facet.core.util.IFilter.IFilterListener;
import org.eclipse.wst.common.project.facet.ui.internal.FacetUiPlugin;
import org.eclipse.wst.common.project.facet.ui.internal.FacetsSelectionPage;
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
public class ModifyFacetedProjectWizard
extends Wizard
{
private IFacetedProjectWorkingCopy fpjwc;
private final WizardContext context = new WizardContext();
private boolean showFacetsSelectionPage;
private FacetsSelectionPage facetsSelectionPage;
private FacetPages[] facetPages = new FacetPages[ 0 ];
private Composite pageContainer;
private final List<IWizardPage> pagesToDispose = new ArrayList<IWizardPage>();
private final List<Runnable> delayedActions;
private final List<Runnable> onDisposeActions;
private final boolean disposeWorkingCopy;
public ModifyFacetedProjectWizard()
{
this( (IFacetedProject) null );
}
public ModifyFacetedProjectWizard( final IFacetedProject fproj )
{
this( fproj == null
? FacetedProjectFramework.createNewProject()
: fproj.createWorkingCopy(), true );
}
public ModifyFacetedProjectWizard( final IFacetedProjectWorkingCopy fpjwc )
{
this( fpjwc, false );
}
private ModifyFacetedProjectWizard( final IFacetedProjectWorkingCopy fpjwc,
final boolean disposeWorkingCopy )
{
try
{
this.fpjwc = fpjwc;
this.delayedActions = new ArrayList<Runnable>();
this.onDisposeActions = new ArrayList<Runnable>();
this.disposeWorkingCopy = disposeWorkingCopy;
this.facetsSelectionPage = null;
this.showFacetsSelectionPage = true;
setNeedsProgressMonitor( true );
setForcePreviousAndNextButtons( true );
setWindowTitle( Resources.wizardTitle );
}
catch( RuntimeException e )
{
FacetUiPlugin.log( e );
throw e;
}
}
public final IFacetedProjectWorkingCopy getFacetedProjectWorkingCopy()
{
return this.fpjwc;
}
public void setFacetedProjectWorkingCopy( final IFacetedProjectWorkingCopy fpjwc )
{
this.fpjwc = fpjwc;
}
public final IFacetedProject getFacetedProject()
{
IFacetedProject fproj = this.fpjwc.getFacetedProject();
if( fproj == null )
{
final String projectName = this.fpjwc.getProjectName();
if( projectName != null )
{
final IProject proj
= ResourcesPlugin.getWorkspace().getRoot().getProject( projectName );
try
{
fproj = ProjectFacetsManager.create( proj );
}
catch( CoreException e )
{
FacetUiPlugin.log( e );
}
}
}
return fproj;
}
public void addPages()
{
final IFacetedProjectListener listener = new IFacetedProjectListener()
{
public void handleEvent( final IFacetedProjectEvent event )
{
final Runnable runnable = new Runnable()
{
public void run()
{
handleSelectedFacetsChangedEvent();
}
};
Display.getDefault().asyncExec( runnable );
}
};
this.fpjwc.addListener( listener, IFacetedProjectEvent.Type.PROJECT_FACETS_CHANGED );
this.onDisposeActions.add
(
new Runnable()
{
public void run()
{
ModifyFacetedProjectWizard.this.fpjwc.removeListener( listener );
}
}
);
if( getShowFacetsSelectionPage() )
{
this.facetsSelectionPage = new FacetsSelectionPage( getBaseFacets(), this.fpjwc );
addPage( this.facetsSelectionPage );
}
}
public int getPageCount()
{
return getPages().length;
}
public IWizardPage[] getPages()
{
final List<IWizardPage> list = new ArrayList<IWizardPage>();
if( this.facetsSelectionPage != null )
{
list.add( this.facetsSelectionPage );
}
for( int i = 0; i < this.facetPages.length; i++ )
{
list.addAll( this.facetPages[ i ].pages );
}
return list.toArray( new IWizardPage[ list.size() ] );
}
public IWizardPage getPage( final String pageName )
{
final IWizardPage[] pages = getPages();
for( int i = 0; i < pages.length; i++ )
{
final IWizardPage page = pages[ i ];
if( page.getName().equals( pageName ) )
{
return page;
}
}
return null;
}
public IWizardPage getStartingPage()
{
return getPages()[ 0 ];
}
public IWizardPage getNextPage( final IWizardPage page )
{
final IWizardPage[] pages = getPages();
int pos = -1;
for( int i = 0; i < pages.length; i++ )
{
if( pages[ i ] == page )
{
pos = i;
}
}
if( pos == pages.length - 1 )
{
return null;
}
else
{
return pages[ pos + 1 ];
}
}
public IWizardPage getPreviousPage( final IWizardPage page )
{
final IWizardPage[] pages = getPages();
int pos = -1;
for( int i = 0; i < pages.length; i++ )
{
if( pages[ i ] == page )
{
pos = i;
}
}
if( pos == 0 )
{
return null;
}
else
{
return pages[ pos - 1 ];
}
}
public boolean canFinish()
{
if( this.facetsSelectionPage != null && ! this.facetsSelectionPage.isPageComplete() )
{
return false;
}
final IWizardPage[] pages = getPages();
for( int i = 0; i < pages.length; i++ )
{
if( ! pages[ i ].isPageComplete() )
{
return false;
}
}
return true;
}
public void createPageControls( final Composite container )
{
super.createPageControls( container );
this.pageContainer = container;
handleSelectedFacetsChangedEvent();
executeDelayedActions();
}
public boolean performFinish()
{
for( int i = 0; i < this.facetPages.length; i++ )
{
for( IFacetWizardPage fp : this.facetPages[ i ].pages )
{
fp.transferStateToConfig();
}
}
final IWorkspaceRunnable wr = new IWorkspaceRunnable()
{
public void run( final IProgressMonitor monitor )
throws CoreException
{
performFinish( monitor );
}
};
final IRunnableWithProgress op = new IRunnableWithProgress()
{
public void run( final IProgressMonitor monitor )
throws InvocationTargetException, InterruptedException
{
try
{
final IWorkspace ws = ResourcesPlugin.getWorkspace();
ws.run( wr, ws.getRoot(), IWorkspace.AVOID_UPDATE, monitor );
}
catch( CoreException e )
{
throw new InvocationTargetException( e );
}
}
};
try
{
getContainer().run( true, false, op );
}
catch( InterruptedException e )
{
return false;
}
catch( InvocationTargetException e )
{
final Throwable te = e.getTargetException();
if( te instanceof CoreException )
{
IStatus st = ( (CoreException) te ).getStatus();
final String msg = st.getMessage();
if( ! ( te instanceof FacetedProjectFrameworkException ) ||
! ( (FacetedProjectFrameworkException) te ).isExpected() )
{
FacetUiPlugin.log( st );
}
final Throwable cause = st.getException();
if( cause instanceof CoreException )
{
st = ( (CoreException) cause ).getStatus();
}
ErrorDialog.openError( getShell(), Resources.errDlgTitle, msg, st );
}
else
{
throw new RuntimeException( e.getTargetException() );
}
}
return true;
}
protected void performFinish( final IProgressMonitor monitor )
throws CoreException
{
this.fpjwc.commitChanges( monitor );
}
public void syncWithPresetsModel( final Combo combo )
{
syncWithPresetsModel( this.fpjwc, combo );
}
public static void syncWithPresetsModel( final IFacetedProjectWorkingCopy fpjwc,
final Combo combo )
{
syncWithPresetsModel( fpjwc, combo, null );
}
public static void syncWithPresetsModel( final IFacetedProjectWorkingCopy fpjwc,
final Combo combo,
final IFilter<IPreset> filter )
{
final List<IPreset> sortedPresets = new ArrayList<IPreset>();
// Contents : model -> view
final IFacetedProjectListener availablePresetsChangedListener = new IFacetedProjectListener()
{
public void handleEvent( final IFacetedProjectEvent event )
{
final Runnable runnable = new Runnable()
{
public void run()
{
if( combo.isDisposed() )
{
return;
}
synchronized( sortedPresets )
{
sortedPresets.clear();
if( filter != null )
{
for( IPreset preset : fpjwc.getAvailablePresets() )
{
if( filter.check( preset ) )
{
sortedPresets.add( preset );
}
}
}
else
{
sortedPresets.addAll( fpjwc.getAvailablePresets() );
}
Collections.sort
(
sortedPresets,
new Comparator<IPreset>()
{
public int compare( final IPreset p1,
final IPreset p2 )
{
if( p1 == p2 )
{
return 0;
}
else
{
return p1.getLabel().compareTo( p2.getLabel() );
}
}
}
);
final IPreset selectedPreset = fpjwc.getSelectedPreset();
combo.removeAll();
combo.add( Resources.customPreset );
if( selectedPreset == null )
{
combo.select( 0 );
}
for( IPreset preset : sortedPresets )
{
combo.add( preset.getLabel() );
if( selectedPreset != null &&
preset.getId().equals( selectedPreset.getId() ) )
{
combo.select( combo.getItemCount() - 1 );
}
}
}
}
};
Display.getDefault().asyncExec( runnable );
}
};
fpjwc.addListener( availablePresetsChangedListener,
IFacetedProjectEvent.Type.AVAILABLE_PRESETS_CHANGED );
if( filter != null )
{
filter.addListener
(
new IFilterListener<IPreset>()
{
public void handleEvent( final IFilterEvent<IPreset> event )
{
availablePresetsChangedListener.handleEvent( null );
}
},
IFilterEvent.Type.FILTER_CHANGED
);
}
final IFacetedProjectListener selectedPresetChangedListener = new IFacetedProjectListener()
{
public void handleEvent( final IFacetedProjectEvent event )
{
final Runnable runnable = new Runnable()
{
public void run()
{
synchronized( sortedPresets )
{
final IPreset preset = fpjwc.getSelectedPreset();
final int index;
if( preset == null )
{
index = -1;
}
else
{
index = sortedPresets.indexOf( preset );
}
combo.select( index + 1 );
}
}
};
Display.getDefault().asyncExec( runnable );
}
};
fpjwc.addListener( selectedPresetChangedListener,
IFacetedProjectEvent.Type.SELECTED_PRESET_CHANGED );
// Selection : view -> model
combo.addSelectionListener
(
new SelectionAdapter()
{
public void widgetSelected( final SelectionEvent e )
{
synchronized( sortedPresets )
{
final int selection = combo.getSelectionIndex();
final String presetId;
if( selection == 0 )
{
presetId = null;
}
else
{
presetId = sortedPresets.get( selection - 1 ).getId();
}
fpjwc.setSelectedPreset( presetId );
}
}
}
);
// Trigger initial UI population.
availablePresetsChangedListener.handleEvent( null );
// Make sure to remove working copy listeners when the widget is disposed.
combo.addDisposeListener
(
new DisposeListener()
{
public void widgetDisposed( final DisposeEvent event )
{
fpjwc.removeListener( availablePresetsChangedListener );
fpjwc.removeListener( selectedPresetChangedListener );
}
}
);
}
public void setCategoryExpandedState( final ICategory category,
final boolean expanded )
{
if( this.facetsSelectionPage != null && this.facetsSelectionPage.panel != null )
{
this.facetsSelectionPage.panel.setCategoryExpandedState( category, true );
}
else
{
final Runnable action = new Runnable()
{
public void run()
{
setCategoryExpandedState( category, expanded );
}
};
this.delayedActions.add( action );
}
}
public boolean getShowFacetsSelectionPage()
{
return this.showFacetsSelectionPage;
}
public void setShowFacetsSelectionPage( final boolean showFacetsSelectionPage )
{
this.showFacetsSelectionPage = showFacetsSelectionPage;
}
public void dispose()
{
super.dispose();
for( int i = 0; i < this.facetPages.length; i++ )
{
this.pagesToDispose.addAll( this.facetPages[ i ].pages );
}
for( IWizardPage page : this.pagesToDispose )
{
page.dispose();
}
for( Runnable onDisposeAction : this.onDisposeActions )
{
try
{
onDisposeAction.run();
}
catch( Exception e )
{
FacetUiPlugin.log( e );
}
}
if( this.disposeWorkingCopy )
{
this.fpjwc.dispose();
}
}
private static final class FacetPages
{
public Action action;
public List<IFacetWizardPage> pages;
}
private void handleSelectedFacetsChangedEvent()
{
// Don't do anything until there are no more validation errors.
if( this.fpjwc.validate().getSeverity() == IStatus.ERROR)
{
return;
}
// Get the set of actions and sort them.
final Set<IProjectFacetVersion> base = getBaseFacets();
final Set<Action> actions = getFacetedProjectWorkingCopy().getProjectFacetActions();
final List<Action> sortedActions = new ArrayList<Action>( actions );
ProjectFacetsManager.sort( base, sortedActions );
// Recalculate the sequence of wizard pages.
final List<FacetPages> newFacetPages = new ArrayList<FacetPages>();
final boolean[] markers = new boolean[ this.facetPages.length ];
boolean changed = false;
for( Action action : sortedActions )
{
final IProjectFacetVersion fv = action.getProjectFacetVersion();
FacetPages fp = findFacetPages( action, markers );
if( fp == null )
{
final IActionDefinition actiondef;
try
{
actiondef = fv.getActionDefinition( base, action.getType() );
}
catch( CoreException e )
{
FacetUiPlugin.log( e );
continue;
}
final List<IFacetWizardPage> pages
= ProjectFacetsUiManager.getWizardPages( actiondef.getId() );
if( ! pages.isEmpty() )
{
fp = new FacetPages();
fp.action = action;
fp.pages = pages;
for( IFacetWizardPage page : fp.pages )
{
page.setWizard( this );
page.setWizardContext( this.context );
page.setConfig( action.getConfig() );
if( page.getControl() == null )
{
page.createControl( this.pageContainer );
page.getControl().setVisible( false );
}
}
changed = true;
}
}
if( fp != null )
{
newFacetPages.add( fp );
}
}
for( int i = 0; i < this.facetPages.length; i++ )
{
if( ! markers[ i ] )
{
for( IFacetWizardPage page : this.facetPages[ i ].pages )
{
page.setWizard( null );
this.pagesToDispose.add( page );
}
changed = true;
}
}
if( changed )
{
this.facetPages = new FacetPages[ newFacetPages.size() ];
newFacetPages.toArray( this.facetPages );
this.pageContainer.layout( true, true );
final IWizardContainer wizardContainer = getContainer();
if( wizardContainer.getCurrentPage() != null )
{
wizardContainer.updateButtons();
}
}
}
private FacetPages findFacetPages( final Action action,
final boolean[] markers )
{
for( int i = 0; i < this.facetPages.length; i++ )
{
final FacetPages fp = this.facetPages[ i ];
if( fp.action == action )
{
markers[ i ] = true;
return fp;
}
}
return null;
}
private Set<IProjectFacetVersion> getBaseFacets()
{
final IFacetedProject fproj = this.fpjwc.getFacetedProject();
if( fproj == null )
{
return Collections.emptySet();
}
else
{
return fproj.getProjectFacets();
}
}
private void executeDelayedActions()
{
for( Runnable r : this.delayedActions )
{
try
{
r.run();
}
catch( Exception e )
{
FacetUiPlugin.log( e );
}
}
}
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
private final class WizardContext
implements IWizardContext
{
public String getProjectName()
{
return getFacetedProjectWorkingCopy().getProjectName();
}
public Set<IProjectFacetVersion> getSelectedProjectFacets()
{
return getFacetedProjectWorkingCopy().getProjectFacets();
}
public boolean isProjectFacetSelected( final IProjectFacetVersion fv )
{
return getSelectedProjectFacets().contains( fv );
}
public Set<Action> getActions()
{
return getFacetedProjectWorkingCopy().getProjectFacetActions();
}
public Action getAction( final Action.Type type,
final IProjectFacetVersion f )
{
for( Action action : getActions() )
{
if( action.getType() == type && action.getProjectFacetVersion() == f )
{
return action;
}
}
return null;
}
public Object getConfig( final IProjectFacetVersion fv,
final Action.Type type,
final String pjname )
{
final Action action = getAction( type, fv );
return action != null ? action.getConfig() : null;
}
}
private static final class Resources
extends NLS
{
public static String wizardTitle;
public static String errDlgTitle;
public static String customPreset;
static
{
initializeMessages( ModifyFacetedProjectWizard.class.getName(),
Resources.class );
}
}
}