Keep the font size of 8 for the explorer property page
[TortoiseGit.git] / src / TortoiseGitBlame / TortoiseGitBlameDoc.cpp
blobdad45d6948d043a70f91fa4223a00a0563b3d019
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2017 - TortoiseGit
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.
21 // TortoiseGitBlameDoc.cpp : implementation of the CTortoiseGitBlameDoc class
24 #include "stdafx.h"
25 #include "TortoiseGitBlame.h"
27 #include "TortoiseGitBlameDoc.h"
28 #include "GitAdminDir.h"
29 #include "Git.h"
30 #include "MainFrm.h"
31 #include "TGitPath.h"
32 #include "TortoiseGitBlameView.h"
33 #include "CmdLineParser.h"
34 #include "CommonAppUtils.h"
35 #include "BlameDetectMovedOrCopiedLines.h"
36 #include "TempFile.h"
38 #ifdef _DEBUG
39 #define new DEBUG_NEW
40 #endif
43 // CTortoiseGitBlameDoc
45 IMPLEMENT_DYNCREATE(CTortoiseGitBlameDoc, CDocument)
47 BEGIN_MESSAGE_MAP(CTortoiseGitBlameDoc, CDocument)
48 END_MESSAGE_MAP()
50 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
52 // CTortoiseGitBlameDoc construction/destruction
54 CTortoiseGitBlameDoc::CTortoiseGitBlameDoc()
55 : m_bFirstStartup(true)
56 , m_IsGitFile(FALSE)
57 , m_lLine(1)
61 CTortoiseGitBlameDoc::~CTortoiseGitBlameDoc()
65 BOOL CTortoiseGitBlameDoc::OnNewDocument()
67 return TRUE;
69 BOOL CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName)
71 CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);
72 if (m_bFirstStartup)
74 m_Rev = parser.GetVal(L"rev");
75 m_lLine = (int)parser.GetLongVal(L"line");
76 m_bFirstStartup = false;
78 else
80 m_Rev.Empty();
81 m_lLine = 1;
84 return OnOpenDocument(lpszPathName,m_Rev);
87 BOOL CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName,CString Rev)
89 if(Rev.IsEmpty())
90 Rev = L"HEAD";
92 // enable blame for files which do not exist in current working tree
93 if (!PathFileExists(lpszPathName) && Rev != L"HEAD")
95 if (!CDocument::OnOpenDocument(CTempFiles::Instance().GetTempFilePath(true).GetWinPathString()))
96 return FALSE;
98 else
100 if (!CDocument::OnOpenDocument(lpszPathName))
101 return FALSE;
104 m_CurrentFileName = lpszPathName;
106 m_Rev=Rev;
108 // (SDI documents will reuse this document)
109 if(!g_Git.CheckMsysGitDir())
111 CCommonAppUtils::RunTortoiseGitProc(L" /command:settings");
112 return FALSE;
114 CString topdir;
115 if (!GitAdminDir::HasAdminDir(m_CurrentFileName, &topdir))
117 CString temp;
118 temp.Format(IDS_CANNOTBLAMENOGIT, (LPCTSTR)m_CurrentFileName);
119 MessageBox(nullptr, temp, L"TortoiseGitBlame", MB_OK | MB_ICONERROR);
120 return FALSE;
122 else
124 m_IsGitFile=TRUE;
125 sOrigCWD = g_Git.m_CurrentDir = topdir;
127 CString PathName = m_CurrentFileName;
128 if (topdir[topdir.GetLength() - 1] == L'\\' || topdir[topdir.GetLength() - 1] == L'/')
129 PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength());
130 else
131 PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()-1);
133 CTGitPath path;
134 path.SetFromWin(PathName);
136 if(!g_Git.m_CurrentDir.IsEmpty())
137 SetCurrentDirectory(g_Git.m_CurrentDir);
141 // make sure all config files are read in order to check that none contains an error
142 g_Git.GetConfigValue(L"doesnot.exist");
144 // make sure git_init() works and that .git-dir is ok
145 CAutoLocker lock(g_Git.m_critGitDllSec);
146 g_Git.CheckAndInitDll();
148 catch (char * libgiterr)
150 MessageBox(nullptr, CString(libgiterr), L"TortoiseGitBlame", MB_ICONERROR);
151 return FALSE;
154 CString cmd, option;
155 int dwDetectMovedOrCopiedLines = theApp.GetInt(L"DetectMovedOrCopiedLines", BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED);
156 int dwDetectMovedOrCopiedLinesNumCharactersWithinFile = theApp.GetInt(L"DetectMovedOrCopiedLinesNumCharactersWithinFile", BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_WITHIN_FILE_DEFAULT);
157 int dwDetectMovedOrCopiedLinesNumCharactersFromFiles = theApp.GetInt(L"DetectMovedOrCopiedLinesNumCharactersFromFiles", BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_FROM_FILES_DEFAULT);
158 switch(dwDetectMovedOrCopiedLines)
160 default:
161 case BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED:
162 option.Empty();
163 break;
164 case BLAME_DETECT_MOVED_OR_COPIED_LINES_WITHIN_FILE:
165 option.Format(L"-M%d", dwDetectMovedOrCopiedLinesNumCharactersWithinFile);
166 break;
167 case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_MODIFIED_FILES:
168 option.Format(L"-C%d", dwDetectMovedOrCopiedLinesNumCharactersFromFiles);
169 break;
170 case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES_AT_FILE_CREATION:
171 option.Format(L"-C -C%d", dwDetectMovedOrCopiedLinesNumCharactersFromFiles);
172 break;
173 case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES:
174 option.Format(L"-C -C -C%d", dwDetectMovedOrCopiedLinesNumCharactersFromFiles);
175 break;
178 if (theApp.GetInt(L"IgnoreWhitespace", 0) == 1)
179 option += L" -w";
181 bool onlyFirstParent = theApp.GetInt(L"OnlyFirstParent", 0) == 1;
182 if (onlyFirstParent)
184 CString tmpfile = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
185 cmd.Format(L"git rev-list --first-parent %s", (LPCTSTR)Rev);
186 CString err;
187 CAutoFILE file = _wfsopen(tmpfile, L"wb", SH_DENYWR);
188 if (!file)
190 MessageBox(nullptr, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + L"\n\nCould not create temp file!", L"TortoiseGitBlame", MB_OK | MB_ICONERROR);
191 return FALSE;
194 CStringA lastline;
195 if (g_Git.Run(cmd, [&](const CStringA& line)
197 fwrite(lastline + ' ' + line + '\n', sizeof(char), lastline.GetLength() + 1 + line.GetLength() + 1, file);
198 lastline = line;
200 , &err))
202 MessageBox(nullptr, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + L"\n\n" + err, L"TortoiseGitBlame", MB_OK | MB_ICONERROR);
203 return FALSE;
205 option.AppendFormat(L" -S \"%s\"", (LPCTSTR)tmpfile);
208 cmd.Format(L"git.exe blame -p %s %s -- \"%s\"", (LPCTSTR)option, (LPCTSTR)Rev, (LPCTSTR)path.GetGitPathString());
209 m_BlameData.clear();
210 BYTE_VECTOR err;
211 if(g_Git.Run(cmd, &m_BlameData, &err))
213 CString str;
214 if (!m_BlameData.empty())
215 CGit::StringAppend(&str, m_BlameData.data(), CP_UTF8, (int)m_BlameData.size());
216 if (!err.empty())
217 CGit::StringAppend(&str, err.data(), CP_UTF8, (int)err.size());
218 MessageBox(nullptr, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + L"\n\n" + str, L"TortoiseGitBlame", MB_OK | MB_ICONERROR);
220 return FALSE;
223 #ifdef USE_TEMPFILENAME
224 m_TempFileName = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
226 cmd.Format(L"git.exe cat-file blob %s:\"%s\"", (LPCTSTR)Rev, (LPCTSTR)path.GetGitPathString());
228 if(g_Git.RunLogFile(cmd, m_TempFileName))
230 CString str;
231 str.Format(IDS_CHECKOUTFAILED, (LPCTSTR)path.GetGitPathString());
232 MessageBox(nullptr, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + L"\n\n" + str, L"TortoiseGitBlame", MB_OK | MB_ICONERROR);
233 return FALSE;
235 #endif
236 m_GitPath = path;
238 CTortoiseGitBlameView *pView=DYNAMIC_DOWNCAST(CTortoiseGitBlameView,GetMainFrame()->GetActiveView());
239 if (!pView)
241 CWnd* pWnd = GetMainFrame()->GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);
242 if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CTortoiseGitBlameView)))
243 pView = static_cast<CTortoiseGitBlameView*>(pWnd);
244 else
245 return FALSE;
247 pView->ParseBlame();
249 BOOL bShowCompleteLog = (theApp.GetInt(L"ShowCompleteLog", 1) == 1);
250 if (bShowCompleteLog && BlameIsLimitedToOneFilename(dwDetectMovedOrCopiedLines) && !onlyFirstParent)
252 if (GetMainFrame()->m_wndOutput.LoadHistory(path.GetGitPathString(), m_Rev, (theApp.GetInt(L"FollowRenames", 0) == 1)))
253 return FALSE;
255 else
257 std::unordered_set<CGitHash> hashes;
258 pView->m_data.GetHashes(hashes);
259 if (GetMainFrame()->m_wndOutput.LoadHistory(hashes))
260 return FALSE;
263 pView->MapLineToLogIndex();
264 pView->UpdateInfo();
265 if (m_lLine > 0)
266 pView->GotoLine(m_lLine);
268 SetPathName(m_CurrentFileName, FALSE);
271 return TRUE;
274 void CTortoiseGitBlameDoc::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU)
276 CDocument::SetPathName(lpszPathName, bAddToMRU && (m_Rev == L"HEAD"));
278 this->SetTitle(CString(lpszPathName) + L':' + m_Rev);
281 // CTortoiseGitBlameDoc diagnostics
283 #ifdef _DEBUG
284 void CTortoiseGitBlameDoc::AssertValid() const
286 CDocument::AssertValid();
289 void CTortoiseGitBlameDoc::Dump(CDumpContext& dc) const
291 CDocument::Dump(dc);
293 #endif //_DEBUG
296 // CTortoiseGitBlameDoc commands