blob: 1fe7e25bc6a134a7478ca3c3c5dbcafcbdce144a [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2005-2007 BEA Systems, Inc.
* 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
******************************************************************************/
package org.eclipse.wst.common.project.facet.ui;
import static org.eclipse.wst.common.project.facet.core.internal.util.ProgressMonitorUtil.beginTask;
import static org.eclipse.wst.common.project.facet.core.internal.util.ProgressMonitorUtil.done;
import static org.eclipse.wst.common.project.facet.core.internal.util.ProgressMonitorUtil.subTask;
import static org.eclipse.wst.common.project.facet.core.internal.util.ProgressMonitorUtil.submon;
import static org.eclipse.wst.common.project.facet.core.internal.util.ProgressMonitorUtil.worked;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
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.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
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.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.IFacetedProject.Action.Type;
import org.eclipse.wst.common.project.facet.core.runtime.IRuntime;
import org.eclipse.wst.common.project.facet.ui.internal.ChangeTargetedRuntimesDataModel;
import org.eclipse.wst.common.project.facet.ui.internal.FacetUiPlugin;
import org.eclipse.wst.common.project.facet.ui.internal.FacetsSelectionPage;
import org.eclipse.wst.common.project.facet.ui.internal.ModifyFacetedProjectDataModel;
/**
* @author <a href="mailto:kosta@bea.com">Konstantin Komissarchik</a>
*/
public class ModifyFacetedProjectWizard
extends Wizard
{
protected IFacetedProject fproj;
private final WizardContext context = new WizardContext();
protected final FacetsSelectionPage facetsSelectionPage;
private FacetPages[] facetPages = new FacetPages[ 0 ];
private Composite pageContainer;
private final List<IWizardPage> pagesToDispose = new ArrayList<IWizardPage>();
private final ModifyFacetedProjectDataModel model;
private final List<Runnable> delayedActions;
public ModifyFacetedProjectWizard( final IFacetedProject fproj )
{
this.model = new ModifyFacetedProjectDataModel();
this.delayedActions = new ArrayList<Runnable>();;
this.fproj = fproj;
Set<IProjectFacetVersion> base = null;
if( this.fproj != null )
{
base = this.fproj.getProjectFacets();
final ChangeTargetedRuntimesDataModel rdm
= this.model.getTargetedRuntimesDataModel();
rdm.setTargetedRuntimes( this.fproj.getTargetedRuntimes() );
rdm.setPrimaryRuntime( this.fproj.getPrimaryRuntime() );
}
this.facetsSelectionPage
= new FacetsSelectionPage( this.context, base, this.model );
setNeedsProgressMonitor( true );
setForcePreviousAndNextButtons( true );
setWindowTitle( Resources.wizardTitle );
}
public final ModifyFacetedProjectDataModel getModel()
{
return this.model;
}
public void addPages()
{
if( this.fproj != null )
{
this.facetsSelectionPage.setInitialSelection( this.fproj.getProjectFacets() );
this.facetsSelectionPage.setFixedProjectFacets( this.fproj.getFixedProjectFacets());
}
this.facetsSelectionPage.addSelectedFacetsChangedListener
(
new Listener()
{
public void handleEvent( final Event event )
{
handleSelectedFacetsChangedEvent();
}
}
);
addPage( this.facetsSelectionPage );
}
public int getPageCount()
{
return getPages().length;
}
public IWizardPage[] getPages()
{
final List<IWizardPage> list = new ArrayList<IWizardPage>();
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.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 )
{
final IStatus st = ( (CoreException) te ).getStatus();
ErrorDialog.openError( getShell(), Resources.errDlgTitle,
st.getMessage(), st );
FacetUiPlugin.log( st );
}
else
{
throw new RuntimeException( e.getTargetException() );
}
}
return true;
}
protected void performFinish( final IProgressMonitor monitor )
throws CoreException
{
beginTask( monitor, "", 20 ); //$NON-NLS-1$
try
{
// Figure out whether we can set runtimes before applying facet actions. This is better
// for performance reasons, but may not work if the project contains facets that are
// not supported by the new runtime. You can get into this situation if the user tries
// to simultaneously uninstall a facet and select a different runtime. The fallback
// solution for this situation is to set the targeted runtimes to an empty list first,
// then apply the facet actions, and then set the targeted runtimes to the new list.
// This is more drastic than necessary in all situations, but it is not clear that
// implementing additional optimizations is necessary either.
final ChangeTargetedRuntimesDataModel rdm = this.model.getTargetedRuntimesDataModel();
boolean canSetRuntimesFirst = true;
for( IProjectFacetVersion fv : this.fproj.getProjectFacets() )
{
for( IRuntime r : rdm.getTargetedRuntimes() )
{
if( ! r.supports( fv ) )
{
canSetRuntimesFirst = false;
break;
}
}
if( ! canSetRuntimesFirst )
{
break;
}
}
subTask( monitor, Resources.taskConfiguringRuntimes );
if( canSetRuntimesFirst )
{
this.fproj.setTargetedRuntimes( rdm.getTargetedRuntimes(), submon( monitor, 2 ) );
if( rdm.getPrimaryRuntime() != null )
{
this.fproj.setPrimaryRuntime( rdm.getPrimaryRuntime(), submon( monitor, 2 ) );
}
else
{
worked( monitor, 2 );
}
}
else
{
final Set<IRuntime> emptySet = Collections.emptySet();
this.fproj.setTargetedRuntimes( emptySet, submon( monitor, 2 ) );
}
this.fproj.modify( this.facetsSelectionPage.getActions(), submon( monitor, 16 ) );
if( ! canSetRuntimesFirst )
{
subTask( monitor, Resources.taskConfiguringRuntimes );
this.fproj.setTargetedRuntimes( rdm.getTargetedRuntimes(), submon( monitor, 1 ) );
if( rdm.getPrimaryRuntime() != null )
{
this.fproj.setPrimaryRuntime( rdm.getPrimaryRuntime(), submon( monitor, 1 ) );
}
else
{
worked( monitor, 1 );
}
}
}
finally
{
done( monitor );
}
}
public String getProjectName()
{
return this.fproj.getProject().getName();
}
public Object getConfig(IProjectFacetVersion fv, Type type, String pjname) throws CoreException{
return null;
}
public void syncWithPresetsModel( final Combo combo )
{
this.facetsSelectionPage.syncWithPresetsModel( combo );
}
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 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();
}
this.model.dispose();
}
private static final class FacetPages
{
public Action action;
public List<IFacetWizardPage> pages;
}
private void handleSelectedFacetsChangedEvent()
{
// Don't do anything until the facet selection page does not have any
// errors.
if( ! this.facetsSelectionPage.isPageComplete() )
{
return;
}
// Get the set of actions and sort them.
final Set<IProjectFacetVersion> base = getBaseFacets();
final Set<Action> actions = this.facetsSelectionPage.getActions();
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 );
}
}
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()
{
if( this.fproj == null )
{
return Collections.emptySet();
}
else
{
return this.fproj.getProjectFacets();
}
}
private void executeDelayedActions()
{
for( Runnable r : this.delayedActions )
{
try
{
r.run();
}
catch( Exception e )
{
FacetUiPlugin.log( e );
}
}
}
/**
* @author <a href="mailto:kosta@bea.com">Konstantin Komissarchik</a>
*/
private final class WizardContext
implements IWizardContext
{
public String getProjectName()
{
return ModifyFacetedProjectWizard.this.getProjectName();
}
public Set<IProjectFacetVersion> getSelectedProjectFacets()
{
return ModifyFacetedProjectWizard.this.facetsSelectionPage.getSelectedProjectFacets();
}
public boolean isProjectFacetSelected( final IProjectFacetVersion fv )
{
return getSelectedProjectFacets().contains( fv );
}
public Set<Action> getActions()
{
final FacetsSelectionPage page
= ModifyFacetedProjectWizard.this.facetsSelectionPage;
return page.getActions();
}
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(IProjectFacetVersion fv, Type type, String pjname) throws CoreException {
Object config = ModifyFacetedProjectWizard.this.getConfig(fv, type, pjname);
if (null == config) {
final Set<IProjectFacetVersion> base = getBaseFacets();
final IActionDefinition def = fv.getActionDefinition( base, type );
config = def.createConfigObject( fv, pjname );
}
return config;
}
}
private static final class Resources
extends NLS
{
public static String wizardTitle;
public static String errDlgTitle;
public static String taskConfiguringRuntimes;
static
{
initializeMessages( ModifyFacetedProjectWizard.class.getName(),
Resources.class );
}
}
}