1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
4 // Copyright (C) 2008-2014 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "gitpropertypage.h"
24 #include "UnicodeUtils.h"
25 #include "PathUtils.h"
26 #include "UnicodeUtils.h"
27 #include "CreateProcessHelper.h"
28 #include "FormatMessageWrapper.h"
30 typedef CComCritSecLock
<CComCriticalSection
> CAutoLocker
;
32 #define MAX_STRING_LENGTH 4096 //should be big enough
34 // Nonmember function prototypes
35 BOOL CALLBACK
PageProc (HWND
, UINT
, WPARAM
, LPARAM
);
36 UINT CALLBACK
PropPageCallbackProc ( HWND hwnd
, UINT uMsg
, LPPROPSHEETPAGE ppsp
);
38 /////////////////////////////////////////////////////////////////////////////
39 // Dialog procedures and other callback functions
41 BOOL CALLBACK
PageProc (HWND hwnd
, UINT uMessage
, WPARAM wParam
, LPARAM lParam
)
43 CGitPropertyPage
* sheetpage
;
45 if (uMessage
== WM_INITDIALOG
)
47 sheetpage
= (CGitPropertyPage
*) ((LPPROPSHEETPAGE
) lParam
)->lParam
;
48 SetWindowLongPtr (hwnd
, GWLP_USERDATA
, (LONG_PTR
) sheetpage
);
49 sheetpage
->SetHwnd(hwnd
);
53 sheetpage
= (CGitPropertyPage
*) GetWindowLongPtr (hwnd
, GWLP_USERDATA
);
57 return sheetpage
->PageProc(hwnd
, uMessage
, wParam
, lParam
);
62 UINT CALLBACK
PropPageCallbackProc ( HWND
/*hwnd*/, UINT uMsg
, LPPROPSHEETPAGE ppsp
)
64 // Delete the page before closing.
65 if (PSPCB_RELEASE
== uMsg
)
67 CGitPropertyPage
* sheetpage
= (CGitPropertyPage
*) ppsp
->lParam
;
68 if (sheetpage
!= NULL
)
74 // *********************** CGitPropertyPage *************************
75 const UINT
CGitPropertyPage::m_UpdateLastCommit
= RegisterWindowMessage(_T("TORTOISEGIT_PROP_UPDATELASTCOMMIT"));
77 CGitPropertyPage::CGitPropertyPage(const std::vector
<stdstring
> &newFilenames
)
78 :filenames(newFilenames
)
84 CGitPropertyPage::~CGitPropertyPage(void)
88 void CGitPropertyPage::SetHwnd(HWND newHwnd
)
93 BOOL
CGitPropertyPage::PageProc (HWND
/*hwnd*/, UINT uMessage
, WPARAM wParam
, LPARAM lParam
)
104 LPNMHDR point
= (LPNMHDR
)lParam
;
105 int code
= point
->code
;
107 // Respond to notifications.
109 if (code
== PSN_APPLY
&& m_bChanged
)
113 CTGitPath
path(filenames
.front().c_str());
114 CString projectTopDir
;
115 if(!path
.HasAdminDir(&projectTopDir
) || path
.IsDirectory())
118 int stripLength
= projectTopDir
.GetLength();
119 if (projectTopDir
[stripLength
- 1] != _T('\\'))
122 CStringA gitdir
= CUnicodeUtils::GetMulti(projectTopDir
, CP_UTF8
);
123 git_repository
*repository
= NULL
;
124 git_index
*index
= NULL
;
126 int ret
= git_repository_open(&repository
, gitdir
.GetBuffer());
127 gitdir
.ReleaseBuffer();
131 if (git_repository_index(&index
, repository
))
133 git_repository_free(repository
);
137 BOOL assumeValid
= (BOOL
)SendMessage(GetDlgItem(m_hwnd
, IDC_ASSUMEVALID
), BM_GETCHECK
, 0, 0);
138 BOOL skipWorktree
= (BOOL
)SendMessage(GetDlgItem(m_hwnd
, IDC_SKIPWORKTREE
), BM_GETCHECK
, 0, 0);
139 BOOL executable
= (BOOL
)SendMessage(GetDlgItem(m_hwnd
, IDC_EXECUTABLE
), BM_GETCHECK
, 0, 0);
141 bool changed
= false;
143 for (auto it
= filenames
.cbegin(); it
< filenames
.cend(); ++it
)
146 file
.SetFromWin(CString(it
->c_str()).Mid(stripLength
));
147 CStringA pathA
= CUnicodeUtils::GetMulti(file
.GetGitPathString(), CP_UTF8
);
149 if (!git_index_find(&idx
, index
, pathA
))
151 git_index_entry
*e
= const_cast<git_index_entry
*>(git_index_get_byindex(index
, idx
)); // HACK
153 if (assumeValid
== BST_CHECKED
)
155 if (!(e
->flags
& GIT_IDXENTRY_VALID
))
157 e
->flags
|= GIT_IDXENTRY_VALID
;
161 else if (assumeValid
!= BST_INDETERMINATE
)
163 if (e
->flags
& GIT_IDXENTRY_VALID
)
165 e
->flags
&= ~GIT_IDXENTRY_VALID
;
169 if (skipWorktree
== BST_CHECKED
)
171 if (!(e
->flags_extended
& GIT_IDXENTRY_SKIP_WORKTREE
))
173 e
->flags_extended
|= GIT_IDXENTRY_SKIP_WORKTREE
;
177 else if (skipWorktree
!= BST_INDETERMINATE
)
179 if (e
->flags_extended
& GIT_IDXENTRY_SKIP_WORKTREE
)
181 e
->flags_extended
&= ~GIT_IDXENTRY_SKIP_WORKTREE
;
185 if (executable
== BST_CHECKED
)
187 if (!(e
->mode
& 0111))
193 else if (executable
!= BST_INDETERMINATE
)
202 git_index_add(index
, e
);
208 if (!git_index_write(index
))
212 git_index_free(index
);
215 SetWindowLongPtr (m_hwnd
, DWLP_MSGRESULT
, FALSE
);
222 PageProcOnCommand(wParam
);
224 } // switch (uMessage)
226 if (uMessage
== m_UpdateLastCommit
)
228 DisplayCommit((git_commit
*)lParam
, IDC_LAST_HASH
, IDC_LAST_SUBJECT
, IDC_LAST_AUTHOR
, IDC_LAST_DATE
);
234 void CGitPropertyPage::PageProcOnCommand(WPARAM wParam
)
236 if(HIWORD(wParam
) != BN_CLICKED
)
239 switch (LOWORD(wParam
))
243 tstring gitCmd
= _T(" /command:");
244 gitCmd
+= _T("log /path:\"");
245 gitCmd
+= filenames
.front().c_str();
250 case IDC_SHOWSETTINGS
:
252 CTGitPath
path(filenames
.front().c_str());
253 CString projectTopDir
;
254 if(!path
.HasAdminDir(&projectTopDir
))
257 tstring gitCmd
= _T(" /command:");
258 gitCmd
+= _T("settings /path:\"");
259 gitCmd
+= projectTopDir
;
264 case IDC_ASSUMEVALID
:
265 case IDC_SKIPWORKTREE
:
268 SendMessage(GetParent(m_hwnd
), PSM_CHANGED
, (WPARAM
)m_hwnd
, 0);
273 void CGitPropertyPage::RunCommand(const tstring
& command
)
275 tstring tortoiseProcPath
= CPathUtils::GetAppDirectory(g_hmodThisDll
) + _T("TortoiseGitProc.exe");
276 if (CCreateProcessHelper::CreateProcessDetached(tortoiseProcPath
.c_str(), const_cast<TCHAR
*>(command
.c_str())))
278 // process started - exit
282 MessageBox(NULL
, CFormatMessageWrapper(), _T("TortoiseGitProc launch failed"), MB_OK
| MB_ICONINFORMATION
);
285 void CGitPropertyPage::Time64ToTimeString(__time64_t time
, TCHAR
* buf
, size_t buflen
)
290 LCID locale
= LOCALE_USER_DEFAULT
;
291 if (!CRegDWORD(_T("Software\\TortoiseGit\\UseSystemLocaleForDates"), TRUE
))
292 locale
= MAKELCID((WORD
)CRegStdDWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
)), SORT_DEFAULT
);
297 TCHAR timebuf
[MAX_STRING_LENGTH
] = { 0 };
298 TCHAR datebuf
[MAX_STRING_LENGTH
] = { 0 };
299 _localtime64_s(&newtime
, &time
);
301 systime
.wDay
= (WORD
)newtime
.tm_mday
;
302 systime
.wDayOfWeek
= (WORD
)newtime
.tm_wday
;
303 systime
.wHour
= (WORD
)newtime
.tm_hour
;
304 systime
.wMilliseconds
= 0;
305 systime
.wMinute
= (WORD
)newtime
.tm_min
;
306 systime
.wMonth
= (WORD
)newtime
.tm_mon
+1;
307 systime
.wSecond
= (WORD
)newtime
.tm_sec
;
308 systime
.wYear
= (WORD
)newtime
.tm_year
+1900;
309 if (CRegStdDWORD(_T("Software\\TortoiseGit\\LogDateFormat")) == 1)
310 GetDateFormat(locale
, DATE_SHORTDATE
, &systime
, NULL
, datebuf
, MAX_STRING_LENGTH
);
312 GetDateFormat(locale
, DATE_LONGDATE
, &systime
, NULL
, datebuf
, MAX_STRING_LENGTH
);
313 GetTimeFormat(locale
, 0, &systime
, NULL
, timebuf
, MAX_STRING_LENGTH
);
315 _tcsncat_s(buf
, buflen
, datebuf
, MAX_STRING_LENGTH
-1);
316 _tcsncat_s(buf
, buflen
, _T(" "), MAX_STRING_LENGTH
-1);
317 _tcsncat_s(buf
, buflen
, timebuf
, MAX_STRING_LENGTH
-1);
321 struct TreewalkStruct
328 static int TreewalkCB_FindFileRecentCommit(const char *root
, const git_tree_entry
*entry
, void *payload
)
330 TreewalkStruct
*treewalkstruct
= (TreewalkStruct
*)payload
;
331 char folder
[MAX_PATH
] = {0};
332 strcpy_s(folder
, root
);
333 strcat_s(folder
, git_tree_entry_name(entry
));
334 strcat_s(folder
, "/");
335 if (strstr(treewalkstruct
->folder
, folder
))
338 if (!strcmp(treewalkstruct
->folder
, root
))
340 if (!strcmp(git_tree_entry_name(entry
), treewalkstruct
->name
))
342 git_oid_cpy(&treewalkstruct
->oid
, git_tree_entry_id(entry
));
352 static git_commit
* FindFileRecentCommit(git_repository
*repository
, CString path
)
354 git_commit
*commit
= NULL
, *commit2
= NULL
;
356 if (git_revwalk_new(&walk
, repository
))
359 CStringA pathA
= CUnicodeUtils::GetUTF8(path
);
360 const char *pathC
= pathA
.GetBuffer();
361 char folder
[MAX_PATH
] = {0}, file
[MAX_PATH
] = {0};
362 const char *slash
= strrchr(pathC
, '/');
365 strncpy(folder
, pathC
, slash
- pathC
+ 1);
366 folder
[slash
- pathC
+ 1] = '\0';
367 strcpy(file
, slash
+ 1);
374 pathA
.ReleaseBuffer();
376 TreewalkStruct treewalkstruct
= { folder
, file
};
377 TreewalkStruct treewalkstruct2
= { folder
, file
};
381 if (git_revwalk_push_head(walk
))
382 throw "git_revwalk_push_head";
385 while (!git_revwalk_next(&oid
, walk
))
389 git_commit_free(commit
);
393 if (git_commit_lookup(&commit
, repository
, &oid
))
396 throw "git_commit_lookup 1";
400 if (git_commit_tree(&tree
, commit
))
401 throw "git_commit_tree 1";
403 memset(&treewalkstruct
.oid
.id
, 0, sizeof(treewalkstruct
.oid
.id
));
404 int ret
= git_tree_walk(tree
, GIT_TREEWALK_PRE
, TreewalkCB_FindFileRecentCommit
, &treewalkstruct
);
406 if (ret
< 0 && ret
!= GIT_EUSER
)
407 throw "git_tree_walk 1";
409 // check if file not found
410 if (git_oid_iszero(&treewalkstruct
.oid
))
412 git_commit_free(commit
);
418 // for merge point, check if it is different to all parents, if yes then there are real change in the merge point.
419 // if no parent then of course it is different
420 for (unsigned int i
= 0; i
< git_commit_parentcount(commit
); ++i
)
422 if (git_commit_parent(&commit2
, commit
, i
))
425 throw "git_commit_parent";
428 if (git_commit_tree(&tree
, commit2
))
429 throw "git_commit_tree 2";
431 git_commit_free(commit2
);
432 memset(&treewalkstruct2
.oid
.id
, 0, sizeof(treewalkstruct2
.oid
.id
));
433 int ret
= git_tree_walk(tree
, GIT_TREEWALK_PRE
, TreewalkCB_FindFileRecentCommit
, &treewalkstruct2
);
435 if (ret
< 0 && ret
!= GIT_EUSER
)
436 throw "git_tree_walk 2";
438 if (!git_oid_cmp(&treewalkstruct
.oid
, &treewalkstruct2
.oid
))
440 else if (git_revwalk_hide(walk
, git_commit_parent_id(commit
, i
)))
441 throw "git_revwalk_hide";
452 git_commit_free(commit
);
457 git_commit_free(commit2
);
462 git_revwalk_free(walk
);
466 void CGitPropertyPage::DisplayCommit(git_commit
* commit
, UINT hashLabel
, UINT subjectLabel
, UINT authorLabel
, UINT dateLabel
)
470 SetDlgItemText(m_hwnd
, hashLabel
, _T(""));
471 SetDlgItemText(m_hwnd
, subjectLabel
, _T(""));
472 SetDlgItemText(m_hwnd
, authorLabel
, _T(""));
473 SetDlgItemText(m_hwnd
, dateLabel
, _T(""));
477 int encode
= CP_UTF8
;
478 const char * encodingString
= git_commit_message_encoding(commit
);
479 if (encodingString
!= NULL
)
482 g_Git
.StringAppend(&str
, (BYTE
*)encodingString
, CP_UTF8
);
483 encode
= CUnicodeUtils::GetCPCode(str
);
486 const git_signature
* author
= git_commit_author(commit
);
488 g_Git
.StringAppend(&authorName
, (BYTE
*)author
->name
, encode
);
491 g_Git
.StringAppend(&message
, (BYTE
*)git_commit_message(commit
), encode
);
494 message
= message
.Tokenize(L
"\n", start
);
496 SetDlgItemText(m_hwnd
, hashLabel
, CGitHash((char*)(git_commit_id(commit
)->id
)).ToString());
497 SetDlgItemText(m_hwnd
, subjectLabel
, message
);
498 SetDlgItemText(m_hwnd
, authorLabel
, authorName
);
501 Time64ToTimeString(author
->when
.time
, authorDate
.GetBufferSetLength(200), 200);
502 SetDlgItemText(m_hwnd
, dateLabel
, authorDate
);
505 int CGitPropertyPage::LogThread()
507 CTGitPath
path(filenames
.front().c_str());
509 CAutoLocker
lock(g_Git
.m_critGitDllSec
); // HACK for libgit2
511 CString ProjectTopDir
;
512 if(!path
.HasAdminDir(&ProjectTopDir
))
515 CStringA gitdir
= CUnicodeUtils::GetMulti(ProjectTopDir
, CP_UTF8
);
516 git_repository
*repository
= NULL
;
518 int ret
= git_repository_open(&repository
, gitdir
.GetBuffer());
519 gitdir
.ReleaseBuffer();
523 int stripLength
= ProjectTopDir
.GetLength();
524 if (ProjectTopDir
[stripLength
- 1] != _T('\\'))
527 CTGitPath relatepath
;
528 relatepath
.SetFromWin(path
.GetWinPathString().Mid(stripLength
));
530 git_commit
*commit
= FindFileRecentCommit(repository
, relatepath
.GetGitPathString());
533 SendMessage(m_hwnd
, m_UpdateLastCommit
, NULL
, (LPARAM
)commit
);
534 git_commit_free(commit
);
538 SendMessage(m_hwnd
, m_UpdateLastCommit
, NULL
, NULL
);
541 git_repository_free(repository
);
546 void CGitPropertyPage::LogThreadEntry(void *param
)
548 ((CGitPropertyPage
*)param
)->LogThread();
551 static void ReadConfigValue(git_config
* config
, CString
& value
, const char * key
)
553 const char * out
= nullptr;
554 git_config_get_string(&out
, config
, key
);
555 value
= CUnicodeUtils::GetUnicode(out
);
558 void CGitPropertyPage::InitWorkfileView()
560 if (filenames
.empty())
563 CTGitPath
path(filenames
.front().c_str());
565 CString ProjectTopDir
;
566 if(!path
.HasAdminDir(&ProjectTopDir
))
569 CStringA gitdir
= CUnicodeUtils::GetMulti(ProjectTopDir
, CP_UTF8
);
570 git_repository
*repository
= NULL
;
572 int ret
= git_repository_open(&repository
, gitdir
.GetBuffer());
573 gitdir
.ReleaseBuffer();
582 git_config
* config
= nullptr;
583 if (!git_repository_config(&config
, repository
))
585 ReadConfigValue(config
, username
, "user.name");
586 ReadConfigValue(config
, useremail
, "user.email");
587 ReadConfigValue(config
, autocrlf
, "core.autocrlf");
588 ReadConfigValue(config
, safecrlf
, "core.safecrlf");
592 CString remotebranch
;
593 if (!git_repository_head_detached(repository
))
595 git_reference
* head
= nullptr;
596 if (git_repository_head_unborn(repository
))
598 git_reference_lookup(&head
, repository
, "HEAD");
599 branch
= CUnicodeUtils::GetUnicode(git_reference_symbolic_target(head
));
600 if (branch
.Find(_T("refs/heads/")) == 0)
601 branch
= branch
.Mid(11); // 11 = len("refs/heads/")
602 git_reference_free(head
);
604 else if (!git_repository_head(&head
, repository
))
606 const char * branchChar
= git_reference_shorthand(head
);
607 branch
= CUnicodeUtils::GetUnicode(branchChar
);
609 const char * branchFullChar
= git_reference_name(head
);
610 CStringA upstreambranchnameA
;
611 if (git_branch_upstream_name(upstreambranchnameA
.GetBufferSetLength(4096), 4096, repository
, branchFullChar
) > 0)
613 upstreambranchnameA
.ReleaseBuffer();
614 remotebranch
= CUnicodeUtils::GetUnicode(upstreambranchnameA
);
615 remotebranch
= remotebranch
.Mid(13); // 13=len("refs/remotes/")
618 git_reference_free(head
);
622 branch
= _T("detached HEAD");
624 if (autocrlf
.Trim().IsEmpty())
625 autocrlf
= _T("false");
626 if (safecrlf
.Trim().IsEmpty())
627 safecrlf
= _T("false");
629 SetDlgItemText(m_hwnd
,IDC_CONFIG_USERNAME
,username
.Trim());
630 SetDlgItemText(m_hwnd
,IDC_CONFIG_USEREMAIL
,useremail
.Trim());
631 SetDlgItemText(m_hwnd
,IDC_CONFIG_AUTOCRLF
,autocrlf
.Trim());
632 SetDlgItemText(m_hwnd
,IDC_CONFIG_SAFECRLF
,safecrlf
.Trim());
634 SetDlgItemText(m_hwnd
,IDC_SHELL_CURRENT_BRANCH
,branch
.Trim());
635 SetDlgItemText(m_hwnd
,IDC_SHELL_REMOTE_BRANCH
, remotebranch
);
638 git_commit
*HEADcommit
= NULL
;
639 if (!git_reference_name_to_id(&oid
, repository
, "HEAD") && !git_commit_lookup(&HEADcommit
, repository
, &oid
) && HEADcommit
!= NULL
)
641 DisplayCommit(HEADcommit
, IDC_HEAD_HASH
, IDC_HEAD_SUBJECT
, IDC_HEAD_AUTHOR
, IDC_HEAD_DATE
);
642 git_commit_free(HEADcommit
);
646 int stripLength
= ProjectTopDir
.GetLength();
647 if (ProjectTopDir
[stripLength
- 1] != _T('\\'))
650 bool allAreFiles
= true;
651 for (auto it
= filenames
.cbegin(); it
< filenames
.cend(); ++it
)
653 if (PathIsDirectory(it
->c_str()))
661 size_t assumevalid
= 0;
662 size_t skipworktree
= 0;
663 size_t executable
= 0;
666 git_index
*index
= NULL
;
668 if (git_repository_index(&index
, repository
))
671 for (auto it
= filenames
.cbegin(); it
< filenames
.cend(); ++it
)
674 file
.SetFromWin(CString(it
->c_str()).Mid(stripLength
));
675 CStringA pathA
= CUnicodeUtils::GetMulti(file
.GetGitPathString(), CP_UTF8
);
677 if (!git_index_find(&idx
, index
, pathA
))
679 const git_index_entry
*e
= git_index_get_byindex(index
, idx
);
681 if (e
->flags
& GIT_IDXENTRY_VALID
)
684 if (e
->flags_extended
& GIT_IDXENTRY_SKIP_WORKTREE
)
692 // do not show checkboxes for unversioned files
693 ShowWindow(GetDlgItem(m_hwnd
, IDC_ASSUMEVALID
), SW_HIDE
);
694 ShowWindow(GetDlgItem(m_hwnd
, IDC_SKIPWORKTREE
), SW_HIDE
);
695 ShowWindow(GetDlgItem(m_hwnd
, IDC_EXECUTABLE
), SW_HIDE
);
699 git_index_free(index
);
702 if (assumevalid
!= 0 && assumevalid
!= filenames
.size())
704 SendMessage(GetDlgItem(m_hwnd
, IDC_ASSUMEVALID
), BM_SETSTYLE
, (DWORD
)GetWindowLong(GetDlgItem(m_hwnd
, IDC_ASSUMEVALID
), GWL_STYLE
) & ~BS_AUTOCHECKBOX
| BS_AUTO3STATE
, 0);
705 SendMessage(GetDlgItem(m_hwnd
, IDC_ASSUMEVALID
), BM_SETCHECK
, BST_INDETERMINATE
, 0);
708 SendMessage(GetDlgItem(m_hwnd
, IDC_ASSUMEVALID
), BM_SETCHECK
, (assumevalid
== 0) ? BST_UNCHECKED
: BST_CHECKED
, 0);
710 if (skipworktree
!= 0 && skipworktree
!= filenames
.size())
712 SendMessage(GetDlgItem(m_hwnd
, IDC_SKIPWORKTREE
), BM_SETSTYLE
, (DWORD
)GetWindowLong(GetDlgItem(m_hwnd
, IDC_SKIPWORKTREE
), GWL_STYLE
) & ~BS_AUTOCHECKBOX
| BS_AUTO3STATE
, 0);
713 SendMessage(GetDlgItem(m_hwnd
, IDC_SKIPWORKTREE
), BM_SETCHECK
, BST_INDETERMINATE
, 0);
716 SendMessage(GetDlgItem(m_hwnd
, IDC_SKIPWORKTREE
), BM_SETCHECK
, (skipworktree
== 0) ? BST_UNCHECKED
: BST_CHECKED
, 0);
718 if (executable
!= 0 && executable
!= filenames
.size())
720 SendMessage(GetDlgItem(m_hwnd
, IDC_EXECUTABLE
), BM_SETSTYLE
, (DWORD
)GetWindowLong(GetDlgItem(m_hwnd
, IDC_EXECUTABLE
), GWL_STYLE
) & ~BS_AUTOCHECKBOX
| BS_AUTO3STATE
, 0);
721 SendMessage(GetDlgItem(m_hwnd
, IDC_EXECUTABLE
), BM_SETCHECK
, BST_INDETERMINATE
, 0);
724 SendMessage(GetDlgItem(m_hwnd
, IDC_EXECUTABLE
), BM_SETCHECK
, (executable
== 0) ? BST_UNCHECKED
: BST_CHECKED
, 0);
728 ShowWindow(GetDlgItem(m_hwnd
, IDC_ASSUMEVALID
), SW_HIDE
);
729 ShowWindow(GetDlgItem(m_hwnd
, IDC_SKIPWORKTREE
), SW_HIDE
);
730 ShowWindow(GetDlgItem(m_hwnd
, IDC_EXECUTABLE
), SW_HIDE
);
733 git_repository_free(repository
);
735 if (filenames
.size() == 1 && !PathIsDirectory(filenames
[0].c_str()))
737 SetDlgItemText(m_hwnd
, IDC_LAST_SUBJECT
, CString(MAKEINTRESOURCE(IDS_LOADING
)));
738 _beginthread(LogThreadEntry
, 0, this);
741 ShowWindow(GetDlgItem(m_hwnd
, IDC_STATIC_LASTMODIFIED
), SW_HIDE
);
745 // CShellExt member functions (needed for IShellPropSheetExt)
746 STDMETHODIMP
CShellExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage
, LPARAM lParam
)
750 return AddPages_Wrap(lpfnAddPage
, lParam
);
752 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
758 STDMETHODIMP
CShellExt::AddPages_Wrap(LPFNADDPROPSHEETPAGE lpfnAddPage
, LPARAM lParam
)
760 CString ProjectTopDir
;
762 for (std::vector
<stdstring
>::iterator I
= files_
.begin(); I
!= files_
.end(); ++I
)
765 GitStatus svn = GitStatus();
766 if (svn.GetStatus(CTGitPath(I->c_str())) == (-2))
767 return S_OK; // file/directory not under version control
769 if (svn.status->entry == NULL)
772 if( CTGitPath(I
->c_str()).HasAdminDir(&ProjectTopDir
))
783 SecureZeroMemory(&psp
, sizeof(PROPSHEETPAGE
));
784 HPROPSHEETPAGE hPage
;
785 CGitPropertyPage
*sheetpage
= new (std::nothrow
) CGitPropertyPage(files_
);
787 psp
.dwSize
= sizeof (psp
);
788 psp
.dwFlags
= PSP_USEREFPARENT
| PSP_USETITLE
| PSP_USEICONID
| PSP_USECALLBACK
;
789 psp
.hInstance
= g_hResInst
;
790 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_PROPPAGE
);
791 psp
.pszIcon
= MAKEINTRESOURCE(IDI_APPSMALL
);
792 psp
.pszTitle
= _T("Git");
793 psp
.pfnDlgProc
= (DLGPROC
) PageProc
;
794 psp
.lParam
= (LPARAM
) sheetpage
;
795 psp
.pfnCallback
= PropPageCallbackProc
;
796 psp
.pcRefParent
= (UINT
*)&g_cRefThisDll
;
798 hPage
= CreatePropertySheetPage (&psp
);
802 if (!lpfnAddPage (hPage
, lParam
))
805 DestroyPropertySheetPage (hPage
);
812 STDMETHODIMP
CShellExt::ReplacePage (UINT
/*uPageID*/, LPFNADDPROPSHEETPAGE
/*lpfnReplaceWith*/, LPARAM
/*lParam*/)