blob: aaf35a7c69902a289c340cac1e90f6b6bf9d5404 [file] [log] [blame]
package org.eclipse.team.internal.ccvs.ui.wizards;
/*
* (c) Copyright IBM Corp. 2000, 2002.
* All Rights Reserved.
*/
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
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.swt.custom.BusyIndicator;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSStatus;
import org.eclipse.team.internal.ccvs.core.CVSTeamProvider;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
import org.eclipse.team.internal.ccvs.ui.Policy;
/**
* A wizard for changing the keyword substitution mode of files.
*
* 1. Ask the user select to select the desired keyword substitution mode.
* 2. Compute the set of possibly affected resources
* 3. If the affected resources include existing committed files, warn the user
* and provide an option to include them in the operation anyways.
* 4. If the affected resources include dirty files, warn the user and provide
* an option to include them in the operation anyways.
* 5. Perform the operation on Finish.
*/
public class KSubstWizard extends Wizard {
private KSubstOption defaultKSubst;
private final IResource[] resources;
private final int depth;
private List changeList = null;
private KSubstOption changeOption = null;
private KSubstWizardSelectionPage mainPage;
private KSubstWizardSummaryPage summaryPage;
private KSubstWizardSharedFilesPage sharedFilesPage;
private KSubstWizardDirtyFilesPage dirtyFilesPage;
public class KSubstChangeElement {
public static final int ADDED_FILE = 1;
public static final int CHANGED_FILE = 2;
public static final int UNCHANGED_FILE = 4;
private IFile file;
private int classification;
private boolean excluded;
private KSubstOption fromKSubst;
private KSubstOption toKSubst;
private KSubstChangeElement(IFile file, int classification, boolean excluded, KSubstOption fromKSubst, KSubstOption toKSubst) {
this.file = file;
this.classification = classification;
this.excluded = excluded;
this.fromKSubst = fromKSubst;
this.toKSubst = toKSubst;
}
public boolean matchesFilter(int filter) {
return (classification & filter) != 0;
}
public boolean isExcluded() {
return excluded;
}
public void setExcluded(boolean excluded) {
this.excluded = excluded;
}
public boolean isNewKSubstMode() {
return ! fromKSubst.equals(toKSubst);
}
public void setKSubst(KSubstOption toKSubst) {
this.toKSubst = toKSubst;
}
public KSubstOption getKSubst() {
return toKSubst;
}
public IFile getFile() {
return file;
}
}
/**
* Creates a wizard to set the keyword substitution mode for the specified resources.
*
* @param resources the resources to alter
* @param depth the recursion depth
* @param defaultOption the keyword substitution option to select by default
*/
public KSubstWizard(IResource[] resources, int depth, KSubstOption defaultOption) {
super();
this.defaultKSubst = defaultOption;
this.resources = resources;
this.depth = depth;
setWindowTitle(Policy.bind("KSubstWizard.title")); //$NON-NLS-1$
}
/**
* Returns the keyword substitution option that was selected at the time
* the Finish button was pressed.
*/
public KSubstOption getKSubstOption() {
return defaultKSubst;
}
public void addPages() {
// add main page
String pageTitle = Policy.bind("KSubstWizardSelectionPage.pageTitle"); //$NON-NLS-1$
String pageDescription = Policy.bind("KSubstWizardSelectionPage.pageDescription"); //$NON-NLS-1$
mainPage = new KSubstWizardSelectionPage(pageTitle, defaultKSubst);
mainPage.setDescription(pageDescription);
mainPage.setTitle(pageTitle);
addPage(mainPage);
// add summary page
pageTitle = Policy.bind("KSubstWizardSummaryPage.pageTitle"); //$NON-NLS-1$
pageDescription = Policy.bind("KSubstWizardSummaryPage.pageDescription"); //$NON-NLS-1$
summaryPage = new KSubstWizardSummaryPage(pageTitle, false);
summaryPage.setDescription(pageDescription);
summaryPage.setTitle(pageTitle);
addPage(summaryPage);
// add shared files warning page
pageTitle = Policy.bind("KSubstWizardSharedFilesPage.pageTitle"); //$NON-NLS-1$
pageDescription = Policy.bind("KSubstWizardSharedFilesPage.pageDescription"); //$NON-NLS-1$
sharedFilesPage = new KSubstWizardSharedFilesPage(pageTitle, false);
sharedFilesPage.setDescription(pageDescription);
sharedFilesPage.setTitle(pageTitle);
addPage(sharedFilesPage);
// add changed files warning page
pageTitle = Policy.bind("KSubstWizardDirtyFilesPage.pageTitle"); //$NON-NLS-1$
pageDescription = Policy.bind("KSubstWizardDirtyFilesPage.pageDescription"); //$NON-NLS-1$
dirtyFilesPage = new KSubstWizardDirtyFilesPage(pageTitle, false);
dirtyFilesPage.setDescription(pageDescription);
dirtyFilesPage.setTitle(pageTitle);
addPage(dirtyFilesPage);
}
public IWizardPage getNextPage(IWizardPage page) {
if (page == mainPage) {
if (prepareSharedFilesPage()) return sharedFilesPage;
} else if (page == sharedFilesPage) {
if (sharedFilesPage.includeSharedFiles() && prepareDirtyFilesPage()) return dirtyFilesPage;
} else if (page == summaryPage) {
return null;
}
prepareSummaryPage();
return summaryPage;
}
public IWizardPage getPreviousPage(IWizardPage page) {
if (page == summaryPage) {
if (sharedFilesPage.includeSharedFiles() && prepareDirtyFilesPage()) return dirtyFilesPage;
if (prepareSharedFilesPage()) return sharedFilesPage;
return mainPage;
} else if (page == dirtyFilesPage) {
if (prepareSharedFilesPage()) return sharedFilesPage;
return mainPage;
} else if (page == sharedFilesPage) {
return mainPage;
}
return null;
}
/* (Non-javadoc)
* Method declared on IWizard.
*/
public boolean needsProgressMonitor() {
return true;
}
/* (Non-javadoc)
* Method declared on IWizard.
*/
public boolean needsPreviousAndNextButtons() {
return true;
}
/* (Non-javadoc)
* Method declared on IWizard.
*/
public boolean performFinish() {
try {
defaultKSubst = mainPage.getKSubstOption();
final List messages = new ArrayList();
getContainer().run(false /*fork*/, true /*cancelable*/, new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
monitor.beginTask("", 10000); //$NON-NLS-1$
monitor.setTaskName(Policy.bind("KSubstWizard.working")); //$NON-NLS-1$
computeChangeList(mainPage.getKSubstOption());
Map table = getProviderMapping();
int workPerProvider = 10000 / (table.size() + 1);
monitor.worked(workPerProvider);
for (Iterator it = table.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
CVSTeamProvider provider = (CVSTeamProvider) entry.getKey();
Map providerFiles = (Map) entry.getValue();
IStatus status = provider.setKeywordSubstitution(providerFiles,
Policy.subMonitorFor(monitor, workPerProvider));
if (status.getCode() != CVSStatus.OK) {
messages.add(status);
}
}
} catch (TeamException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
}
});
// Check for any status messages and display them
if ( ! messages.isEmpty()) {
boolean error = false;
MultiStatus combinedStatus = new MultiStatus(CVSUIPlugin.ID, 0,
Policy.bind("KSubstWizard.problemsMessage"), null); //$NON-NLS-1$
for (int i = 0; i < messages.size(); i++) {
IStatus status = (IStatus)messages.get(i);
if (status.getSeverity() == IStatus.ERROR || status.getCode() == CVSStatus.SERVER_ERROR) {
error = true;
}
combinedStatus.merge(status);
}
String message = null;
IStatus statusToDisplay;
if (combinedStatus.getChildren().length == 1) {
message = combinedStatus.getMessage();
statusToDisplay = combinedStatus.getChildren()[0];
} else {
statusToDisplay = combinedStatus;
}
String title;
if (error) {
title = Policy.bind("KSubstWizard.errorTitle"); //$NON-NLS-1$
} else {
title = Policy.bind("KSubstWizard.warningTitle"); //$NON-NLS-1$
}
ErrorDialog.openError(getShell(), title, message, statusToDisplay);
}
return true;
} catch (InterruptedException e1) {
return true;
} catch (InvocationTargetException e2) {
if (e2.getTargetException() instanceof CoreException) {
CoreException e = (CoreException) e2.getTargetException();
ErrorDialog.openError(getShell(), Policy.bind("KSubstWizard.problemsMessage"), null, e.getStatus()); //$NON-NLS-1$
return false;
} else {
Throwable target = e2.getTargetException();
if (target instanceof RuntimeException) {
throw (RuntimeException) target;
}
if (target instanceof Error) {
throw (Error) target;
}
}
return true;
}
}
private boolean prepareDirtyFilesPage() {
BusyIndicator.showWhile(getContainer().getShell().getDisplay(), new Runnable() {
public void run() {
computeChangeList(mainPage.getKSubstOption());
dirtyFilesPage.setChangeList(changeList);
}
});
return ! dirtyFilesPage.isListEmpty();
}
private boolean prepareSharedFilesPage() {
BusyIndicator.showWhile(getContainer().getShell().getDisplay(), new Runnable() {
public void run() {
computeChangeList(mainPage.getKSubstOption());
sharedFilesPage.setChangeList(changeList);
}
});
return ! sharedFilesPage.isListEmpty();
}
private void prepareSummaryPage() {
BusyIndicator.showWhile(getContainer().getShell().getDisplay(), new Runnable() {
public void run() {
computeChangeList(mainPage.getKSubstOption());
summaryPage.setChangeList(changeList, getFilters());
}
});
}
/**
* @param ksubst the desired keyword substitution mode, if null chooses for each file:
* <code>KSubstOption.fromPattern(fileName).isBinary() ? KSUBST_BINARY : KSUBST_TEXT</code>
*/
private void computeChangeList(final KSubstOption ksubst) {
if (changeList != null) {
if (changeOption == ksubst) return;
changeList.clear();
} else {
changeList = new ArrayList();
}
changeOption = ksubst;
// recurse over all specified resources, considering each exactly once
final Set seen = new HashSet();
for (int i = 0; i < resources.length; i++) {
final IResource currentResource = resources[i];
try {
currentResource.accept(new IResourceVisitor() {
public boolean visit(IResource resource) throws CoreException {
try {
if (resource.getType() == IResource.FILE && resource.exists() && ! seen.contains(resource)) {
seen.add(resource);
IFile file = (IFile) resource;
ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(file);
if (cvsFile.isManaged()) {
ResourceSyncInfo info = cvsFile.getSyncInfo();
// classify the change
final int classification;
if (info.isAdded()) {
classification = KSubstChangeElement.ADDED_FILE;
} else if (info.isDeleted()) {
return true;
} else if (cvsFile.isModified()) {
classification = KSubstChangeElement.CHANGED_FILE;
} else {
classification = KSubstChangeElement.UNCHANGED_FILE;
}
// determine the to/from substitution modes
KSubstOption fromKSubst = info.getKeywordMode();
KSubstOption toKSubst = ksubst;
if (ksubst == null) {
toKSubst = KSubstOption.fromFile(file);
}
changeList.add(new KSubstChangeElement(file, classification, false, fromKSubst, toKSubst));
}
}
} catch (TeamException e) {
throw new CoreException(e.getStatus());
}
// always return true and let the depth determine if children are visited
return true;
}
}, depth, false);
} catch (CoreException e) {
ErrorDialog.openError(getShell(), Policy.bind("KSubstWizard.problemsMessage"), null, e.getStatus()); //$NON-NLS-1$
}
}
}
private int getFilters() {
return KSubstChangeElement.ADDED_FILE |
(sharedFilesPage.includeSharedFiles() ? KSubstChangeElement.UNCHANGED_FILE |
(dirtyFilesPage.includeDirtyFiles() ? KSubstChangeElement.CHANGED_FILE : 0) : 0);
}
private Map getProviderMapping() {
Map table = new HashMap();
int filter = getFilters();
for (Iterator it = changeList.iterator(); it.hasNext();) {
KSubstChangeElement change = (KSubstChangeElement) it.next();
if (! change.isExcluded() && change.isNewKSubstMode() && change.matchesFilter(filter)) {
// classify file according to its provider
IFile file = change.getFile();
RepositoryProvider provider = RepositoryProvider.getProvider(file.getProject(), CVSProviderPlugin.getTypeId());
Map providerMap = (Map) table.get(provider);
if (providerMap == null) {
providerMap = new HashMap();
table.put(provider, providerMap);
}
providerMap.put(file, change.toKSubst);
}
}
return table;
}
}