git4idea: git actions are now dumb-aware
[fedora-idea.git] / plugins / git4idea / src / git4idea / actions / BasicAction.java
blobd1e08530b11ada0883410a9acac192250202fb3d
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package git4idea.actions;
18 import com.intellij.openapi.actionSystem.AnActionEvent;
19 import com.intellij.openapi.actionSystem.DataContext;
20 import com.intellij.openapi.actionSystem.PlatformDataKeys;
21 import com.intellij.openapi.actionSystem.Presentation;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.fileEditor.FileDocumentManager;
24 import com.intellij.openapi.project.DumbAwareAction;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.vcs.AbstractVcsHelper;
27 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
28 import com.intellij.openapi.vcs.TransactionRunnable;
29 import com.intellij.openapi.vcs.VcsException;
30 import com.intellij.openapi.vfs.VirtualFile;
31 import git4idea.GitUtil;
32 import git4idea.GitVcs;
33 import org.jetbrains.annotations.NotNull;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.List;
39 /**
40 * Basic abstract action handler for all Git actions to extend.
42 public abstract class BasicAction extends DumbAwareAction {
44 @Override
45 public void actionPerformed(@NotNull AnActionEvent event) {
46 final Project project = event.getData(PlatformDataKeys.PROJECT);
47 ApplicationManager.getApplication().runWriteAction(new Runnable() {
48 public void run() {
49 FileDocumentManager.getInstance().saveAllDocuments();
51 });
52 final VirtualFile[] vFiles = event.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
53 assert vFiles != null : "The action is only available when files are selected";
55 assert project != null;
56 final GitVcs vcs = GitVcs.getInstance(project);
57 if (!ProjectLevelVcsManager.getInstance(project).checkAllFilesAreUnder(vcs, vFiles)) {
58 return;
61 String actionName = getActionName();
62 AbstractVcsHelper helper = AbstractVcsHelper.getInstance(project);
64 //Runs the runnable inside the vcs transaction (if needed), collects all exceptions, commits/rollbacks transaction and returns all exceptions together.
65 List<VcsException> exceptions = helper.runTransactionRunnable(vcs, new TransactionRunnable() {
66 public void run(List<VcsException> exceptions) {
67 final VirtualFile[] affectedFiles = collectAffectedFiles(project, vFiles);
68 //noinspection unchecked
69 try {
70 perform(project, vcs, exceptions, affectedFiles);
72 catch (VcsException e) {
73 exceptions.add(e);
75 GitUtil.refreshFiles(project, Arrays.asList(affectedFiles));
78 }, null);
79 vcs.showErrors(exceptions, actionName);
83 protected abstract void perform(@NotNull Project project,
84 GitVcs mksVcs,
85 @NotNull List<VcsException> exceptions,
86 @NotNull VirtualFile[] affectedFiles) throws VcsException;
88 /**
89 * given a list of action-target files, returns ALL the files that should be
90 * subject to the action Does not keep directories, but recursively adds
91 * directory contents
93 * @param project the project subject of the action
94 * @param files the root selection
95 * @return the complete set of files this action should apply to
97 @NotNull
98 protected VirtualFile[] collectAffectedFiles(@NotNull Project project, @NotNull VirtualFile[] files) {
99 List<VirtualFile> affectedFiles = new ArrayList<VirtualFile>(files.length);
100 ProjectLevelVcsManager projectLevelVcsManager = ProjectLevelVcsManager.getInstance(project);
101 for (VirtualFile file : files) {
102 if (!file.isDirectory() && projectLevelVcsManager.getVcsFor(file) instanceof GitVcs) {
103 affectedFiles.add(file);
105 else if (file.isDirectory() && isRecursive()) {
106 addChildren(project, affectedFiles, file);
110 return affectedFiles.toArray(new VirtualFile[affectedFiles.size()]);
114 * recursively adds all the children of file to the files list, for which
115 * this action makes sense ({@link #appliesTo(Project, VirtualFile)}
116 * returns true)
118 * @param project the project subject of the action
119 * @param files result list
120 * @param file the file whose children should be added to the result list
121 * (recursively)
123 private void addChildren(@NotNull Project project, @NotNull List<VirtualFile> files, @NotNull VirtualFile file) {
124 VirtualFile[] children = file.getChildren();
125 for (VirtualFile child : children) {
126 if (!child.isDirectory() && appliesTo(project, child)) {
127 files.add(child);
129 else if (child.isDirectory() && isRecursive()) {
130 addChildren(project, files, child);
135 @NotNull
136 protected abstract String getActionName();
138 @SuppressWarnings({"MethodMayBeStatic"})
139 protected boolean isRecursive() {
140 return true;
143 @SuppressWarnings({"MethodMayBeStatic", "UnusedDeclaration"})
144 protected boolean appliesTo(@NotNull Project project, @NotNull VirtualFile file) {
145 return !file.isDirectory();
149 * Disable the action if the event does not apply in this context.
151 * @param e The update event
153 @Override
154 public void update(@NotNull AnActionEvent e) {
155 super.update(e);
156 Presentation presentation = e.getPresentation();
157 DataContext dataContext = e.getDataContext();
158 Project project = (Project)dataContext.getData(PlatformDataKeys.PROJECT.getName());
159 if (project == null) {
160 presentation.setEnabled(false);
161 presentation.setVisible(false);
162 return;
165 VirtualFile[] vFiles = (VirtualFile[])dataContext.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY.getName());
166 if (vFiles == null || vFiles.length == 0) {
167 presentation.setEnabled(false);
168 presentation.setVisible(true);
169 return;
171 GitVcs vcs = GitVcs.getInstance(project);
172 boolean enabled = ProjectLevelVcsManager.getInstance(project).checkAllFilesAreUnder(vcs, vFiles) && isEnabled(project, vcs, vFiles);
173 // only enable action if all the targets are under the vcs and the action supports all of them
175 presentation.setEnabled(enabled);
176 presentation.setVisible(enabled);
179 protected abstract boolean isEnabled(@NotNull Project project, @NotNull GitVcs vcs, @NotNull VirtualFile... vFiles);
181 public static void saveAll() {
182 ApplicationManager.getApplication().runWriteAction(new Runnable() {
183 public void run() {
184 FileDocumentManager.getInstance().saveAllDocuments();