KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > subscriber > WorkspaceCommitOperation


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.internal.ccvs.ui.subscriber;
12
13 import java.lang.reflect.InvocationTargetException JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.compare.structuremergeviewer.IDiffElement;
18 import org.eclipse.core.resources.IProject;
19 import org.eclipse.core.resources.IResource;
20 import org.eclipse.core.resources.mapping.ResourceMappingContext;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.OperationCanceledException;
23 import org.eclipse.jface.dialogs.IDialogConstants;
24 import org.eclipse.jface.dialogs.MessageDialog;
25 import org.eclipse.osgi.util.NLS;
26 import org.eclipse.swt.widgets.Shell;
27 import org.eclipse.team.core.TeamException;
28 import org.eclipse.team.core.mapping.provider.SynchronizationScopeManager;
29 import org.eclipse.team.core.synchronize.SyncInfo;
30 import org.eclipse.team.core.synchronize.SyncInfoSet;
31 import org.eclipse.team.internal.ccvs.core.*;
32 import org.eclipse.team.internal.ccvs.core.client.Command;
33 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
34 import org.eclipse.team.internal.ccvs.ui.*;
35 import org.eclipse.team.internal.ccvs.ui.Policy;
36 import org.eclipse.team.internal.ccvs.ui.operations.*;
37 import org.eclipse.team.internal.ccvs.ui.repo.RepositoryManager;
38 import org.eclipse.team.internal.core.subscribers.ChangeSet;
39 import org.eclipse.team.internal.ui.Utils;
40 import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;
41
42 public class WorkspaceCommitOperation extends CVSSubscriberOperation {
43     
44     private String JavaDoc comment;
45     private SyncInfoSet syncSet;
46     private boolean override;
47
48     public WorkspaceCommitOperation(ISynchronizePageConfiguration configuration, IDiffElement[] elements, boolean override) {
49         super(configuration, elements);
50         this.override = override;
51     }
52
53     /* (non-Javadoc)
54      * @see org.eclipse.team.internal.ccvs.ui.subscriber.CVSSubscriberOperation#getErrorTitle()
55      */

56     protected String JavaDoc getErrorTitle() {
57         return CVSUIMessages.CommitAction_commitFailed;
58     }
59     
60     /* (non-Javadoc)
61      * @see org.eclipse.team.internal.ui.actions.TeamOperation#getJobName()
62      */

63     protected String JavaDoc getJobName() {
64         SyncInfoSet syncSet = getSyncInfoSet();
65         return NLS.bind(CVSUIMessages.CommitAction_jobName, new String JavaDoc[] { new Integer JavaDoc(syncSet.size()).toString() });
66     }
67     
68     /* (non-Javadoc)
69      * @see org.eclipse.team.ui.TeamOperation#shouldRun()
70      */

71     public boolean shouldRun() {
72         SyncInfoSet set = getSyncInfoSet();
73         return !set.isEmpty();
74     }
75     
76     /* (non-Javadoc)
77      * @see org.eclipse.team.internal.ui.actions.SubscriberOperation#getSyncInfoSet()
78      */

79     protected SyncInfoSet getSyncInfoSet() {
80         if (syncSet == null) {
81             syncSet = super.getSyncInfoSet();
82             if (!promptForConflictHandling(syncSet)) {
83                 syncSet.clear();
84                 return syncSet;
85             }
86             try {
87                 if (!promptForUnaddedHandling(syncSet)) {
88                     syncSet.clear();
89                     return syncSet;
90                 }
91             } catch (CVSException e) {
92                 Utils.handle(e);
93                 syncSet.clear();
94             }
95         }
96         return syncSet;
97     }
98     
99     protected boolean promptForConflictHandling(SyncInfoSet syncSet) {
100         if (syncSet.hasConflicts() || syncSet.hasIncomingChanges()) {
101             if (override) {
102                 // If overriding, prompt to ensure that is what the user wants
103
switch (promptForConflicts(syncSet)) {
104                     case 0:
105                         // Yes, synchronize conflicts as well
106
break;
107                     case 1:
108                         // No, stop here
109
return false;
110                     case 2:
111                     default:
112                         // Cancel
113
return false;
114                 }
115             } else {
116                 // If there is a conflict in the syncSet, remove from sync set.
117
syncSet.removeConflictingNodes();
118                 syncSet.removeIncomingNodes();
119             }
120         }
121         return true;
122     }
123     
124     /*
125      * (non-Javadoc)
126      * @see org.eclipse.team.internal.ccvs.ui.subscriber.CVSSubscriberOperation#run(org.eclipse.team.core.synchronize.SyncInfoSet, org.eclipse.core.runtime.IProgressMonitor)
127      */

128     public void runWithProjectRule(IProject project, SyncInfoSet syncSet, IProgressMonitor monitor) throws TeamException {
129         
130         final SyncInfo[] changed = syncSet.getSyncInfos();
131         if (changed.length == 0) return;
132         
133         // A list of files to be committed
134
final List JavaDoc commits = new ArrayList JavaDoc(); // of IResource
135
// New resources that are not yet under CVS control and need a "cvs add"
136
final List JavaDoc additions = new ArrayList JavaDoc(); // of IResource
137
// A list of incoming or conflicting file changes to be made outgoing changes
138
final List JavaDoc makeOutgoing = new ArrayList JavaDoc(); // of SyncInfo
139
// A list of out-of-sync folders that must be made in-sync
140
final List JavaDoc makeInSync = new ArrayList JavaDoc(); // of SyncInfo
141

142         for (int i = 0; i < changed.length; i++) {
143             SyncInfo changedNode = changed[i];
144             int kind = changedNode.getKind();
145             IResource resource = changedNode.getLocal();
146             
147             // Any parent folders should be made in-sync.
148
// Steps will be taken after the commit to prune any empty folders
149
SyncInfo parent = getParent(changedNode);
150             if (parent != null) {
151                 if (isOutOfSync(parent)) {
152                     makeInSync.add(parent);
153                 }
154             }
155             
156             if (resource.getType() == IResource.FILE) {
157                 // By default, all files are committed
158
commits.add(resource);
159                 // Determine what other work needs to be done for the file
160
switch (kind & SyncInfo.DIRECTION_MASK) {
161                     case SyncInfo.INCOMING:
162                         // Convert the incoming change to an outgoing change
163
makeOutgoing.add(changedNode);
164                         break;
165                     case SyncInfo.OUTGOING:
166                         switch (kind & SyncInfo.CHANGE_MASK) {
167                             case SyncInfo.ADDITION:
168                                 // Outgoing addition. 'add' it before committing.
169
if (!isAdded(resource))
170                                     additions.add(resource);
171                                 break;
172                             case SyncInfo.DELETION:
173                                 // Outgoing deletion is handled by move/delete
174
// hook and EclipseSynchronizer
175
break;
176                             case SyncInfo.CHANGE:
177                                 // Outgoing change. Just commit it.
178
break;
179                         }
180                         break;
181                     case SyncInfo.CONFLICTING:
182                         // Convert the conflicting change to an outgoing change
183
makeOutgoing.add(changedNode);
184                         break;
185                 }
186             } else {
187                 if (((kind & SyncInfo.DIRECTION_MASK) == SyncInfo.OUTGOING)
188                     && ((kind & SyncInfo.CHANGE_MASK) == SyncInfo.ADDITION)) {
189                         // Outgoing folder additions must be added
190
additions.add(changedNode.getLocal());
191                 } else if (isOutOfSync(changedNode)) {
192                     // otherwise, make any out-of-sync folders in-sync using the remote info
193
makeInSync.add(changedNode);
194                 }
195             }
196         }
197         monitor.beginTask(null, 200);
198         
199         if (makeInSync.size() > 0) {
200             makeInSync((SyncInfo[]) makeInSync.toArray(new SyncInfo[makeInSync.size()]), Policy.subMonitorFor(monitor, 25));
201         }
202
203         if (makeOutgoing.size() > 0) {
204             makeOutgoing((SyncInfo[]) makeOutgoing.toArray(new SyncInfo[makeInSync.size()]), Policy.subMonitorFor(monitor, 25));
205         }
206
207         if (additions.size() != 0) {
208             add(project, (IResource[])additions.toArray(new IResource[0]), Policy.subMonitorFor(monitor, 50));
209         }
210         commit(project, (IResource[])commits.toArray(new IResource[commits.size()]), Policy.subMonitorFor(monitor, 100));
211     }
212     
213     private void commit(final IProject project, IResource[] commits, IProgressMonitor monitor) throws TeamException {
214         try {
215             CommitOperation commitOperation = new CommitOperation(getPart(), RepositoryProviderOperation.asResourceMappers(commits),
216                     new Command.LocalOption[0], comment) {
217                 protected ResourceMappingContext getResourceMappingContext() {
218                     return new SingleProjectSubscriberContext(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), false, project);
219                 }
220                 protected SynchronizationScopeManager createScopeManager(boolean consultModels) {
221                     return new SingleProjectScopeManager(getJobName(), getSelectedMappings(), getResourceMappingContext(), consultModels, project);
222                 }
223             };
224             commitOperation
225                         .run(monitor);
226         } catch (InvocationTargetException JavaDoc e) {
227             throw TeamException.asTeamException(e);
228         } catch (InterruptedException JavaDoc e) {
229             throw new OperationCanceledException();
230         }
231     }
232
233     private void add(final IProject project, IResource[] additions, IProgressMonitor monitor) throws TeamException {
234         try {
235             new AddOperation(getPart(), RepositoryProviderOperation.asResourceMappers(additions)) {
236                 protected ResourceMappingContext getResourceMappingContext() {
237                     return new SingleProjectSubscriberContext(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), false, project);
238                 }
239                 protected SynchronizationScopeManager createScopeManager(boolean consultModels) {
240                     return new SingleProjectScopeManager(getJobName(), getSelectedMappings(), getResourceMappingContext(), consultModels, project);
241                 }
242             }.run(monitor);
243         } catch (InvocationTargetException JavaDoc e1) {
244             throw TeamException.asTeamException(e1);
245         } catch (InterruptedException JavaDoc e1) {
246             throw new OperationCanceledException();
247         }
248     }
249
250     /**
251      * Prompts the user to determine how conflicting changes should be handled.
252      * Note: This method is designed to be overridden by test cases.
253      * @return 0 to sync conflicts, 1 to sync all non-conflicts, 2 to cancel
254      */

