2e402f5e8cca28226b95bc3f1b2aa0fa28b92f02
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / actions / RollbackAction.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Created by IntelliJ IDEA.
19  * User: yole
20  * Date: 02.11.2006
21  * Time: 22:12:19
22  */
23 package com.intellij.openapi.vcs.changes.actions;
24
25 import com.intellij.openapi.actionSystem.ActionPlaces;
26 import com.intellij.openapi.actionSystem.AnAction;
27 import com.intellij.openapi.actionSystem.AnActionEvent;
28 import com.intellij.openapi.actionSystem.PlatformDataKeys;
29 import com.intellij.openapi.fileEditor.FileDocumentManager;
30 import com.intellij.openapi.progress.ProcessCanceledException;
31 import com.intellij.openapi.progress.ProgressIndicator;
32 import com.intellij.openapi.progress.ProgressManager;
33 import com.intellij.openapi.project.DumbAware;
34 import com.intellij.openapi.project.Project;
35 import com.intellij.openapi.ui.Messages;
36 import com.intellij.openapi.vcs.*;
37 import com.intellij.openapi.vcs.changes.Change;
38 import com.intellij.openapi.vcs.changes.ChangeListManager;
39 import com.intellij.openapi.vcs.changes.ChangesUtil;
40 import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
41 import com.intellij.openapi.vcs.changes.ui.ChangesListView;
42 import com.intellij.openapi.vcs.changes.ui.RollbackChangesDialog;
43 import com.intellij.openapi.vcs.changes.ui.RollbackProgressModifier;
44 import com.intellij.openapi.vcs.rollback.RollbackEnvironment;
45 import com.intellij.openapi.vfs.VirtualFile;
46 import com.intellij.openapi.vfs.VirtualFileManager;
47 import org.jetbrains.annotations.Nullable;
48
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.LinkedList;
52 import java.util.List;
53
54 public class RollbackAction extends AnAction implements DumbAware {
55   public void update(AnActionEvent e) {
56     Project project = e.getData(PlatformDataKeys.PROJECT);
57     final boolean visible = project != null && ProjectLevelVcsManager.getInstance(project).hasActiveVcss();
58     e.getPresentation().setVisible(visible);
59     if (! visible) return;
60
61     final Change[] leadSelection = e.getData(VcsDataKeys.CHANGE_LEAD_SELECTION);
62     boolean isEnabled = (leadSelection != null && leadSelection.length > 0) ||
63                               Boolean.TRUE.equals(e.getData(VcsDataKeys.HAVE_LOCALLY_DELETED)) ||
64                               Boolean.TRUE.equals(e.getData(VcsDataKeys.HAVE_MODIFIED_WITHOUT_EDITING)) ||
65                               Boolean.TRUE.equals(e.getData(VcsDataKeys.HAVE_SELECTED_CHANGES));
66     if (! isEnabled) {
67       final VirtualFile[] files = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
68       if (files != null) {
69         final FileStatusManager fileStatusManager = FileStatusManager.getInstance(project);
70         for (VirtualFile file : files) {
71           final FileStatus status = fileStatusManager.getStatus(file);
72           if (FileStatus.UNKNOWN.equals(status) || FileStatus.IGNORED.equals(status) || FileStatus.NOT_CHANGED.equals(status)) {
73             continue;
74           }
75           isEnabled = true;
76           break;
77         }
78       }
79     }
80     e.getPresentation().setEnabled(isEnabled);
81     if (isEnabled) {
82       final AbstractVcs[] vcss = ProjectLevelVcsManager.getInstance(project).getAllActiveVcss();
83       for (AbstractVcs vcs : vcss) {
84         final RollbackEnvironment rollbackEnvironment = vcs.getRollbackEnvironment();
85         if (rollbackEnvironment != null) {
86           e.getPresentation().setText(rollbackEnvironment.getRollbackOperationName());
87           return;
88         }
89       }
90     }
91   }
92
93   public void actionPerformed(AnActionEvent e) {
94     Project project = e.getData(PlatformDataKeys.PROJECT);
95     if (project == null) {
96       return;
97     }
98     final String title = ActionPlaces.CHANGES_VIEW_TOOLBAR.equals(e.getPlace()) ? null : "Can not rollback now";
99     if (ChangeListManager.getInstance(project).isFreezedWithNotification(title)) return;
100     FileDocumentManager.getInstance().saveAllDocuments();
101
102     List<FilePath> missingFiles = e.getData(ChangesListView.MISSING_FILES_DATA_KEY);
103     boolean hasChanges = false;
104     if (missingFiles != null && !missingFiles.isEmpty()) {
105       hasChanges = true;
106       new RollbackDeletionAction().actionPerformed(e);
107     }
108
109     List<VirtualFile> modifiedWithoutEditing = getModifiedWithoutEditing(e);
110     if (modifiedWithoutEditing != null && !modifiedWithoutEditing.isEmpty()) {
111       hasChanges = true;
112       rollbackModifiedWithoutEditing(project, modifiedWithoutEditing);
113     }
114
115     Change[] changes = getChanges(project, e);
116     if (changes != null && (changes.length > 0 || !hasChanges)) {
117       RollbackChangesDialog.rollbackChanges(project, Arrays.asList(changes));
118     }
119   }
120
121   private static class ChangesCheckHelper {
122     private Change[] myChanges;
123     private final boolean myChangesSet;
124
125     public ChangesCheckHelper(final Project project, final AnActionEvent e) {
126       Change[] changes = e.getData(VcsDataKeys.CHANGES);
127       if (changes == null) {
128         final VirtualFile[] files = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
129         if (files != null) {
130           final ChangeListManager clManager = ChangeListManager.getInstance(project);
131           final List<Change> changesList = new LinkedList<Change>();
132           for (VirtualFile vf : files) {
133             changesList.addAll(clManager.getChangesIn(vf));
134           }
135           if (! changesList.isEmpty()) {
136             changes = changesList.toArray(new Change[changesList.size()]);
137           }
138         }
139       }
140       myChangesSet = changes != null && changes.length > 0;
141       if (myChangesSet) {
142         if (ChangesUtil.allChangesInOneListOrWholeListsSelected(project, changes)) {
143           myChanges = changes;
144         }
145       }
146     }
147
148     public boolean isChangesSet() {
149       return myChangesSet;
150     }
151
152     public Change[] getChanges() {
153       return myChanges;
154     }
155   }
156
157   @Nullable
158   private static Change[] getChanges(final Project project, final AnActionEvent e) {
159     final ChangesCheckHelper helper = new ChangesCheckHelper(project, e);
160     if (helper.isChangesSet()) return helper.getChanges();
161
162     final VirtualFile[] virtualFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
163     if (virtualFiles != null && virtualFiles.length > 0) {
164       List<Change> result = new ArrayList<Change>();
165       for(VirtualFile file: virtualFiles) {
166         result.addAll(ChangeListManager.getInstance(project).getChangesIn(file));
167       }
168       return result.toArray(new Change[result.size()]);
169     }
170     return null;
171   }
172
173   @Nullable
174   private static List<VirtualFile> getModifiedWithoutEditing(final AnActionEvent e) {
175     final List<VirtualFile> modifiedWithoutEditing = e.getData(VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY);
176     if (modifiedWithoutEditing != null && modifiedWithoutEditing.size() > 0) {
177       return modifiedWithoutEditing;
178     }
179     return null;
180   }
181
182   private static void rollbackModifiedWithoutEditing(final Project project, final List<VirtualFile> modifiedWithoutEditing) {
183     String message = (modifiedWithoutEditing.size() == 1)
184       ? VcsBundle.message("rollback.modified.without.editing.confirm.single", modifiedWithoutEditing.get(0).getPresentableUrl())
185       : VcsBundle.message("rollback.modified.without.editing.confirm.multiple", modifiedWithoutEditing.size());
186     int rc = Messages.showYesNoDialog(project, message, VcsBundle.message("changes.action.rollback.title"), Messages.getQuestionIcon());
187     if (rc != 0) {
188       return;
189     }
190     final List<VcsException> exceptions = new ArrayList<VcsException>();
191
192     final ProgressManager progressManager = ProgressManager.getInstance();
193     final Runnable action = new Runnable() {
194       public void run() {
195         final ProgressIndicator indicator = progressManager.getProgressIndicator();
196         try {
197           ChangesUtil.processVirtualFilesByVcs(project, modifiedWithoutEditing, new ChangesUtil.PerVcsProcessor<VirtualFile>() {
198             public void process(final AbstractVcs vcs, final List<VirtualFile> items) {
199               final RollbackEnvironment rollbackEnvironment = vcs.getRollbackEnvironment();
200               if (rollbackEnvironment != null) {
201                 if (indicator != null) {
202                   indicator.setText(vcs.getDisplayName() + ": performing rollback...");
203                   indicator.setIndeterminate(false);
204                 }
205                 rollbackEnvironment.rollbackModifiedWithoutCheckout(items, exceptions, new RollbackProgressModifier(items.size(), indicator));
206                 if (indicator != null) {
207                   indicator.setText2("");
208                 }
209               }
210             }
211           });
212         }
213         catch (ProcessCanceledException e) {
214           // for files refresh  
215         }
216         if (!exceptions.isEmpty()) {
217           AbstractVcsHelper.getInstance(project).showErrors(exceptions, VcsBundle.message("rollback.modified.without.checkout.error.tab"));
218         }
219         VirtualFileManager.getInstance().refresh(true, new Runnable() {
220           public void run() {
221             for(VirtualFile virtualFile: modifiedWithoutEditing) {
222               VcsDirtyScopeManager.getInstance(project).fileDirty(virtualFile);
223             }
224           }
225         });
226       }
227     };
228     progressManager.runProcessWithProgressSynchronously(action, VcsBundle.message("changes.action.rollback.text"), true, project);
229   }
230 }