Skip to main content
summaryrefslogtreecommitdiffstats
blob: f7b8e9cf7c9cecf535de84b84441db47dd790ab7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*******************************************************************************
 * Copyright (c) 2000, 2007 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.team.ui.synchronize;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareUI;
import org.eclipse.core.resources.mapping.RemoteResourceMappingContext;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.*;
import org.eclipse.team.core.mapping.ISynchronizationContext;
import org.eclipse.team.core.mapping.ISynchronizationScopeManager;
import org.eclipse.team.core.mapping.provider.SynchronizationContext;
import org.eclipse.team.internal.ui.TeamUIMessages;
import org.eclipse.team.ui.TeamUI;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.progress.WorkbenchJob;

/**
 * A model merge operation that uses a participant to preview the changes
 * in either a dialog or the Synchronize view.
 * 
 * @since 3.2
 */
public abstract class ModelParticipantMergeOperation extends ModelMergeOperation {
	
	/**
	 * Status code that can be returned from the {@link #performMerge(IProgressMonitor)}
	 * method to indicate that a subclass would like to force a preview of the merge.
	 * The message of such a status should be ignored.
	 */
	public static final int REQUEST_PREVIEW = 1024;

	private ModelSynchronizeParticipant participant;
	private boolean ownsParticipant = true;

	private boolean sentToSyncView;
	
	private static final Object PARTICIPANT_MERGE_FAMILY = new Object();
	
	/**
	 * Create a merge participant operation for the scope of the given manager.
	 * @param part the workbench part from which the merge was launched or <code>null</code>
	 * @param manager the scope manager
	 */
	protected ModelParticipantMergeOperation(IWorkbenchPart part, ISynchronizationScopeManager manager) {
		super(part, manager);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.team.ui.operations.ModelMergeOperation#initializeContext(org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected void initializeContext(IProgressMonitor monitor) throws CoreException {
		if (participant == null) {
			participant = createParticipant();
			if (isPreviewRequested() && !isPreviewInDialog()) {
				// Put the participant into the sync view right away since a preview is requested
				handlePreviewRequest();
				sentToSyncView = true;
			}
			participant.getContext().refresh(getScope().getTraversals(), 
					RemoteResourceMappingContext.FILE_CONTENTS_REQUIRED, monitor);
			// Only wait if we are not going to preview or we are previewing in a dialog
			if (!sentToSyncView)
				try {
					Job.getJobManager().join(participant.getContext(), monitor);
				} catch (InterruptedException e) {
					// Ignore
				}
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.ui.operations.ModelMergeOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
		try {
			super.execute(monitor);
		} finally {
			if (ownsParticipant && participant != null)
				participant.dispose();
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.ui.mapping.ModelMergeOperation#executeMerge(org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected void executeMerge(IProgressMonitor monitor) throws CoreException {
		if (!sentToSyncView)
			super.executeMerge(monitor);
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.ui.operations.ModelMergeOperation#handlePreviewRequest()
	 */
	protected void handlePreviewRequest() {
		Job job = new WorkbenchJob(getJobName()) {
			public IStatus runInUIThread(IProgressMonitor monitor) {
				if (isPreviewInDialog()) {
					CompareConfiguration cc = new CompareConfiguration();
					ISynchronizePageConfiguration pageConfiguration = participant.createPageConfiguration();
					// Restrict preview page to only support incoming and conflict modes
					if (pageConfiguration.getComparisonType() == ISynchronizePageConfiguration.THREE_WAY) {
						pageConfiguration.setSupportedModes(ISynchronizePageConfiguration.INCOMING_MODE | ISynchronizePageConfiguration.CONFLICTING_MODE);
						pageConfiguration.setMode(ISynchronizePageConfiguration.INCOMING_MODE);
					}
					ParticipantPageCompareEditorInput input = new ParticipantPageCompareEditorInput(cc, pageConfiguration, participant);
					CompareUI.openCompareDialog(input);
				} else {				
					ISynchronizeManager mgr = TeamUI.getSynchronizeManager();
					ISynchronizeView view = mgr.showSynchronizeViewInActivePage();
					mgr.addSynchronizeParticipants(new ISynchronizeParticipant[] {participant});
					view.display(participant);
					Object adapted = view.getSite().getAdapter(IWorkbenchSiteProgressService.class);
					if (adapted instanceof IWorkbenchSiteProgressService) {
						IWorkbenchSiteProgressService siteProgress = (IWorkbenchSiteProgressService) adapted;
						siteProgress.showBusyForFamily(PARTICIPANT_MERGE_FAMILY);
					}
				}
				return Status.OK_STATUS;
			}
		};
		job.addJobChangeListener(new JobChangeAdapter() {
			public void done(IJobChangeEvent event) {
				// Ensure that the participant is disposed it it didn't go to the sync view
				if (TeamUI.getSynchronizeManager().get(participant.getId(), participant.getSecondaryId()) == null)
					participant.dispose();
			}
			
		});
		ownsParticipant = false;
		job.schedule();
	}

	public boolean belongsTo(Object family) {
		if (family == PARTICIPANT_MERGE_FAMILY) {
			return true;
		}
		if (participant != null && participant == family)
			return true;
		return super.belongsTo(family);
	}
	
	/**
	 * Return whether previews should occur in a dialog or in the synchronize view.
	 * @return whether previews should occur in a dialog or in the synchronize view
	 */
	protected boolean isPreviewInDialog() {
		return true;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.team.ui.operations.ResourceMappingOperation#getContext()
	 */
	protected ISynchronizationContext getContext() {
		if (participant != null)
			return participant.getContext();
		return null;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.ui.operations.ResourceMappingOperation#getPreviewRequestMessage()
	 */
	protected String getPreviewRequestMessage() {
		if (!isPreviewRequested()) {
			return TeamUIMessages.ResourceMappingMergeOperation_4; 
		}
		return super.getPreviewRequestMessage();
	}

	/**
	 * Create the synchronize participant to be used by this operation
	 * to preview changes. By default, a {@link ModelSynchronizeParticipant}
	 * is created using the scope manager ({@link #getScopeManager()}) context 
	 * from ({@link #createMergeContext()}) and job name ({@link #getJobName()})
	 * of this operation. Subclasses may override this method.
	 * <p>
	 * Once created, it is the responsibility of the participant to dispose of the 
	 * synchronization context when it is no longer needed. 
	 * @return a newly created synchronize participant to be used by this operation
	 */
	protected ModelSynchronizeParticipant createParticipant() {
		return ModelSynchronizeParticipant.createParticipant(createMergeContext(), getJobName());
	}

	/**
	 * Create a merge context for use by this operation. This method
	 * is not long running so the operation should not refresh the 
	 * context or perform other long running operations in this thread.
	 * However the context may start initializing in another thread as long
	 * as the job used to perform the initialization belongs to the
	 * family that matches the context.
	 * @return a merge context for use by this operation
	 */
	protected abstract SynchronizationContext createMergeContext();

}

Back to the top