255     protected int promptForConflicts(SyncInfoSet syncSet) {
256         String JavaDoc[] buttons = new String JavaDoc[] {IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL};
257         String JavaDoc question = CVSUIMessages.CommitSyncAction_questionRelease;
258         String JavaDoc title = CVSUIMessages.CommitSyncAction_titleRelease;
259         String JavaDoc[] tips = new String JavaDoc[] {
260             CVSUIMessages.CommitSyncAction_releaseAll,
261             CVSUIMessages.CommitSyncAction_releasePart,
262             CVSUIMessages.CommitSyncAction_cancelRelease
263         };
264         Shell shell = getShell();
265         final ToolTipMessageDialog dialog = new ToolTipMessageDialog(shell, title, null, question, MessageDialog.QUESTION, buttons, tips, 0);
266         shell.getDisplay().syncExec(new Runnable JavaDoc() {
267             public void run() {
268                 dialog.open();
269             }
270         });
271         return dialog.getReturnCode();
272     }
273         
274     /**
275      * Prompts the user for a release comment.
276      * Note: This method is designed to be overridden by test cases.
277      * @return the comment, or null to cancel
278      */

279     protected String JavaDoc promptForComment(RepositoryManager manager, IResource[] resourcesToCommit) {
280         String JavaDoc proposedComment = getProposedComment(resourcesToCommit);
281         return manager.promptForComment(getShell(), resourcesToCommit, proposedComment);
282     }
283
284     private String JavaDoc getProposedComment(IResource[] resourcesToCommit) {
285         StringBuffer JavaDoc comment = new StringBuffer JavaDoc();
286         ChangeSet[] sets = CVSUIPlugin.getPlugin().getChangeSetManager().getSortedSets();
287         int numMatchedSets = 0;
288         for (int i = 0; i < sets.length; i++) {
289             ChangeSet set = sets[i];
290             if (containsOne(set, resourcesToCommit)) {
291                 if(numMatchedSets > 0) comment.append(System.getProperty("line.separator")); //$NON-NLS-1$
292
comment.append(set.getComment());
293                 numMatchedSets++;
294             }
295         }
296         return comment.toString();
297     }
298     
299     private boolean containsOne(ChangeSet set, IResource[] resourcesToCommit) {
300          for (int j = 0; j < resourcesToCommit.length; j++) {
301             IResource resource = resourcesToCommit[j];
302             if (set.contains(resource)) {
303                 return true;
304             }
305         }
306         return false;
307     }
308
309     protected IResource[] promptForResourcesToBeAdded(RepositoryManager manager, IResource[] unadded) {
310         return manager.promptForResourcesToBeAdded(getShell(), unadded);
311     }
312     
313     private boolean promptForUnaddedHandling(SyncInfoSet syncSet) throws CVSException {
314         if (syncSet.isEmpty()) return false;
315         
316         // accumulate any resources that are not under version control
317
IResource[] unadded = getUnaddedResources(syncSet);
318         
319         // prompt to get comment and any resources to be added to version control
320
RepositoryManager manager = CVSUIPlugin.getPlugin().getRepositoryManager();
321         IResource[] toBeAdded = promptForResourcesToBeAdded(manager, unadded);
322         if (toBeAdded == null) return false; // User cancelled.
323
comment = promptForComment(manager, syncSet.getResources());
324         if (comment == null) return false; // User cancelled.
325

326         // remove unshared resources that were not selected by the user
327
if (unadded != null && unadded.length > 0) {
328             List JavaDoc resourcesToRemove = new ArrayList JavaDoc(unadded.length);
329             for (int i = 0; i < unadded.length; i++) {
330                 IResource unaddedResource = unadded[i];
331                 boolean included = false;
332                 for (int j = 0; j < toBeAdded.length; j++) {
333                     IResource resourceToAdd = toBeAdded[j];
334                     if (unaddedResource.equals(resourceToAdd)) {
335                         included = true;
336                         break;
337                     }
338                 }
339                 if (!included)
340                     resourcesToRemove.add(unaddedResource);
341             }
342             syncSet.removeAll((IResource[]) resourcesToRemove.toArray(new IResource[resourcesToRemove.size()]));
343         }
344         return true;
345     }
346     
347     private IResource[] getUnaddedResources(SyncInfoSet syncSet) throws CVSException {
348         // TODO: Should only get outgoing additions (since conflicting additions
349
// could be considered to be under version control already)
350
IResource[] resources = syncSet.getResources();
351         List JavaDoc result = new ArrayList JavaDoc();
352         for (int i = 0; i < resources.length; i++) {
353             IResource resource = resources[i];
354             if (!isAdded(resource)) {
355                 result.add(resource);
356             }
357         }
358         return (IResource[]) result.toArray(new IResource[result.size()]);
359     }
360
361     private boolean isAdded(IResource resource) throws CVSException {
362         ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
363         if (cvsResource.isFolder()) {
364             return ((ICVSFolder)cvsResource).isCVSFolder();
365         } else {
366             return cvsResource.isManaged();
367         }
368     }
369
370 }
371
Popular Tags