1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "TortoiseProc.h"
22 #include "ProgressDlg.h"
25 #include "UnicodeUtils.h"
39 // m_progressDlg.Stop();
42 BOOL
CBlame::BlameCallback(LONG linenumber
, git_revnum_t revision
, const CString
& author
, const CString
& date
,
43 git_revnum_t merged_revision
, const CString
& merged_author
, const CString
& merged_date
, const CString
& merged_path
,
50 git_revnum_t origrev
= revision
;
52 if (((m_lowestrev
< 0)||(m_lowestrev
> revision
))&&(revision
>= 0))
53 m_lowestrev
= revision
;
54 if (m_highestrev
< revision
)
55 m_highestrev
= revision
;
58 CStringA
authorA(author
);
59 CStringA
pathA(merged_path
);
61 if (!merged_author
.IsEmpty() && (merged_revision
> 0))
63 dateA
= CStringA(merged_date
);
64 authorA
= CStringA(merged_author
);
65 revision
= merged_revision
;
70 if (pathA
.Find(' ') >= 60)
72 // the merge path has spaces in it:
73 // TortoiseBlame can't deal with such paths if the space is after
74 // the 60 char which is reserved for the path length in the blame file
75 // To avoid these problems, we escape the space
76 // (not the best solution, but it works)
77 pathA
.Replace(" ", "%20");
79 if (authorA
.GetLength() > 30 )
80 authorA
= authorA
.Left(30);
82 infolineA
.Format("%c %6ld %6ld %-30s %-60s %-30s ", c
, revision
, origrev
, (LPCSTR
)dateA
, (LPCSTR
)pathA
, (LPCSTR
)authorA
);
84 infolineA
.Format("%c %6ld %6ld %6ld %-30s %-60s %-30s ", c
, linenumber
, revision
, origrev
, (LPCSTR
)dateA
, (LPCSTR
)pathA
, (LPCSTR
)authorA
);
86 fulllineA
.TrimRight("\r\n");
88 if (m_saveFile
.m_hFile
!= INVALID_HANDLE_VALUE
)
90 m_saveFile
.WriteString(infolineA
);
91 m_saveFile
.WriteString(fulllineA
);
100 BOOL
CBlame::Log(git_revnum_t revision
, const CString
& /*author*/, const CString
& /*date*/, const CString
& message
, LogChangedPathArray
* /*cpaths*/, apr_time_t
/*time*/, int /*filechanges*/, BOOL
/*copies*/, DWORD
/*actions*/, BOOL
/*children*/)
102 m_progressDlg
.SetProgress(m_highestrev
- revision
, m_highestrev
);
103 if (m_saveLog
.m_hFile
!= INVALID_HANDLE_VALUE
)
105 CStringA msgutf8
= CUnicodeUtils::GetUTF8(message
);
106 int length
= msgutf8
.GetLength();
107 m_saveLog
.Write(&revision
, sizeof(LONG
));
108 m_saveLog
.Write(&length
, sizeof(int));
109 m_saveLog
.Write((LPCSTR
)msgutf8
, length
);
115 BOOL
CBlame::Cancel()
117 // if (m_progressDlg.HasUserCancelled())
118 // m_bCancelled = TRUE;
122 CString
CBlame::BlameToTempFile(const CTGitPath
& path
, GitRev startrev
, GitRev endrev
, GitRev pegrev
,
123 CString
& logfile
, const CString
& options
, BOOL includemerge
,
124 BOOL showprogress
, BOOL ignoremimetype
)
127 // if the user specified to use another tool to show the blames, there's no
128 // need to fetch the log later: only TortoiseBlame uses those logs to give
129 // the user additional information for the blame.
130 BOOL extBlame
= CRegDWORD(_T("Software\\TortoiseGit\\TextBlame"), FALSE
);
133 m_sSavePath
= CTempFiles::Instance().GetTempFilePath(false).GetWinPathString();
134 if (m_sSavePath
.IsEmpty())
136 temp
= path
.GetFileExtension();
137 if (!temp
.IsEmpty() && !extBlame
)
139 if (!m_saveFile
.Open(m_sSavePath
, CFile::typeText
| CFile::modeReadWrite
| CFile::modeCreate
))
143 headline
.Format(_T("%c %-6s %-6s %-6s %-30s %-60s %-30s %-s \n"), ' ', _T("line"), _T("rev"), _T("rev"), _T("date"), _T("path"), _T("author"), _T("content"));
144 m_saveFile
.WriteString(headline
);
145 m_saveFile
.WriteString(_T("\n"));
146 m_progressDlg
.SetTitle(IDS_BLAME_PROGRESSTITLE
);
147 m_progressDlg
.SetAnimation(IDR_DOWNLOAD
);
148 m_progressDlg
.SetShowProgressBar(TRUE
);
151 m_progressDlg
.ShowModeless(CWnd::FromHandle(hWndExplorer
));
153 m_progressDlg
.FormatNonPathLine(1, IDS_BLAME_PROGRESSINFO
);
154 m_progressDlg
.FormatNonPathLine(2, IDS_BLAME_PROGRESSINFOSTART
);
155 m_progressDlg
.SetCancelMsg(IDS_BLAME_PROGRESSCANCEL
);
156 m_progressDlg
.SetTime(FALSE
);
159 m_nHeadRev
= GetHEADRevision(path
);
160 m_progressDlg
.SetProgress(0, m_nHeadRev
);
162 m_bHasMerges
= false;
163 BOOL bBlameSuccesful
= this->Blame(path
, startrev
, endrev
, pegrev
, options
, !!ignoremimetype
, !!includemerge
);
164 if ( !bBlameSuccesful
&& !pegrev
.IsValid() )
166 // retry with the end rev as peg rev
167 if (this->Blame(path
, startrev
, endrev
, endrev
, options
, !!ignoremimetype
, !!includemerge
))
169 bBlameSuccesful
= TRUE
;
173 if (!bBlameSuccesful
)
176 DeleteFile(m_sSavePath
);
181 m_progressDlg
.FormatNonPathLine(2, IDS_BLAME_PROGRESSLOGSTART
);
182 m_progressDlg
.SetProgress(0, m_highestrev
);
183 logfile
= CTempFiles::Instance().GetTempFilePath(false).GetWinPathString();
184 if (!m_saveLog
.Open(logfile
, CFile::typeBinary
| CFile::modeReadWrite
| CFile::modeCreate
))
189 BOOL bRet
= ReceiveLog(CTGitPathList(path
), pegrev
, m_nHeadRev
, m_lowestrev
, 0, FALSE
, m_bHasMerges
, false);
201 m_progressDlg
.Stop();
202 if (m_saveFile
.m_hFile
!= INVALID_HANDLE_VALUE
)
208 BOOL
CBlame::Notify(const CTGitPath
& /*path*/, svn_wc_notify_action_t
/*action*/,
209 svn_node_kind_t
/*kind*/, const CString
& /*mime_type*/,
210 svn_wc_notify_state_t
/*content_state*/,
211 svn_wc_notify_state_t
/*prop_state*/, LONG rev
,
212 const svn_lock_t
* /*lock*/, svn_wc_notify_lock_state_t
/*lock_state*/,
213 svn_error_t
* /*err*/, apr_pool_t
* /*pool*/)
215 m_progressDlg
.FormatNonPathLine(2, IDS_BLAME_PROGRESSINFO2
, rev
, m_nHeadRev
);
216 m_progressDlg
.SetProgress(rev
, m_nHeadRev
);
220 bool CBlame::BlameToFile(const CTGitPath
& path
, GitRev startrev
, GitRev endrev
, GitRev peg
,
221 const CTGitPath
& tofile
, const CString
& options
, BOOL ignoremimetype
, BOOL includemerge
)
224 if (!m_saveFile
.Open(tofile
.GetWinPathString(), CFile::typeText
| CFile::modeReadWrite
| CFile::modeCreate
))
229 m_nHeadRev
= GetHEADRevision(path
);
231 BOOL bBlameSuccesful
= this->Blame(path
, startrev
, endrev
, peg
, options
, !!ignoremimetype
, !!includemerge
);
232 if ( !bBlameSuccesful
&& !peg
.IsValid() )
234 // retry with the end rev as peg rev
235 if (this->Blame(path
, startrev
, endrev
, endrev
, options
, !!ignoremimetype
, !!includemerge
))
237 bBlameSuccesful
= TRUE
;
242 if (!bBlameSuccesful
)
248 if (m_saveFile
.m_hFile
!= INVALID_HANDLE_VALUE
)