don't show empty revert dialog after reverting a hijacked file (IDEA-80577)
[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 com.intellij.util.containers.CollectionFactory;
48 import org.jetbrains.annotations.Nullable;
49
50 import java.util.*;
51
52 public class RollbackAction extends AnAction implements DumbAware {
53   public void update(AnActionEvent e) {
54     Project project = e.getData(PlatformDataKeys.PROJECT);
55     final boolean visible = project != null && ProjectLevelVcsManager.getInstance(project).hasActiveVcss();
56     e.getPresentation().setVisible(visible);
57     if (! visible) return;
58
59     final Change[] leadSelection = e.getData(VcsDataKeys.CHANGE_LEAD_SELECTION);
60     boolean isEnabled = (leadSelection != null && leadSelection.length > 0) ||
61                               Boolean.TRUE.equals(e.getData(VcsDataKeys.HAVE_LOCALLY_DELETED)) ||
62                               Boolean.TRUE.equals(e.getData(VcsDataKeys.HAVE_MODIFIED_WITHOUT_EDITING)) ||
63                               Boolean.TRUE.equals(e.getData(VcsDataKeys.HAVE_SELECTED_CHANGES));
64     if (! isEnabled) {
65       final VirtualFile[] files = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
66       if (files != null) {
67         final FileStatusManager fileStatusManager = FileStatusManager.getInstance(project);
68         for (VirtualFile file : files) {
69           final FileStatus status = fileStatusManager.getStatus(file);
70           if (FileStatus.UNKNOWN.equals(status) || FileStatus.IGNORED.equals(status) || FileStatus.NOT_CHANGED.equals(status)) {
71             continue;
72           }
73           isEnabled = true;
74           break;
75         }
76       }
77     }
78     e.getPresentation().setEnabled(isEnabled);
79     if (isEnabled) {
80       final AbstractVcs[] vcss = ProjectLevelVcsManager.getInstance(project).getAllActiveVcss();
81       for (AbstractVcs vcs : vcss) {
82         final RollbackEnvironment rollbackEnvironment = vcs.getRollbackEnvironment();
83         if (rollbackEnvironment != null) {
84           e.getPresentation().setText(rollbackEnvironment.getRollbackOperationName());
85           return;
86         }
87       }
88     }
89   }
90
91   public void actionPerformed(AnActionEvent e) {
92     Project project = e.getData(PlatformDataKeys.PROJECT);
93     if (project == null) {
94       return;
95     }
96     final String title = ActionPlaces.CHANGES_VIEW_TOOLBAR.equals(e.getPlace()) ? null : "Can not rollback now";
97     if (ChangeListManager.getInstance(project).isFreezedWithNotification(title)) return;
98     FileDocumentManager.getInstance().saveAllDocuments();
99
100     List<FilePath> missingFiles = e.getData(ChangesListView.MISSING_FILES_DATA_KEY);
101     boolean hasChanges = false;
102     if (missingFiles != null && !missingFiles.isEmpty()) {
103       hasChanges = true;
104       new RollbackDeletionAction().actionPerformed(e);
105     }
106
107     LinkedHashSet<VirtualFile> modifiedWithoutEditing = getModifiedWithoutEditing(e, project);
108     if (modifiedWithoutEditing != null && !modifiedWithoutEditing.isEmpty()) {
109       hasChanges = true;
110       rollbackModifiedWithoutEditing(project, modifiedWithoutEditing);
111     }
112
113     List<Change> changes = getChanges(project, e);
114     if (changes != null) {
115       if (modifiedWithoutEditing != null) {
116         for (Iterator<Change> iterator = changes.iterator(); iterator.hasNext(); ) {
117           Change next = iterator.next();
118           if (modifiedWithoutEditing.contains(next.getVirtualFile())) {
119             iterator.remove();
120           }
121         }
122       }
123       if (!changes.isEmpty() || !hasChanges) {
124         RollbackChangesDialog.rollbackChanges(project, changes);
125       }
126     }
127   }
128
129   private static class ChangesCheckHelper {
130     private Change[] myChanges;
131     private final boolean myChangesSet;
132
133     public ChangesCheckHelper(final Project project, final AnActionEvent e) {
134       Change[] changes = e.getData(VcsDataKeys.CHANGES);
135       if (changes == null) {
136         final VirtualFile[] files = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
137         if (files != null) {
138           final ChangeListManager clManager = ChangeListManager.getInstance(project);
139           final List<Change> changesList = new LinkedList<Change>();
140           for (VirtualFile vf : files) {
141             changesList.addAll(clManager.getChangesIn(vf));
142           }
143           if (! changesList.isEmpty()) {
144             changes = changesList.toArray(new Change[changesList.size()]);
145           }
146         }
147       }
148       myChangesSet = changes != null && changes.length > 0;
149       if (myChangesSet) {
150         if (ChangesUtil.allChangesInOneListOrWholeListsSelected(project, changes)) {
151           myChanges = changes;
152         }
153       }
154     }
155
156     public boolean isChangesSet() {
157       return myChangesSet;
158     }
159
160     public Change[] getChanges() {
161       return myChanges;
162     }
163   }
164
165   @Nullable
166   private static List<Change> getChanges(final Project project, final AnActionEvent e) {
167     final ChangesCheckHelper helper = new ChangesCheckHelper(project, e);
168     if (helper.isChangesSet()) return CollectionFactory.arrayList(helper.getChanges());
169
170     final VirtualFile[] virtualFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
171     if (virtualFiles != null && virtualFiles.length > 0) {
172       List<Change> result = new ArrayList<Change>();
173       for(VirtualFile file: virtualFiles) {
174         result.addAll(ChangeListManager.getInstance(project).getChangesIn(file));
175       }
176       return result;
177     }
178     return null;
179   }
180
181   @Nullable
182   private static LinkedHashSet<VirtualFile> getModifiedWithoutEditing(final AnActionEvent e, Project project) {
183     final List<VirtualFile> modifiedWithoutEditing = e.getData(VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY);
184     if (modifiedWithoutEditing != null && modifiedWithoutEditing.size() > 0) {
185       return new LinkedHashSet<VirtualFile>(modifiedWithoutEditing);
186     }
187
188     final VirtualFile[] virtualFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
189     if (virtualFiles != null && virtualFiles.length > 0) {
190       LinkedHashSet<VirtualFile> result = new LinkedHashSet<VirtualFile>(Arrays.asList(virtualFiles));
191       result.retainAll(ChangeListManager.getInstance(project).getModifiedWithoutEditing());
192       return result;
193     }
194
195     return null;
196   }
197
198   private static void rollbackModifiedWithoutEditing(final Project project, final LinkedHashSet<VirtualFile> modifiedWithoutEditing) {
199     String message = (modifiedWithoutEditing.size() == 1)
200       ? VcsBundle.message("rollback.modified.without.editing.confirm.single", modifiedWithoutEditing.iterator().next().getPresentableUrl())
201       : VcsBundle.message("rollback.modified.without.editing.confirm.multiple", modifiedWithoutEditing.size());
202     int rc = Messages.showYesNoDialog(project, message, VcsBundle.message("changes.action.rollback.title"), Messages.getQuestionIcon());
203     if (rc != 0) {
204       return;
205     }
206     final List<VcsException> exceptions = new ArrayList<VcsException>();
207
208     final ProgressManager progressManager = ProgressManager.getInstance();
209     final Runnable action = new Runnable() {
210       public void run() {
211         final ProgressIndicator indicator = progressManager.getProgressIndicator();
212         try {
213           ChangesUtil.processVirtualFilesByVcs(project, modifiedWithoutEditing, new ChangesUtil.PerVcsProcessor<VirtualFile>() {
214             public void process(final AbstractVcs vcs, final List<VirtualFile> items) {
215               final RollbackEnvironment rollbackEnvironment = vcs.getRollbackEnvironment();
216               if (rollbackEnvironment != null) {
217                 if (indicator != null) {
218                   indicator.setText(vcs.getDisplayName() + ": performing rollback...");
219                   indicator.setIndeterminate(false);
220                 }
221                 rollbackEnvironment.rollbackModifiedWithoutCheckout(items, exceptions, new RollbackProgressModifier(items.size(), indicator));
222                 if (indicator != null) {
223                   indicator.setText2("");
224                 }
225               }
226             }
227           });
228         }
229         catch (ProcessCanceledException e) {
230           // for files refresh  
231         }
232         if (!exceptions.isEmpty()) {
233           AbstractVcsHelper.getInstance(project).showErrors(exceptions, VcsBundle.message("rollback.modified.without.checkout.error.tab"));
234         }
235         VirtualFileManager.getInstance().refresh(true, new Runnable() {
236           public void run() {
237             for(VirtualFile virtualFile: modifiedWithoutEditing) {
238               VcsDirtyScopeManager.getInstance(project).fileDirty(virtualFile);
239             }
240           }
241         });
242       }
243     };
244     progressManager.runProcessWithProgressSynchronously(action, VcsBundle.message("changes.action.rollback.text"), true, project);
245   }
246 }