blob: d94b4948bc22d17b26fccf81b3840900ab8cd383 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui.actions;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import org.eclipse.core.resources.*;
import org.eclipse.core.resources.mapping.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.mapping.ISynchronizationContext;
import org.eclipse.team.core.subscribers.Subscriber;
import org.eclipse.team.core.subscribers.SubscriberScopeManager;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.ui.*;
import org.eclipse.team.internal.ccvs.ui.mappings.WorkspaceModelParticipant;
import org.eclipse.team.internal.ccvs.ui.mappings.WorkspaceSubscriberContext;
import org.eclipse.team.internal.ccvs.ui.subscriber.WorkspaceSynchronizeParticipant;
import org.eclipse.team.internal.ui.Utils;
import org.eclipse.team.internal.ui.synchronize.actions.OpenInCompareAction;
import org.eclipse.team.ui.TeamUI;
import org.eclipse.team.ui.synchronize.*;
import org.eclipse.ui.*;
/**
* Action to initiate a CVS workspace synchronize
*/
public class SyncAction extends WorkspaceTraversalAction {
@Override
public void execute(IAction action) throws InvocationTargetException {
// First, see if there is a single file selected
if (isOpenEditorForSingleFile()) {
IFile file = getSelectedFile();
if (file != null && isOKToShowSingleFile(file)) {
showSingleFileComparison(getShell(), CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), file, getTargetPage());
return;
}
}
if (isShowModelSync()) {
ResourceMapping[] mappings = getCVSResourceMappings();
if (mappings.length == 0)
return;
SubscriberScopeManager manager = WorkspaceSubscriberContext.createWorkspaceScopeManager(mappings, true, CommitAction.isIncludeChangeSets(getShell(), CVSUIMessages.SyncAction_1));
WorkspaceSubscriberContext context = WorkspaceSubscriberContext.createContext(manager, ISynchronizationContext.THREE_WAY);
WorkspaceModelParticipant participant = new WorkspaceModelParticipant(context);
TeamUI.getSynchronizeManager().addSynchronizeParticipants(new ISynchronizeParticipant[] {participant});
participant.run(getTargetPart());
} else {
IResource[] resources = getResourcesToCompare(getWorkspaceSubscriber());
if (resources == null || resources.length == 0) return;
// First check if there is an existing matching participant
WorkspaceSynchronizeParticipant participant = (WorkspaceSynchronizeParticipant)SubscriberParticipant.getMatchingParticipant(WorkspaceSynchronizeParticipant.ID, resources);
// If there isn't, create one and add to the manager
if (participant == null) {
ISynchronizeScope scope;
if (includesAllCVSProjects(resources)) {
scope = new WorkspaceScope();
} else {
IWorkingSet[] sets = getSelectedWorkingSets();
if (sets != null) {
scope = new WorkingSetScope(sets);
} else {
scope = new ResourceScope(resources);
}
}
participant = new WorkspaceSynchronizeParticipant(scope);
TeamUI.getSynchronizeManager().addSynchronizeParticipants(new ISynchronizeParticipant[] {participant});
}
participant.refresh(resources, getTargetPart().getSite());
}
}
private static boolean isShowModelSync() {
return CVSUIPlugin.getPlugin().getPreferenceStore().getBoolean(ICVSUIConstants.PREF_ENABLE_MODEL_SYNC);
}
private static boolean isOpenEditorForSingleFile() {
return CVSUIPlugin.getPlugin().getPreferenceStore().getBoolean(ICVSUIConstants.PREF_OPEN_COMPARE_EDITOR_FOR_SINGLE_FILE);
}
private IWorkingSet[] getSelectedWorkingSets() {
ResourceMapping[] mappings = getCVSResourceMappings();
List<IWorkingSet> sets = new ArrayList<>();
for (int i = 0; i < mappings.length; i++) {
ResourceMapping mapping = mappings[i];
if (mapping.getModelObject() instanceof IWorkingSet) {
IWorkingSet set = (IWorkingSet) mapping.getModelObject();
sets.add(set);
} else {
return null;
}
}
if (sets.isEmpty())
return null;
return sets.toArray(new IWorkingSet[sets.size()]);
}
private boolean includesAllCVSProjects(IResource[] resources) {
// First, make sure all the selected thinsg are projects
for (int i = 0; i < resources.length; i++) {
IResource resource = resources[i];
if (resource.getType() != IResource.PROJECT)
return false;
}
IProject[] cvsProjects = getAllCVSProjects();
return cvsProjects.length == resources.length;
}
private IProject[] getAllCVSProjects() {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
Set<IProject> cvsProjects = new HashSet<>();
for (int i = 0; i < projects.length; i++) {
IProject project = projects[i];
if (RepositoryProvider.isShared(project) && RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId()) != null) {
cvsProjects.add(project);
}
}
return cvsProjects.toArray(new IProject[cvsProjects.size()]);
}
/**
* Return whether it is OK to open the selected file directly in a compare editor.
* It is not OK to show the single file if the file is part of a logical model element
* that spans files.
* @param file the file
* @return whether it is OK to open the selected file directly in a compare editor
*/
public static boolean isOKToShowSingleFile(IFile file) {
if (!isShowModelSync())
return true;
IModelProviderDescriptor[] descriptors = ModelProvider.getModelProviderDescriptors();
for (int i = 0; i < descriptors.length; i++) {
IModelProviderDescriptor descriptor = descriptors[i];
try {
IResource[] resources = descriptor.getMatchingResources(new IResource[] { file });
if (resources.length > 0) {
ModelProvider provider = descriptor.getModelProvider();
// Technically, we should us the remote context to determine if multiple resources are involved.
// However, we do not have a progress monitor so we'll just use a local context since,
// it is unlikely that a model element will consist of one file locally but multiple files remotely
ResourceMapping[] mappings = provider.getMappings(file, ResourceMappingContext.LOCAL_CONTEXT, null);
for (int j = 0; j < mappings.length; j++) {
ResourceMapping mapping = mappings[j];
ResourceTraversal[] traversals = mapping.getTraversals(ResourceMappingContext.LOCAL_CONTEXT, null);
for (int k = 0; k < traversals.length; k++) {
ResourceTraversal traversal = traversals[k];
IResource[] tResources = traversal.getResources();
for (int index = 0; index < tResources.length; index++) {
IResource tr = tResources[index];
if (!tr.equals(file))
return false;
}
}
}
}
} catch (CoreException e) {
CVSUIPlugin.log(e);
}
}
return true;
}
/**
* Refresh the subscriber directly and show the resulting synchronization state in a compare editor. If there
* is no difference the user is prompted.
*
* @param resources the file to refresh and compare
*/
public static void showSingleFileComparison(final Shell shell, final Subscriber subscriber, final IResource resource, final IWorkbenchPage page) {
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(monitor -> {
try {
subscriber.refresh(new IResource[] { resource }, IResource.DEPTH_ZERO, monitor);
} catch (TeamException e) {
throw new InvocationTargetException(e);
}
});
final SyncInfo info = subscriber.getSyncInfo(resource);
if (info == null) return;
shell.getDisplay().syncExec(() -> {
if (info.getKind() == SyncInfo.IN_SYNC) {
MessageDialog.openInformation(shell, CVSUIMessages.SyncAction_noChangesTitle,
CVSUIMessages.SyncAction_noChangesMessage); //
} else {
SyncInfoCompareInput input = new SyncInfoCompareInput(subscriber.getName(), info);
OpenInCompareAction.openCompareEditor(input, page);
}
});
} catch (InvocationTargetException e) {
Utils.handle(e);
} catch (InterruptedException e) {
} catch (TeamException e) {
Utils.handle(e);
}
}
public static boolean isSingleFile(IResource[] resources) {
return resources.length == 1 && resources[0].getType() == IResource.FILE;
}
/**
* Enable for resources that are managed (using super) or whose parent is a
* CVS folder.
*
* @see org.eclipse.team.internal.ccvs.ui.actions.WorkspaceAction#isEnabledForCVSResource(org.eclipse.team.internal.ccvs.core.ICVSResource)
*/
@Override
protected boolean isEnabledForCVSResource(ICVSResource cvsResource) throws CVSException {
return (super.isEnabledForCVSResource(cvsResource) || (cvsResource.getParent().isCVSFolder() && !cvsResource.isIgnored()));
}
@Override
public String getId() {
return ICVSUIConstants.CMD_SYNCHRONIZE;
}
@Override
public boolean isEnabled() {
if(super.isEnabled()){
return true;
}
IWorkingSet[] sets = getSelectedWorkingSets();
// empty selection will not be considered
if(sets == null || sets.length == 0){
return false;
}
Set projects = getProjects(sets);
boolean existsProjectToSynchronize = false;
for (Iterator it = projects.iterator(); it.hasNext();) {
IProject project = (IProject) it.next();
RepositoryProvider provider = RepositoryProvider.getProvider(project);
if(provider != null){
existsProjectToSynchronize = true;
//we handle only CVS repositories
if(!CVSProviderPlugin.getTypeId().equals(provider.getID())){
return false;
}
}
}
return existsProjectToSynchronize;
}
private Set getProjects(IWorkingSet[] sets) {
Set<IProject> projects = new HashSet<>();
if(sets == null)
return projects;
for (int i = 0; i < sets.length; i++) {
IAdaptable ad[] = sets[i].getElements();
if (ad != null) {
for (int j = 0; j < ad.length; j++) {
IResource resource = ad[j]
.getAdapter(IResource.class);
if (resource != null) {
projects.add(resource.getProject());
}
}
}
}
return projects;
}
}