"revert" action for committed changelist (IDEADEV-13292); refactoring to introduce...
[fedora-idea.git] / vcs-api / src / com / intellij / openapi / vcs / changes / ChangesUtil.java
blobb476478800baaab43881b6f897c6258f61ef18e9
1 /*
2 * Copyright 2000-2007 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.
17 package com.intellij.openapi.vcs.changes;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.fileEditor.OpenFileDescriptor;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.util.Computable;
23 import com.intellij.openapi.util.io.FileUtil;
24 import com.intellij.openapi.vcs.AbstractVcs;
25 import com.intellij.openapi.vcs.FilePath;
26 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
27 import com.intellij.openapi.vcs.actions.VcsContextFactory;
28 import com.intellij.openapi.vfs.LocalFileSystem;
29 import com.intellij.openapi.vfs.VirtualFile;
30 import com.intellij.pom.Navigatable;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
34 import java.io.File;
35 import java.util.*;
37 /**
38 * @author max
40 public class ChangesUtil {
41 private ChangesUtil() {}
43 @NotNull
44 public static FilePath getFilePath(@NotNull final Change change) {
45 ContentRevision revision = change.getAfterRevision();
46 if (revision == null) {
47 revision = change.getBeforeRevision();
48 assert revision != null;
51 return revision.getFile();
54 @Nullable
55 public static FilePath getBeforePath(@NotNull final Change change) {
56 ContentRevision revision = change.getBeforeRevision();
57 return revision == null ? null : revision.getFile();
60 @Nullable
61 public static FilePath getAfterPath(@NotNull final Change change) {
62 ContentRevision revision = change.getAfterRevision();
63 return revision == null ? null : revision.getFile();
66 public static AbstractVcs getVcsForChange(Change change, final Project project) {
67 return ProjectLevelVcsManager.getInstance(project).getVcsFor(getFilePath(change));
70 public static AbstractVcs getVcsForFile(VirtualFile file, Project project) {
71 return ProjectLevelVcsManager.getInstance(project).getVcsFor(file);
74 public static AbstractVcs getVcsForFile(File file, Project project) {
75 return ProjectLevelVcsManager.getInstance(project).getVcsFor(VcsContextFactory.SERVICE.getInstance().createFilePathOn(file));
78 public static Collection<FilePath> getPaths(final List<Change> changes) {
79 Set<FilePath> paths = new HashSet<FilePath>();
80 for (Change change : changes) {
81 ContentRevision beforeRevision = change.getBeforeRevision();
82 if (beforeRevision != null) {
83 paths.add(beforeRevision.getFile());
85 ContentRevision afterRevision = change.getAfterRevision();
86 if (afterRevision != null) {
87 paths.add(afterRevision.getFile());
90 return paths;
93 public static VirtualFile[] getFilesFromChanges(final Collection<Change> changes) {
94 ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
95 for (Change change : changes) {
96 final ContentRevision afterRevision = change.getAfterRevision();
97 if (afterRevision != null) {
98 final VirtualFile file = afterRevision.getFile().getVirtualFile();
99 if (file != null && file.isValid()) {
100 files.add(file);
104 return files.toArray(new VirtualFile[files.size()]);
107 public static Navigatable[] getNavigatableArray(final Project project, final VirtualFile[] selectedFiles) {
108 List<Navigatable> result = new ArrayList<Navigatable>();
109 for (VirtualFile selectedFile : selectedFiles) {
110 if (!selectedFile.isDirectory()) {
111 result.add(new OpenFileDescriptor(project, selectedFile));
114 return result.toArray(new Navigatable[result.size()]);
117 @Nullable
118 public static ChangeList getChangeListIfOnlyOne(@NotNull final Project project, @Nullable Change[] changes) {
119 if (changes == null || changes.length == 0) {
120 return null;
123 ChangeList selectedList = null;
124 for (Change change : changes) {
125 final ChangeList list = ChangeListManager.getInstance(project).getChangeList(change);
126 if (selectedList == null) {
127 selectedList = list;
129 else if (selectedList != list) {
130 return null;
133 return selectedList;
136 public static FilePath getCommittedPath(final Project project, FilePath filePath) {
137 // check if the file has just been renamed (IDEADEV-15494)
138 Change change = ChangeListManager.getInstance(project).getChange(filePath);
139 if (change != null) {
140 final ContentRevision beforeRevision = change.getBeforeRevision();
141 final ContentRevision afterRevision = change.getAfterRevision();
142 if (beforeRevision != null && afterRevision != null && !beforeRevision.getFile().equals(afterRevision.getFile()) &&
143 afterRevision.getFile().equals(filePath)) {
144 filePath = beforeRevision.getFile();
147 return filePath;
150 public static FilePath getLocalPath(final Project project, final FilePath filePath) {
151 // check if the file has just been renamed (IDEADEV-15494)
152 Change change = ApplicationManager.getApplication().runReadAction(new Computable<Change>() {
153 @Nullable
154 public Change compute() {
155 if (project.isDisposed()) return null;
156 return ChangeListManager.getInstance(project).getChange(filePath);
159 if (change != null) {
160 final ContentRevision beforeRevision = change.getBeforeRevision();
161 final ContentRevision afterRevision = change.getAfterRevision();
162 if (beforeRevision != null && afterRevision != null && !beforeRevision.getFile().equals(afterRevision.getFile()) &&
163 beforeRevision.getFile().equals(filePath)) {
164 return afterRevision.getFile();
167 return filePath;
170 @Nullable
171 public static VirtualFile findValidParent(FilePath file) {
172 ApplicationManager.getApplication().assertReadAccessAllowed();
173 VirtualFile parent = file.getVirtualFile();
174 if (parent == null) {
175 parent = file.getVirtualFileParent();
177 if (parent == null) {
178 File ioFile = file.getIOFile();
179 do {
180 parent = LocalFileSystem.getInstance().findFileByIoFile(ioFile);
181 if (parent != null) break;
182 ioFile = ioFile.getParentFile();
183 if (ioFile == null) return null;
185 while (true);
187 return parent;
190 @Nullable
191 public static String getProjectRelativePath(final Project project, @Nullable final File fileName) {
192 if (fileName == null) return null;
193 VirtualFile baseDir = project.getBaseDir();
194 if (baseDir == null) return fileName.toString();
195 String relativePath = FileUtil.getRelativePath(new File(baseDir.getPath()), fileName);
196 if (relativePath != null) return relativePath;
197 return fileName.toString();
200 public static boolean isBinaryContentRevision(final ContentRevision revision) {
201 return revision != null && !revision.getFile().isDirectory() && revision instanceof BinaryContentRevision;
204 public static boolean isBinaryChange(final Change change) {
205 return isBinaryContentRevision(change.getBeforeRevision()) || isBinaryContentRevision(change.getAfterRevision());
208 public interface PerVcsProcessor<T> {
209 void process(AbstractVcs vcs, List<T> items);
212 public interface VcsSeparator<T> {
213 AbstractVcs getVcsFor(T item);
216 public static <T> void processItemsByVcs(final Collection<T> items, final VcsSeparator<T> separator, PerVcsProcessor<T> processor) {
217 final Map<AbstractVcs, List<T>> changesByVcs = new HashMap<AbstractVcs, List<T>>();
219 ApplicationManager.getApplication().runReadAction(new Runnable() {
220 public void run() {
221 for (T item : items) {
222 final AbstractVcs vcs = separator.getVcsFor(item);
223 if (vcs != null) {
224 List<T> vcsChanges = changesByVcs.get(vcs);
225 if (vcsChanges == null) {
226 vcsChanges = new ArrayList<T>();
227 changesByVcs.put(vcs, vcsChanges);
229 vcsChanges.add(item);
235 for (Map.Entry<AbstractVcs, List<T>> entry : changesByVcs.entrySet()) {
236 processor.process(entry.getKey(), entry.getValue());
240 public static void processChangesByVcs(final Project project, Collection<Change> changes, PerVcsProcessor<Change> processor) {
241 processItemsByVcs(changes, new VcsSeparator<Change>() {
242 public AbstractVcs getVcsFor(final Change item) {
243 return getVcsForChange(item, project);
245 }, processor);
248 public static void processVirtualFilesByVcs(final Project project, Collection<VirtualFile> files, PerVcsProcessor<VirtualFile> processor) {
249 processItemsByVcs(files, new VcsSeparator<VirtualFile>() {
250 public AbstractVcs getVcsFor(final VirtualFile item) {
251 return getVcsForFile(item, project);
253 }, processor);
256 public static void processFilePathsByVcs(final Project project, Collection<FilePath> files, PerVcsProcessor<FilePath> processor) {
257 processItemsByVcs(files, new VcsSeparator<FilePath>() {
258 public AbstractVcs getVcsFor(final FilePath item) {
259 return getVcsForFile(item.getIOFile(), project);
261 }, processor);
264 public static List<File> filePathsToFiles(Collection<FilePath> filePaths) {
265 List<File> ioFiles = new ArrayList<File>();
266 for(FilePath filePath: filePaths) {
267 ioFiles.add(filePath.getIOFile());
269 return ioFiles;
272 public static boolean hasFileChanges(final Collection<Change> changes) {
273 for(Change change: changes) {
274 FilePath path = ChangesUtil.getFilePath(change);
275 if (!path.isDirectory()) {
276 return true;
279 return false;