1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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
25 #include "TortoiseGitBlame.h"
27 #include "TortoiseGitBlameDoc.h"
28 #include "GitAdminDir.h"
29 #include "MessageBox.h"
33 #include "TortoiseGitBlameView.h"
34 #include "CmdLineParser.h"
35 #include "CommonAppUtils.h"
36 #include "BlameDetectMovedOrCopiedLines.h"
43 // CTortoiseGitBlameDoc
45 IMPLEMENT_DYNCREATE(CTortoiseGitBlameDoc
, CDocument
)
47 BEGIN_MESSAGE_MAP(CTortoiseGitBlameDoc
, CDocument
)
51 // CTortoiseGitBlameDoc construction/destruction
53 CTortoiseGitBlameDoc::CTortoiseGitBlameDoc()
55 m_bFirstStartup
= true;
60 CTortoiseGitBlameDoc::~CTortoiseGitBlameDoc()
64 BOOL
CTortoiseGitBlameDoc::OnNewDocument()
68 BOOL
CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName
)
70 CCmdLineParser
parser(AfxGetApp()->m_lpCmdLine
);
73 m_Rev
=parser
.GetVal(_T("rev"));
74 m_lLine
= (int)parser
.GetLongVal(_T("line"));
75 m_bFirstStartup
= false;
83 return OnOpenDocument(lpszPathName
,m_Rev
);
86 BOOL
CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName
,CString Rev
)
91 // enable blame for files which do not exist in current working tree
92 if (!PathFileExists(lpszPathName
) && Rev
!= _T("HEAD"))
94 if (!CDocument::OnOpenDocument(GetTempFile()))
99 if (!CDocument::OnOpenDocument(lpszPathName
))
103 m_CurrentFileName
= lpszPathName
;
107 // (SDI documents will reuse this document)
108 if(!g_Git
.CheckMsysGitDir())
110 CCommonAppUtils::RunTortoiseGitProc(_T(" /command:settings"));
114 if (!GitAdminDir::HasAdminDir(m_CurrentFileName
, &topdir
))
117 temp
.Format(IDS_CANNOTBLAMENOGIT
, (LPCTSTR
)m_CurrentFileName
);
118 CMessageBox::Show(NULL
, temp
, _T("TortoiseGitBlame"), MB_OK
);
124 if (topdir
!= g_Git
.m_CurrentDir
&& CTGitPath(g_Git
.m_CurrentDir
).HasAdminDir(&oldTopDir
) && oldTopDir
!= topdir
)
127 sMsg
.Format(IDS_ERR_DIFFENERTPREPO
, (LPCTSTR
)oldTopDir
, (LPCTSTR
)topdir
);
128 MessageBox(NULL
, sMsg
, _T("TortoiseGitBlame"), MB_OK
| MB_ICONERROR
);
133 sOrigCWD
= g_Git
.m_CurrentDir
= topdir
;
135 CString PathName
= m_CurrentFileName
;
136 if(topdir
[topdir
.GetLength()-1] == _T('\\') ||
137 topdir
[topdir
.GetLength()-1] == _T('/'))
138 PathName
=PathName
.Right(PathName
.GetLength()-g_Git
.m_CurrentDir
.GetLength());
140 PathName
=PathName
.Right(PathName
.GetLength()-g_Git
.m_CurrentDir
.GetLength()-1);
143 path
.SetFromWin(PathName
);
145 if(!g_Git
.m_CurrentDir
.IsEmpty())
146 SetCurrentDirectory(g_Git
.m_CurrentDir
);
150 // make sure all config files are read in order to check that none contains an error
151 g_Git
.GetConfigValue(_T("doesnot.exist"));
153 catch (char * libgiterr
)
155 MessageBox(NULL
, CString(libgiterr
), _T("TortoiseGitBlame"), MB_ICONERROR
);
160 int dwDetectMovedOrCopiedLines
= theApp
.GetInt(_T("DetectMovedOrCopiedLines"), BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED
);
161 int dwDetectMovedOrCopiedLinesNumCharactersWithinFile
= theApp
.GetInt(_T("DetectMovedOrCopiedLinesNumCharactersWithinFile"), BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_WITHIN_FILE_DEFAULT
);
162 int dwDetectMovedOrCopiedLinesNumCharactersFromFiles
= theApp
.GetInt(_T("DetectMovedOrCopiedLinesNumCharactersFromFiles"), BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_FROM_FILES_DEFAULT
);
163 switch(dwDetectMovedOrCopiedLines
)
166 case BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED
:
169 case BLAME_DETECT_MOVED_OR_COPIED_LINES_WITHIN_FILE
:
170 option
.Format(_T("-M%d"), dwDetectMovedOrCopiedLinesNumCharactersWithinFile
);
172 case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_MODIFIED_FILES
:
173 option
.Format(_T("-C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles
);
175 case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES_AT_FILE_CREATION
:
176 option
.Format(_T("-C -C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles
);
178 case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES
:
179 option
.Format(_T("-C -C -C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles
);
183 if (theApp
.GetInt(_T("IgnoreWhitespace"), 0) == 1)
186 cmd
.Format(_T("git.exe blame -p %s %s -- \"%s\""), (LPCTSTR
)option
, (LPCTSTR
)Rev
, (LPCTSTR
)path
.GetGitPathString());
189 if(g_Git
.Run(cmd
, &m_BlameData
, &err
))
192 if (!m_BlameData
.empty())
193 CGit::StringAppend(&str
, &m_BlameData
[0], CP_UTF8
);
195 CGit::StringAppend(&str
, &err
[0], CP_UTF8
);
196 MessageBox(NULL
, CString(MAKEINTRESOURCE(IDS_BLAMEERROR
)) + _T("\n\n") + str
, _T("TortoiseGitBlame"), MB_OK
);
201 #ifdef USE_TEMPFILENAME
202 if(!m_TempFileName
.IsEmpty())
204 ::DeleteFile(m_TempFileName
);
205 m_TempFileName
.Empty();
208 m_TempFileName
=GetTempFile();
210 cmd
.Format(_T("git.exe cat-file blob %s:\"%s\""), (LPCTSTR
)Rev
, (LPCTSTR
)path
.GetGitPathString());
212 if(g_Git
.RunLogFile(cmd
, m_TempFileName
))
215 str
.Format(IDS_CHECKOUTFAILED
, (LPCTSTR
)path
.GetGitPathString());
216 MessageBox(NULL
, CString(MAKEINTRESOURCE(IDS_BLAMEERROR
)) + _T("\n\n") + str
, _T("TortoiseGitBlame"), MB_OK
);
222 CTortoiseGitBlameView
*pView
=DYNAMIC_DOWNCAST(CTortoiseGitBlameView
,GetMainFrame()->GetActiveView());
225 CWnd
* pWnd
= GetMainFrame()->GetDescendantWindow(AFX_IDW_PANE_FIRST
, TRUE
);
226 if (pWnd
!= NULL
&& pWnd
->IsKindOf(RUNTIME_CLASS(CTortoiseGitBlameView
)))
228 pView
= (CTortoiseGitBlameView
*)pWnd
;
237 BOOL bShowCompleteLog
= (theApp
.GetInt(_T("ShowCompleteLog"), 1) == 1);
238 if (bShowCompleteLog
&& BlameIsLimitedToOneFilename(dwDetectMovedOrCopiedLines
))
240 if (GetMainFrame()->m_wndOutput
.LoadHistory(path
.GetGitPathString(), m_Rev
, (theApp
.GetInt(_T("FollowRenames"), 0) == 1)))
245 std::set
<CGitHash
> hashes
;
246 pView
->m_data
.GetHashes(hashes
);
247 if (GetMainFrame()->m_wndOutput
.LoadHistory(hashes
))
251 pView
->MapLineToLogIndex();
254 pView
->GotoLine(m_lLine
);
256 SetPathName(m_CurrentFileName
, FALSE
);
262 void CTortoiseGitBlameDoc::SetPathName(LPCTSTR lpszPathName
, BOOL bAddToMRU
)
264 CDocument::SetPathName(lpszPathName
, bAddToMRU
&& (m_Rev
== _T("HEAD")));
266 this->SetTitle(CString(lpszPathName
) + _T(":") + m_Rev
);
269 // CTortoiseGitBlameDoc diagnostics
272 void CTortoiseGitBlameDoc::AssertValid() const
274 CDocument::AssertValid();
277 void CTortoiseGitBlameDoc::Dump(CDumpContext
& dc
) const
284 // CTortoiseGitBlameDoc commands