SVN 1.6 support. svnkit: 1-3-0-beta3, patched for IDEA
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / actions / CompareWithBranchAction.java
blobc598b2cffd339ec54fb26884660a41588f30ca36
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 org.jetbrains.idea.svn.actions;
19 import com.intellij.openapi.actionSystem.AnAction;
20 import com.intellij.openapi.actionSystem.AnActionEvent;
21 import com.intellij.openapi.actionSystem.PlatformDataKeys;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.diff.DiffManager;
25 import com.intellij.openapi.diff.FileContent;
26 import com.intellij.openapi.diff.SimpleContent;
27 import com.intellij.openapi.diff.SimpleDiffRequest;
28 import com.intellij.openapi.progress.ProgressIndicator;
29 import com.intellij.openapi.progress.ProgressManager;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.ui.Messages;
32 import com.intellij.openapi.util.Ref;
33 import com.intellij.openapi.util.io.FileUtil;
34 import com.intellij.openapi.vcs.AbstractVcsHelper;
35 import com.intellij.openapi.vcs.FileStatus;
36 import com.intellij.openapi.vcs.FileStatusManager;
37 import com.intellij.openapi.vcs.changes.Change;
38 import com.intellij.openapi.vfs.VirtualFile;
39 import org.jetbrains.annotations.Nullable;
40 import org.jetbrains.idea.svn.*;
41 import org.jetbrains.idea.svn.status.SvnDiffEditor;
42 import org.tmatesoft.svn.core.*;
43 import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
44 import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor;
45 import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
46 import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaInfo;
47 import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
48 import org.tmatesoft.svn.core.internal.wc.admin.SVNReporter;
49 import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
50 import org.tmatesoft.svn.core.io.SVNRepository;
51 import org.tmatesoft.svn.core.wc.SVNRevision;
52 import org.tmatesoft.svn.core.wc.SVNWCClient;
53 import org.tmatesoft.svn.util.SVNLogType;
54 import org.tmatesoft.svn.util.SVNDebugLog;
56 import java.io.ByteArrayOutputStream;
57 import java.io.File;
58 import java.nio.ByteBuffer;
59 import java.util.ArrayList;
60 import java.util.List;
62 /**
63 * @author yole
65 public class CompareWithBranchAction extends AnAction {
66 private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.actions.CompareWithBranchAction");
68 public void actionPerformed(AnActionEvent e) {
69 Project project = e.getData(PlatformDataKeys.PROJECT);
70 assert project != null;
71 final VirtualFile virtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE);
73 SelectBranchPopup.show(project, virtualFile, new SelectBranchPopup.BranchSelectedCallback() {
74 public void branchSelected(final Project project, final SvnBranchConfiguration configuration, final String url, final long revision) {
75 new CompareWithBranchOperation(project, virtualFile, configuration).compareWithBranch(url, revision);
77 }, SvnBundle.message("compare.with.branch.popup.title"));
80 @Override
81 public void update(final AnActionEvent e) {
82 Project project = e.getData(PlatformDataKeys.PROJECT);
83 VirtualFile virtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE);
84 e.getPresentation().setEnabled(isEnabled(project, virtualFile));
87 private static boolean isEnabled(final Project project, final VirtualFile virtualFile) {
88 if (project == null || virtualFile == null) {
89 return false;
91 final FileStatus fileStatus = FileStatusManager.getInstance(project).getStatus(virtualFile);
92 if (fileStatus == FileStatus.UNKNOWN || fileStatus == FileStatus.ADDED) {
93 return false;
95 return true;
99 private class CompareWithBranchOperation {
100 private final Project myProject;
101 private final VirtualFile myVirtualFile;
102 private final SvnBranchConfiguration myConfiguration;
104 public CompareWithBranchOperation(final Project project, final VirtualFile virtualFile, final SvnBranchConfiguration config) {
105 myProject = project;
106 myVirtualFile = virtualFile;
107 myConfiguration = config;
110 public void compareWithBranch(final String baseUrl, final long revision) {
111 if (myVirtualFile.isDirectory()) {
112 compareDirectoryWithBranch(baseUrl, revision);
114 else {
115 compareFileWithBranch(baseUrl, revision);
118 final StringBuilder titleBuilder = new StringBuilder();
120 public void compareDirectoryWithBranch(final String baseUrl, final long revision) {
121 final List<Change> changes = new ArrayList<Change>();
122 ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
123 public void run() {
124 try {
125 final SvnVcs vcs = SvnVcs.getInstance(myProject);
126 final SVNURL url = getURLInBranch(vcs, baseUrl);
127 if (url == null) return;
128 titleBuilder.append(SvnBundle.message("repository.browser.compare.title",
129 url.toString(),
130 FileUtil.toSystemDependentName(myVirtualFile.getPresentableUrl())));
133 SVNWCAccess wcAccess = vcs.createWCAccess();
134 try {
135 SVNAdminAreaInfo info = wcAccess.openAnchor(new File(myVirtualFile.getPath()), false, SVNWCAccess.INFINITE_DEPTH);
136 File anchorPath = info.getAnchor().getRoot();
137 String target = "".equals(info.getTargetName()) ? null : info.getTargetName();
139 SVNEntry anchorEntry = info.getAnchor().getEntry("", false);
140 if (anchorEntry == null) {
141 SVNErrorMessage err =
142 SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "''{0}'' is not under version control", anchorPath);
143 SVNErrorManager.error(err, SVNLogType.WC);
145 else if (anchorEntry.getURL() == null) {
146 SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", anchorPath);
147 SVNErrorManager.error(err, SVNLogType.WC);
150 SVNURL anchorURL = anchorEntry.getSVNURL();
151 SVNRepository repository = vcs.createRepository(anchorURL.toString());
152 SVNReporter reporter = new SVNReporter(info, info.getAnchor().getFile(info.getTargetName()), false, true, SVNDepth.INFINITY,
153 false, false, true, SVNDebugLog.getDefaultLog());
154 long rev = repository.getLatestRevision();
155 SvnDiffEditor diffEditor = new SvnDiffEditor((target == null) ? myVirtualFile : myVirtualFile.getParent(),
156 vcs.createRepository((target == null) ? url.toString() : url.removePathTail().toString()), rev, true);
157 repository.diff(url, rev, rev, target, true, true, false, reporter,
158 SVNCancellableEditor.newInstance(diffEditor, new SvnProgressCanceller(), null));
159 changes.addAll(diffEditor.getChangesMap().values());
161 finally {
162 wcAccess.close();
165 catch(SVNCancelException ex) {
166 changes.clear();
168 catch (SVNException ex) {
169 reportException(ex, baseUrl);
172 }, SvnBundle.message("progress.computing.difference"), true, myProject);
173 if (!changes.isEmpty()) {
174 AbstractVcsHelper.getInstance(myProject).showWhatDiffersBrowser(null, changes, titleBuilder.toString());
178 public void compareFileWithBranch(final String baseUrl, final long revision) {
179 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
180 final StringBuilder remoteTitleBuilder = new StringBuilder();
181 final Ref<Boolean> success = new Ref<Boolean>();
182 ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
183 public void run() {
184 try {
185 final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
186 if (indicator != null) {
187 indicator.setIndeterminate(true);
189 final SvnVcs vcs = SvnVcs.getInstance(myProject);
190 SVNURL svnurl = getURLInBranch(vcs, baseUrl);
191 if (svnurl == null) return;
192 remoteTitleBuilder.append(svnurl.toString());
193 SVNWCClient client = vcs.createWCClient();
194 client.doGetFileContents(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD, true, baos);
195 success.set(true);
197 catch (SVNException ex) {
198 reportException(ex, baseUrl);
201 }, SvnBundle.message("compare.with.branch.progress.loading.content"), true, myProject);
202 if (success.isNull()) {
203 return;
205 ByteBuffer contents = ByteBuffer.wrap(baos.toByteArray());
206 SimpleDiffRequest req = new SimpleDiffRequest(myProject, SvnBundle.message("compare.with.branch.diff.title"));
207 req.setContents(new SimpleContent(myVirtualFile.getCharset().decode(contents).toString()),
208 new FileContent(myProject, myVirtualFile));
209 req.setContentTitles(remoteTitleBuilder.toString(), myVirtualFile.getPresentableUrl());
210 DiffManager.getInstance().getDiffTool().show(req);
213 @Nullable
214 private SVNURL getURLInBranch(final SvnVcs vcs, final String baseUrl) throws SVNException {
215 final SvnFileUrlMapping urlMapping = vcs.getSvnFileUrlMapping();
216 final File file = new File(myVirtualFile.getPath());
217 final SVNURL fileUrl = urlMapping.getUrlForFile(file);
218 if (fileUrl == null) {
219 return null;
222 final String fileUrlString = fileUrl.toString();
223 final RootUrlInfo rootMixed = urlMapping.getWcRootForUrl(fileUrlString);
224 if (rootMixed == null) {
225 return null;
228 final SVNURL thisBranchForUrl = SvnUtil.getBranchForUrl(vcs, rootMixed.getVirtualFile(), fileUrlString);
229 if (thisBranchForUrl == null) {
230 return null;
233 final String relativePath = SVNPathUtil.getRelativePath(thisBranchForUrl.toString(), fileUrlString);
234 return SVNURL.parseURIEncoded(SVNPathUtil.append(baseUrl, relativePath));
237 private void reportException(final SVNException ex, final String baseUrl) {
238 final SVNErrorCode errorCode = ex.getErrorMessage().getErrorCode();
239 if (errorCode.equals(SVNErrorCode.RA_ILLEGAL_URL) ||
240 errorCode.equals(SVNErrorCode.CLIENT_UNRELATED_RESOURCES) ||
241 errorCode.equals(SVNErrorCode.RA_DAV_PATH_NOT_FOUND) ||
242 errorCode.equals(SVNErrorCode.FS_NOT_FOUND)) {
243 reportNotFound(baseUrl);
245 else {
246 ApplicationManager.getApplication().invokeLater(new Runnable() {
247 public void run() {
248 Messages.showMessageDialog(myProject, ex.getMessage(),
249 SvnBundle.message("compare.with.branch.error.title"), Messages.getErrorIcon());
252 LOG.info(ex);
256 private void reportNotFound(final String baseUrl) {
257 ApplicationManager.getApplication().invokeLater(new Runnable() {
258 public void run() {
259 Messages.showMessageDialog(myProject,
260 SvnBundle.message("compare.with.branch.location.error", myVirtualFile.getPresentableUrl(), baseUrl),
261 SvnBundle.message("compare.with.branch.error.title"), Messages.getErrorIcon());