Avoid CString.GetBuffer() and make use of default (LPCTSTR) operator
[TortoiseGit.git] / src / TortoiseShell / GITPropertyPage.cpp
blobb900103972a4133b0c973f922e677db251ce3517
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.
20 #include "stdafx.h"
22 #include "ShellExt.h"
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);
51 else
53 sheetpage = (CGitPropertyPage*) GetWindowLongPtr (hwnd, GWLP_USERDATA);
56 if (sheetpage != 0L)
57 return sheetpage->PageProc(hwnd, uMessage, wParam, lParam);
58 else
59 return FALSE;
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)
69 delete sheetpage;
71 return 1;
74 // *********************** CGitPropertyPage *************************
75 const UINT CGitPropertyPage::m_UpdateLastCommit = RegisterWindowMessage(_T("TORTOISEGIT_PROP_UPDATELASTCOMMIT"));
77 CGitPropertyPage::CGitPropertyPage(const std::vector<stdstring> &newFilenames)
78 :filenames(newFilenames)
79 ,m_bChanged(false)
80 , m_hwnd(NULL)
84 CGitPropertyPage::~CGitPropertyPage(void)
88 void CGitPropertyPage::SetHwnd(HWND newHwnd)
90 m_hwnd = newHwnd;
93 BOOL CGitPropertyPage::PageProc (HWND /*hwnd*/, UINT uMessage, WPARAM wParam, LPARAM lParam)
95 switch (uMessage)
97 case WM_INITDIALOG:
99 InitWorkfileView();
100 return TRUE;
102 case WM_NOTIFY:
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())
116 break;
118 int stripLength = projectTopDir.GetLength();
119 if (projectTopDir[stripLength - 1] != _T('\\'))
120 ++stripLength;
122 CStringA gitdir = CUnicodeUtils::GetMulti(projectTopDir, CP_UTF8);
123 git_repository *repository = NULL;
124 git_index *index = NULL;
126 if (git_repository_open(&repository, gitdir))
127 break;
129 if (git_repository_index(&index, repository))
131 git_repository_free(repository);
132 break;
135 BOOL assumeValid = (BOOL)SendMessage(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), BM_GETCHECK, 0, 0);
136 BOOL skipWorktree = (BOOL)SendMessage(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), BM_GETCHECK, 0, 0);
137 BOOL executable = (BOOL)SendMessage(GetDlgItem(m_hwnd, IDC_EXECUTABLE), BM_GETCHECK, 0, 0);
139 bool changed = false;
141 for (auto it = filenames.cbegin(); it < filenames.cend(); ++it)
143 CTGitPath file;
144 file.SetFromWin(CString(it->c_str()).Mid(stripLength));
145 CStringA pathA = CUnicodeUtils::GetMulti(file.GetGitPathString(), CP_UTF8);
146 size_t idx;
147 if (!git_index_find(&idx, index, pathA))
149 git_index_entry *e = const_cast<git_index_entry *>(git_index_get_byindex(index, idx)); // HACK
151 if (assumeValid == BST_CHECKED)
153 if (!(e->flags & GIT_IDXENTRY_VALID))
155 e->flags |= GIT_IDXENTRY_VALID;
156 changed = true;
159 else if (assumeValid != BST_INDETERMINATE)
161 if (e->flags & GIT_IDXENTRY_VALID)
163 e->flags &= ~GIT_IDXENTRY_VALID;
164 changed = true;
167 if (skipWorktree == BST_CHECKED)
169 if (!(e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE))
171 e->flags_extended |= GIT_IDXENTRY_SKIP_WORKTREE;
172 changed = true;
175 else if (skipWorktree != BST_INDETERMINATE)
177 if (e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE)
179 e->flags_extended &= ~GIT_IDXENTRY_SKIP_WORKTREE;
180 changed = true;
183 if (executable == BST_CHECKED)
185 if (!(e->mode & 0111))
187 e->mode |= 0111;
188 changed = true;
191 else if (executable != BST_INDETERMINATE)
193 if (e->mode & 0111)
195 e->mode &= ~0111;
196 changed = true;
199 if (changed)
200 git_index_add(index, e);
204 if (changed)
206 if (!git_index_write(index))
207 m_bChanged = false;
210 git_index_free(index);
211 } while (0);
213 SetWindowLongPtr (m_hwnd, DWLP_MSGRESULT, FALSE);
214 return TRUE;
216 case WM_DESTROY:
217 return TRUE;
219 case WM_COMMAND:
220 PageProcOnCommand(wParam);
221 break;
222 } // switch (uMessage)
224 if (uMessage == m_UpdateLastCommit)
226 DisplayCommit((git_commit *)lParam, IDC_LAST_HASH, IDC_LAST_SUBJECT, IDC_LAST_AUTHOR, IDC_LAST_DATE);
227 return TRUE;
230 return FALSE;
232 void CGitPropertyPage::PageProcOnCommand(WPARAM wParam)
234 if(HIWORD(wParam) != BN_CLICKED)
235 return;
237 switch (LOWORD(wParam))
239 case IDC_SHOWLOG:
241 tstring gitCmd = _T(" /command:");
242 gitCmd += _T("log /path:\"");
243 gitCmd += filenames.front().c_str();
244 gitCmd += _T("\"");
245 RunCommand(gitCmd);
247 break;
248 case IDC_SHOWSETTINGS:
250 CTGitPath path(filenames.front().c_str());
251 CString projectTopDir;
252 if(!path.HasAdminDir(&projectTopDir))
253 return;
255 tstring gitCmd = _T(" /command:");
256 gitCmd += _T("settings /path:\"");
257 gitCmd += projectTopDir;
258 gitCmd += _T("\"");
259 RunCommand(gitCmd);
261 break;
262 case IDC_ASSUMEVALID:
263 case IDC_SKIPWORKTREE:
264 case IDC_EXECUTABLE:
265 m_bChanged = true;
266 SendMessage(GetParent(m_hwnd), PSM_CHANGED, (WPARAM)m_hwnd, 0);
267 break;
271 void CGitPropertyPage::RunCommand(const tstring& command)
273 tstring tortoiseProcPath = CPathUtils::GetAppDirectory(g_hmodThisDll) + _T("TortoiseGitProc.exe");
274 if (CCreateProcessHelper::CreateProcessDetached(tortoiseProcPath.c_str(), const_cast<TCHAR*>(command.c_str())))
276 // process started - exit
277 return;
280 MessageBox(NULL, CFormatMessageWrapper(), _T("TortoiseGitProc launch failed"), MB_OK | MB_ICONINFORMATION);
283 void CGitPropertyPage::Time64ToTimeString(__time64_t time, TCHAR * buf, size_t buflen)
285 struct tm newtime;
286 SYSTEMTIME systime;
288 LCID locale = LOCALE_USER_DEFAULT;
289 if (!CRegDWORD(_T("Software\\TortoiseGit\\UseSystemLocaleForDates"), TRUE))
290 locale = MAKELCID((WORD)CRegStdDWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)), SORT_DEFAULT);
292 *buf = '\0';
293 if (time)
295 TCHAR timebuf[MAX_STRING_LENGTH] = { 0 };
296 TCHAR datebuf[MAX_STRING_LENGTH] = { 0 };
297 _localtime64_s(&newtime, &time);
299 systime.wDay = (WORD)newtime.tm_mday;
300 systime.wDayOfWeek = (WORD)newtime.tm_wday;
301 systime.wHour = (WORD)newtime.tm_hour;
302 systime.wMilliseconds = 0;
303 systime.wMinute = (WORD)newtime.tm_min;
304 systime.wMonth = (WORD)newtime.tm_mon+1;
305 systime.wSecond = (WORD)newtime.tm_sec;
306 systime.wYear = (WORD)newtime.tm_year+1900;
307 if (CRegStdDWORD(_T("Software\\TortoiseGit\\LogDateFormat")) == 1)
308 GetDateFormat(locale, DATE_SHORTDATE, &systime, NULL, datebuf, MAX_STRING_LENGTH);
309 else
310 GetDateFormat(locale, DATE_LONGDATE, &systime, NULL, datebuf, MAX_STRING_LENGTH);
311 GetTimeFormat(locale, 0, &systime, NULL, timebuf, MAX_STRING_LENGTH);
312 *buf = '\0';
313 _tcsncat_s(buf, buflen, datebuf, MAX_STRING_LENGTH-1);
314 _tcsncat_s(buf, buflen, _T(" "), MAX_STRING_LENGTH-1);
315 _tcsncat_s(buf, buflen, timebuf, MAX_STRING_LENGTH-1);
319 struct TreewalkStruct
321 const char *folder;
322 const char *name;
323 git_oid oid;
326 static int TreewalkCB_FindFileRecentCommit(const char *root, const git_tree_entry *entry, void *payload)
328 TreewalkStruct *treewalkstruct = (TreewalkStruct *)payload;
329 char folder[MAX_PATH] = {0};
330 strcpy_s(folder, root);
331 strcat_s(folder, git_tree_entry_name(entry));
332 strcat_s(folder, "/");
333 if (strstr(treewalkstruct->folder, folder))
334 return 0;
336 if (!strcmp(treewalkstruct->folder, root))
338 if (!strcmp(git_tree_entry_name(entry), treewalkstruct->name))
340 git_oid_cpy(&treewalkstruct->oid, git_tree_entry_id(entry));
341 return -1;
344 return 1;
347 return 1;
350 static git_commit * FindFileRecentCommit(git_repository *repository, CString path)
352 git_commit *commit = NULL, *commit2 = NULL;
353 git_revwalk *walk;
354 if (git_revwalk_new(&walk, repository))
355 return NULL;
357 CStringA pathA = CUnicodeUtils::GetUTF8(path);
358 const char *pathC = pathA;
359 char folder[MAX_PATH] = {0}, file[MAX_PATH] = {0};
360 const char *slash = strrchr(pathC, '/');
361 if (slash)
363 strncpy(folder, pathC, slash - pathC + 1);
364 folder[slash - pathC + 1] = '\0';
365 strcpy(file, slash + 1);
367 else
369 folder[0] = '\0';
370 strcpy(file, pathC);
373 TreewalkStruct treewalkstruct = { folder, file };
374 TreewalkStruct treewalkstruct2 = { folder, file };
378 if (git_revwalk_push_head(walk))
379 throw "git_revwalk_push_head";
381 git_oid oid;
382 while (!git_revwalk_next(&oid, walk))
384 if (commit != NULL)
386 git_commit_free(commit);
387 commit = NULL;
390 if (git_commit_lookup(&commit, repository, &oid))
392 commit = NULL;
393 throw "git_commit_lookup 1";
396 git_tree *tree;
397 if (git_commit_tree(&tree, commit))
398 throw "git_commit_tree 1";
400 memset(&treewalkstruct.oid.id, 0, sizeof(treewalkstruct.oid.id));
401 int ret = git_tree_walk(tree, GIT_TREEWALK_PRE, TreewalkCB_FindFileRecentCommit, &treewalkstruct);
402 git_tree_free(tree);
403 if (ret < 0 && ret != GIT_EUSER)
404 throw "git_tree_walk 1";
406 // check if file not found
407 if (git_oid_iszero(&treewalkstruct.oid))
409 git_commit_free(commit);
410 commit = NULL;
411 break;
414 bool diff = true;
415 // for merge point, check if it is different to all parents, if yes then there are real change in the merge point.
416 // if no parent then of course it is different
417 for (unsigned int i = 0; i < git_commit_parentcount(commit); ++i)
419 if (git_commit_parent(&commit2, commit, i))
421 commit2 = NULL;
422 throw "git_commit_parent";
425 if (git_commit_tree(&tree, commit2))
426 throw "git_commit_tree 2";
428 git_commit_free(commit2);
429 memset(&treewalkstruct2.oid.id, 0, sizeof(treewalkstruct2.oid.id));
430 int ret = git_tree_walk(tree, GIT_TREEWALK_PRE, TreewalkCB_FindFileRecentCommit, &treewalkstruct2);
431 git_tree_free(tree);
432 if (ret < 0 && ret != GIT_EUSER)
433 throw "git_tree_walk 2";
435 if (!git_oid_cmp(&treewalkstruct.oid, &treewalkstruct2.oid))
436 diff = false;
437 else if (git_revwalk_hide(walk, git_commit_parent_id(commit, i)))
438 throw "git_revwalk_hide";
441 if (diff)
442 break;
445 catch (...)
447 if (commit != NULL)
449 git_commit_free(commit);
450 commit = NULL;
452 if (commit2 != NULL)
454 git_commit_free(commit2);
455 commit2 = NULL;
459 git_revwalk_free(walk);
460 return commit;
463 void CGitPropertyPage::DisplayCommit(git_commit * commit, UINT hashLabel, UINT subjectLabel, UINT authorLabel, UINT dateLabel)
465 if (commit == NULL)
467 SetDlgItemText(m_hwnd, hashLabel, _T(""));
468 SetDlgItemText(m_hwnd, subjectLabel, _T(""));
469 SetDlgItemText(m_hwnd, authorLabel, _T(""));
470 SetDlgItemText(m_hwnd, dateLabel, _T(""));
471 return;
474 int encode = CP_UTF8;
475 const char * encodingString = git_commit_message_encoding(commit);
476 if (encodingString != NULL)
478 CString str;
479 g_Git.StringAppend(&str, (BYTE*)encodingString, CP_UTF8);
480 encode = CUnicodeUtils::GetCPCode(str);
483 const git_signature * author = git_commit_author(commit);
484 CString authorName;
485 g_Git.StringAppend(&authorName, (BYTE*)author->name, encode);
487 CString message;
488 g_Git.StringAppend(&message, (BYTE*)git_commit_message(commit), encode);
490 int start = 0;
491 message = message.Tokenize(L"\n", start);
493 SetDlgItemText(m_hwnd, hashLabel, CGitHash((char*)(git_commit_id(commit)->id)).ToString());
494 SetDlgItemText(m_hwnd, subjectLabel, message);
495 SetDlgItemText(m_hwnd, authorLabel, authorName);
497 CString authorDate;
498 Time64ToTimeString(author->when.time, authorDate.GetBufferSetLength(200), 200);
499 SetDlgItemText(m_hwnd, dateLabel, authorDate);
502 int CGitPropertyPage::LogThread()
504 CTGitPath path(filenames.front().c_str());
506 CAutoLocker lock(g_Git.m_critGitDllSec); // HACK for libgit2
508 CString ProjectTopDir;
509 if(!path.HasAdminDir(&ProjectTopDir))
510 return 0;
512 CStringA gitdir = CUnicodeUtils::GetMulti(ProjectTopDir, CP_UTF8);
513 git_repository *repository = NULL;
515 if (git_repository_open(&repository, gitdir))
516 return 0;
518 int stripLength = ProjectTopDir.GetLength();
519 if (ProjectTopDir[stripLength - 1] != _T('\\'))
520 ++stripLength;
522 CTGitPath relatepath;
523 relatepath.SetFromWin(path.GetWinPathString().Mid(stripLength));
525 git_commit *commit = FindFileRecentCommit(repository, relatepath.GetGitPathString());
526 if (commit != NULL)
528 SendMessage(m_hwnd, m_UpdateLastCommit, NULL, (LPARAM)commit);
529 git_commit_free(commit);
531 else
533 SendMessage(m_hwnd, m_UpdateLastCommit, NULL, NULL);
536 git_repository_free(repository);
538 return 0;
541 void CGitPropertyPage::LogThreadEntry(void *param)
543 ((CGitPropertyPage*)param)->LogThread();
546 static void ReadConfigValue(git_config * config, CString& value, const char * key)
548 const char * out = nullptr;
549 git_config_get_string(&out, config, key);
550 value = CUnicodeUtils::GetUnicode(out);
553 void CGitPropertyPage::InitWorkfileView()
555 if (filenames.empty())
556 return;
558 CTGitPath path(filenames.front().c_str());
560 CString ProjectTopDir;
561 if(!path.HasAdminDir(&ProjectTopDir))
562 return;
564 CStringA gitdir = CUnicodeUtils::GetMulti(ProjectTopDir, CP_UTF8);
565 git_repository *repository = NULL;
567 if (git_repository_open(&repository, gitdir))
568 return;
570 CString username;
571 CString useremail;
572 CString autocrlf;
573 CString safecrlf;
575 git_config* config = nullptr;
576 if (!git_repository_config(&config, repository))
578 ReadConfigValue(config, username, "user.name");
579 ReadConfigValue(config, useremail, "user.email");
580 ReadConfigValue(config, autocrlf, "core.autocrlf");
581 ReadConfigValue(config, safecrlf, "core.safecrlf");
584 CString branch;
585 CString remotebranch;
586 if (!git_repository_head_detached(repository))
588 git_reference * head = nullptr;
589 if (git_repository_head_unborn(repository))
591 git_reference_lookup(&head, repository, "HEAD");
592 branch = CUnicodeUtils::GetUnicode(git_reference_symbolic_target(head));
593 if (branch.Find(_T("refs/heads/")) == 0)
594 branch = branch.Mid(11); // 11 = len("refs/heads/")
595 git_reference_free(head);
597 else if (!git_repository_head(&head, repository))
599 const char * branchChar = git_reference_shorthand(head);
600 branch = CUnicodeUtils::GetUnicode(branchChar);
602 const char * branchFullChar = git_reference_name(head);
603 CStringA upstreambranchnameA;
604 if (git_branch_upstream_name(upstreambranchnameA.GetBufferSetLength(4096), 4096, repository, branchFullChar) > 0)
606 upstreambranchnameA.ReleaseBuffer();
607 remotebranch = CUnicodeUtils::GetUnicode(upstreambranchnameA);
608 remotebranch = remotebranch.Mid(13); // 13=len("refs/remotes/")
611 git_reference_free(head);
614 else
615 branch = _T("detached HEAD");
617 if (autocrlf.Trim().IsEmpty())
618 autocrlf = _T("false");
619 if (safecrlf.Trim().IsEmpty())
620 safecrlf = _T("false");
622 SetDlgItemText(m_hwnd,IDC_CONFIG_USERNAME,username.Trim());
623 SetDlgItemText(m_hwnd,IDC_CONFIG_USEREMAIL,useremail.Trim());
624 SetDlgItemText(m_hwnd,IDC_CONFIG_AUTOCRLF,autocrlf.Trim());
625 SetDlgItemText(m_hwnd,IDC_CONFIG_SAFECRLF,safecrlf.Trim());
627 SetDlgItemText(m_hwnd,IDC_SHELL_CURRENT_BRANCH,branch.Trim());
628 SetDlgItemText(m_hwnd,IDC_SHELL_REMOTE_BRANCH, remotebranch);
630 git_oid oid;
631 git_commit *HEADcommit = NULL;
632 if (!git_reference_name_to_id(&oid, repository, "HEAD") && !git_commit_lookup(&HEADcommit, repository, &oid) && HEADcommit != NULL)
634 DisplayCommit(HEADcommit, IDC_HEAD_HASH, IDC_HEAD_SUBJECT, IDC_HEAD_AUTHOR, IDC_HEAD_DATE);
635 git_commit_free(HEADcommit);
639 int stripLength = ProjectTopDir.GetLength();
640 if (ProjectTopDir[stripLength - 1] != _T('\\'))
641 ++stripLength;
643 bool allAreFiles = true;
644 for (auto it = filenames.cbegin(); it < filenames.cend(); ++it)
646 if (PathIsDirectory(it->c_str()))
648 allAreFiles = false;
649 break;
652 if (allAreFiles)
654 size_t assumevalid = 0;
655 size_t skipworktree = 0;
656 size_t executable = 0;
659 git_index *index = NULL;
661 if (git_repository_index(&index, repository))
662 break;
664 for (auto it = filenames.cbegin(); it < filenames.cend(); ++it)
666 CTGitPath file;
667 file.SetFromWin(CString(it->c_str()).Mid(stripLength));
668 CStringA pathA = CUnicodeUtils::GetMulti(file.GetGitPathString(), CP_UTF8);
669 size_t idx;
670 if (!git_index_find(&idx, index, pathA))
672 const git_index_entry *e = git_index_get_byindex(index, idx);
674 if (e->flags & GIT_IDXENTRY_VALID)
675 ++assumevalid;
677 if (e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE)
678 ++skipworktree;
680 if (e->mode & 0111)
681 ++executable;
683 else
685 // do not show checkboxes for unversioned files
686 ShowWindow(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), SW_HIDE);
687 ShowWindow(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), SW_HIDE);
688 ShowWindow(GetDlgItem(m_hwnd, IDC_EXECUTABLE), SW_HIDE);
689 break;
692 git_index_free(index);
693 } while (0);
695 if (assumevalid != 0 && assumevalid != filenames.size())
697 SendMessage(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), BM_SETSTYLE, (DWORD)GetWindowLong(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), GWL_STYLE) & ~BS_AUTOCHECKBOX | BS_AUTO3STATE, 0);
698 SendMessage(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), BM_SETCHECK, BST_INDETERMINATE, 0);
700 else
701 SendMessage(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), BM_SETCHECK, (assumevalid == 0) ? BST_UNCHECKED : BST_CHECKED, 0);
703 if (skipworktree != 0 && skipworktree != filenames.size())
705 SendMessage(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), BM_SETSTYLE, (DWORD)GetWindowLong(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), GWL_STYLE) & ~BS_AUTOCHECKBOX | BS_AUTO3STATE, 0);
706 SendMessage(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), BM_SETCHECK, BST_INDETERMINATE, 0);
708 else
709 SendMessage(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), BM_SETCHECK, (skipworktree == 0) ? BST_UNCHECKED : BST_CHECKED, 0);
711 if (executable != 0 && executable != filenames.size())
713 SendMessage(GetDlgItem(m_hwnd, IDC_EXECUTABLE), BM_SETSTYLE, (DWORD)GetWindowLong(GetDlgItem(m_hwnd, IDC_EXECUTABLE), GWL_STYLE) & ~BS_AUTOCHECKBOX | BS_AUTO3STATE, 0);
714 SendMessage(GetDlgItem(m_hwnd, IDC_EXECUTABLE), BM_SETCHECK, BST_INDETERMINATE, 0);
716 else
717 SendMessage(GetDlgItem(m_hwnd, IDC_EXECUTABLE), BM_SETCHECK, (executable == 0) ? BST_UNCHECKED : BST_CHECKED, 0);
719 else
721 ShowWindow(GetDlgItem(m_hwnd, IDC_ASSUMEVALID), SW_HIDE);
722 ShowWindow(GetDlgItem(m_hwnd, IDC_SKIPWORKTREE), SW_HIDE);
723 ShowWindow(GetDlgItem(m_hwnd, IDC_EXECUTABLE), SW_HIDE);
726 git_repository_free(repository);
728 if (filenames.size() == 1 && !PathIsDirectory(filenames[0].c_str()))
730 SetDlgItemText(m_hwnd, IDC_LAST_SUBJECT, CString(MAKEINTRESOURCE(IDS_LOADING)));
731 _beginthread(LogThreadEntry, 0, this);
733 else
734 ShowWindow(GetDlgItem(m_hwnd, IDC_STATIC_LASTMODIFIED), SW_HIDE);
738 // CShellExt member functions (needed for IShellPropSheetExt)
739 STDMETHODIMP CShellExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
741 __try
743 return AddPages_Wrap(lpfnAddPage, lParam);
745 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
748 return E_FAIL;
751 STDMETHODIMP CShellExt::AddPages_Wrap(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
753 CString ProjectTopDir;
755 for (std::vector<stdstring>::iterator I = files_.begin(); I != files_.end(); ++I)
758 GitStatus svn = GitStatus();
759 if (svn.GetStatus(CTGitPath(I->c_str())) == (-2))
760 return S_OK; // file/directory not under version control
762 if (svn.status->entry == NULL)
763 return S_OK;
765 if( CTGitPath(I->c_str()).HasAdminDir(&ProjectTopDir))
766 break;
767 else
768 return S_OK;
771 if (files_.empty())
772 return S_OK;
774 LoadLangDll();
775 PROPSHEETPAGE psp;
776 SecureZeroMemory(&psp, sizeof(PROPSHEETPAGE));
777 HPROPSHEETPAGE hPage;
778 CGitPropertyPage *sheetpage = new (std::nothrow) CGitPropertyPage(files_);
780 psp.dwSize = sizeof (psp);
781 psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USEICONID | PSP_USECALLBACK;
782 psp.hInstance = g_hResInst;
783 psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE);
784 psp.pszIcon = MAKEINTRESOURCE(IDI_APPSMALL);
785 psp.pszTitle = _T("Git");
786 psp.pfnDlgProc = (DLGPROC) PageProc;
787 psp.lParam = (LPARAM) sheetpage;
788 psp.pfnCallback = PropPageCallbackProc;
789 psp.pcRefParent = (UINT*)&g_cRefThisDll;
791 hPage = CreatePropertySheetPage (&psp);
793 if (hPage != NULL)
795 if (!lpfnAddPage (hPage, lParam))
797 delete sheetpage;
798 DestroyPropertySheetPage (hPage);
802 return S_OK;
805 STDMETHODIMP CShellExt::ReplacePage (UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)
807 return E_FAIL;