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 org
.jetbrains
.idea
.svn
.annotate
;
18 import com
.intellij
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.fileEditor
.impl
.LoadTextUtil
;
20 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
21 import com
.intellij
.openapi
.progress
.ProgressManager
;
22 import com
.intellij
.openapi
.vcs
.VcsException
;
23 import com
.intellij
.openapi
.vcs
.annotate
.AnnotationProvider
;
24 import com
.intellij
.openapi
.vcs
.annotate
.FileAnnotation
;
25 import com
.intellij
.openapi
.vcs
.history
.VcsFileRevision
;
26 import com
.intellij
.openapi
.vfs
.VirtualFile
;
27 import org
.jetbrains
.idea
.svn
.SvnBundle
;
28 import org
.jetbrains
.idea
.svn
.SvnVcs
;
29 import org
.jetbrains
.idea
.svn
.SvnConfiguration
;
30 import org
.jetbrains
.idea
.svn
.SvnUtil
;
31 import org
.jetbrains
.idea
.svn
.history
.SvnFileRevision
;
32 import org
.tmatesoft
.svn
.core
.*;
33 import org
.tmatesoft
.svn
.core
.wc
.*;
35 import java
.io
.ByteArrayOutputStream
;
37 import java
.util
.Date
;
39 public class SvnAnnotationProvider
implements AnnotationProvider
{
40 private final SvnVcs myVcs
;
42 public SvnAnnotationProvider(final SvnVcs vcs
) {
46 public FileAnnotation
annotate(final VirtualFile file
) throws VcsException
{
47 return annotate(file
, new SvnFileRevision(myVcs
, SVNRevision
.WORKING
, SVNRevision
.WORKING
, null, null, null, null, null));
50 public FileAnnotation
annotate(final VirtualFile file
, final VcsFileRevision revision
) throws VcsException
{
51 if (file
.isDirectory()) {
52 throw new VcsException(SvnBundle
.message("exception.text.cannot.annotate.directory"));
54 final FileAnnotation
[] annotation
= new FileAnnotation
[1];
55 final SVNException
[] exception
= new SVNException
[1];
57 Runnable command
= new Runnable() {
59 final ProgressIndicator progress
= ProgressManager
.getInstance().getProgressIndicator();
61 final File ioFile
= new File(file
.getPath()).getAbsoluteFile();
63 final ByteArrayOutputStream buffer
= new ByteArrayOutputStream();
64 myVcs
.createWCClient().doGetFileContents(ioFile
, SVNRevision
.UNDEFINED
, SVNRevision
.BASE
, true, buffer
);
65 final String contents
= LoadTextUtil
.getTextByBinaryPresentation(buffer
.toByteArray(), file
, false).toString();
67 final SvnFileAnnotation result
= new SvnFileAnnotation(myVcs
, file
, contents
);
69 SVNWCClient wcClient
= myVcs
.createWCClient();
70 SVNInfo info
= wcClient
.doInfo(ioFile
, SVNRevision
.WORKING
);
72 exception
[0] = new SVNException(SVNErrorMessage
.create(SVNErrorCode
.UNKNOWN
, "File ''{0}'' is not under version control", ioFile
));
75 final String url
= info
.getURL() == null ?
null : info
.getURL().toString();
77 SVNLogClient client
= myVcs
.createLogClient();
78 setLogClientOptions(client
);
79 SVNRevision endRevision
= ((SvnFileRevision
) revision
).getRevision();
80 if (SVNRevision
.WORKING
.equals(endRevision
)) {
81 endRevision
= info
.getRevision();
83 if (progress
!= null) {
84 progress
.setText(SvnBundle
.message("progress.text.computing.annotation", file
.getName()));
87 // ignore mime type=true : IDEA-19562
88 final ISVNAnnotateHandler annotateHandler
= new ISVNAnnotateHandler() {
89 public void handleLine(Date date
, long revision
, String author
, String line
) {
90 if (progress
!= null) {
91 progress
.checkCanceled();
93 result
.appendLineInfo(date
, revision
, author
);
96 public void handleLine(final Date date
,
100 final Date mergedDate
,
101 final long mergedRevision
,
102 final String mergedAuthor
,
103 final String mergedPath
,
104 final int lineNumber
) throws SVNException
{
105 if (progress
!= null) {
106 progress
.checkCanceled();
108 if ((mergedDate
!= null) && (revision
> mergedRevision
)) {
109 // !!! merged date = date of merge, i.e. date -> date of original change etc.
110 result
.appendLineInfo(date
, revision
, author
, mergedDate
, mergedRevision
, mergedAuthor
);
113 result
.appendLineInfo(date
, revision
, author
);
117 public boolean handleRevision(final Date date
, final long revision
, final String author
, final File contents
)
118 throws SVNException
{
119 if (progress
!= null) {
120 progress
.checkCanceled();
122 // todo check that false is ok
126 public void handleEOF() {
131 final boolean supportsMergeinfo
= SvnUtil
.checkRepositoryVersion15(myVcs
, url
);
132 client
.doAnnotate(ioFile
, SVNRevision
.UNDEFINED
, SVNRevision
.create(0), endRevision
, true, supportsMergeinfo
, annotateHandler
, null);
134 client
.doLog(new File
[]{ioFile
}, endRevision
, SVNRevision
.create(1), SVNRevision
.UNDEFINED
, false, false, supportsMergeinfo
, 0, null,
135 new ISVNLogEntryHandler() {
136 public void handleLogEntry(SVNLogEntry logEntry
) {
137 if (progress
!= null) {
138 progress
.checkCanceled();
139 progress
.setText2(SvnBundle
.message("progress.text2.revision.processed", logEntry
.getRevision()));
141 result
.setRevision(logEntry
.getRevision(), new SvnFileRevision(myVcs
, SVNRevision
.UNDEFINED
, logEntry
, url
, ""));
145 annotation
[0] = result
;
147 catch (SVNException e
) {
152 if (ApplicationManager
.getApplication().isDispatchThread()) {
153 ProgressManager
.getInstance().runProcessWithProgressSynchronously(command
, SvnBundle
.message("action.text.annotate"), false, myVcs
.getProject());
158 if (exception
[0] != null) {
159 throw new VcsException(exception
[0]);
161 return annotation
[0];
164 public boolean isAnnotationValid( VcsFileRevision rev
){
168 private void setLogClientOptions(final SVNLogClient client
) {
169 if (SvnConfiguration
.getInstance(myVcs
.getProject()).IGNORE_SPACES_IN_ANNOTATE
) {
170 client
.setDiffOptions(new SVNDiffOptions(true, true, true));