Initialize more buffers
[TortoiseGit.git] / src / TortoiseShell / GITPropertyPage.cpp
blob215878917c99d01c5e189938a4dd454736ebc826
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 int ret = git_repository_open(&repository, gitdir.GetBuffer());
127 gitdir.ReleaseBuffer();
128 if (ret)
129 break;
131 if (git_repository_index(&index, repository))
133 git_repository_free(repository);
134 break;
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)
145 CTGitPath file;
146 file.SetFromWin(CString(it->c_str()).Mid(stripLength));
147 CStringA pathA = CUnicodeUtils::GetMulti(file.GetGitPathString(), CP_UTF8);
148 size_t idx;
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;
158 changed = true;
161 else if (assumeValid != BST_INDETERMINATE)
163 if (e->flags & GIT_IDXENTRY_VALID)
165 e->flags &= ~GIT_IDXENTRY_VALID;
166 changed = true;
169 if (skipWorktree == BST_CHECKED)
171 if (!(e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE))
173 e->flags_extended |= GIT_IDXENTRY_SKIP_WORKTREE;
174 changed = true;
177 else if (skipWorktree != BST_INDETERMINATE)
179 if (e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE)
181 e->flags_extended &= ~GIT_IDXENTRY_SKIP_WORKTREE;
182 changed = true;
185 if (executable == BST_CHECKED)
187 if (!(e->mode & 0111))
189 e->mode |= 0111;
190 changed = true;
193 else if (executable != BST_INDETERMINATE)
195 if (e->mode & 0111)
197 e->mode &= ~0111;
198 changed = true;
201 if (changed)
202 git_index_add(index, e);
206 if (changed)
208 if (!git_index_write(index))
209 m_bChanged = false;
212 git_index_free(index);
213 } while (0);
215 SetWindowLongPtr (m_hwnd, DWLP_MSGRESULT, FALSE);
216 return TRUE;
218 case WM_DESTROY:
219 return TRUE;
221 case WM_COMMAND:
222 PageProcOnCommand(wParam);
223 break;
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);
229 return TRUE;
232 return FALSE;
234 void CGitPropertyPage::PageProcOnCommand(WPARAM wParam)
236 if(HIWORD(wParam) != BN_CLICKED)
237 return;
239 switch (LOWORD(wParam))
241 case IDC_SHOWLOG:
243 tstring gitCmd = _T(" /command:");
244 gitCmd += _T("log /path:\"");
245 gitCmd += filenames.front().c_str();
246 gitCmd += _T("\"");
247 RunCommand(gitCmd);
249 break;
250 case IDC_SHOWSETTINGS:
252 CTGitPath path(filenames.front().c_str());
253 CString projectTopDir;
254 if(!path.HasAdminDir(&projectTopDir))
255 return;
257 tstring gitCmd = _T(" /command:");
258 gitCmd += _T("settings /path:\"");
259 gitCmd += projectTopDir;
260 gitCmd += _T("\"");
261 RunCommand(gitCmd);
263 break;
264 case IDC_ASSUMEVALID:
265 case IDC_SKIPWORKTREE:
266 case IDC_EXECUTABLE:
267 m_bChanged = true;
268 SendMessage(GetParent(m_hwnd), PSM_CHANGED, (WPARAM)m_hwnd, 0);
269 break;
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
279 return;
282 MessageBox(NULL, CFormatMessageWrapper(), _T("TortoiseGitProc launch failed"), MB_OK | MB_ICONINFORMATION);
285 void CGitPropertyPage::Time64ToTimeString(__time64_t time, TCHAR * buf, size_t buflen)
287 struct tm newtime;
288 SYSTEMTIME systime;
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);
294 *buf = '\0';
295 if (time)
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);
311 else
312 GetDateFormat(locale, DATE_LONGDATE, &systime, NULL, datebuf, MAX_STRING_LENGTH);
313 GetTimeFormat(locale, 0, &systime, NULL, timebuf, MAX_STRING_LENGTH);
314 *buf = '\0';
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
323 const char *folder;
324 const char *name;
325 git_oid oid;
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))
336 return 0;
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));
343 return -1;
346 return 1;
349 return 1;
352 static git_commit * FindFileRecentCommit(git_repository *repository, CString path)
354 git_commit *commit = NULL, *commit2 = NULL;
355 git_revwalk *walk;
356 if (git_revwalk_new(&walk, repository))
357 return NULL;
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, '/');
363 if (slash)
365 strncpy(folder, pathC, slash - pathC + 1);
366 folder[slash - pathC + 1] = '\0';
367 strcpy(file, slash + 1);
369 else
371 folder[0] = '\0';
372 strcpy(file, pathC);
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";
384 git_oid oid;
385 while (!git_revwalk_next(&oid, walk))
387 if (commit != NULL)
389 git_commit_free(commit);
390 commit = NULL;
393 if (git_commit_lookup(&commit, repository, &oid))
395 commit = NULL;
396 throw "git_commit_lookup 1";
399 git_tree *tree;
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);
405 git_tree_free(tree);
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);
413 commit = NULL;
414 break;
417 bool diff = true;
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))
424 commit2 = NULL;
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);
434 git_tree_free(tree);
435 if (ret < 0 && ret != GIT_EUSER)
436 throw "git_tree_walk 2";
438 if (!git_oid_cmp(&treewalkstruct.oid, &treewalkstruct2.oid))
439 diff = false;
440 else if (git_revwalk_hide(walk, git_commit_parent_id(commit, i)))
441 throw "git_revwalk_hide";
444 if (diff)
445 break;
448 catch (...)
450 if (commit != NULL)
452 git_commit_free(commit);
453 commit = NULL;
455 if (commit2 != NULL)
457 git_commit_free(commit2);
458 commit2 = NULL;
462 git_revwalk_free(walk);
463 return commit;
466 void CGitPropertyPage::DisplayCommit(git_commit * commit, UINT hashLabel, UINT subjectLabel, UINT authorLabel, UINT dateLabel)
468 if (commit == NULL)
470 SetDlgItemText(m_hwnd, hashLabel, _T(""));
471 SetDlgItemText(m_hwnd, subjectLabel, _T(""));
472 SetDlgItemText(m_hwnd, authorLabel, _T(""));
473 SetDlgItemText(m_hwnd, dateLabel, _T(""));
474 return;
477 int encode = CP_UTF8;
478 const char * encodingString = git_commit_message_encoding(commit);
479 if (encodingString != NULL)
481 CString str;
482 g_Git.StringAppend(&str, (BYTE*)encodingString, CP_UTF8);
483 encode = CUnicodeUtils::GetCPCode(str);
486 const git_signature * author = git_commit_author(commit);
487 CString authorName;
488 g_Git.StringAppend(&authorName, (BYTE*)author->name, encode);
490 CString message;
491 g_Git.StringAppend(&message, (BYTE*)git_commit_message(commit), encode);
493 int start = 0;
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);
500 CString authorDate;
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))
513 return 0;
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();
520 if (ret)
521 return 0;
523 int stripLength = ProjectTopDir.GetLength();
524 if (ProjectTopDir[stripLength - 1] != _T('\\'))
525 ++stripLength;
527 CTGitPath relatepath;
528 relatepath.SetFromWin(path.GetWinPathString().Mid(stripLength));
530 git_commit *commit = FindFileRecentCommit(repository, relatepath.GetGitPathString());
531 if (commit != NULL)
533 SendMessage(m_hwnd, m_UpdateLastCommit, NULL, (LPARAM)commit);
534 git_commit_free(commit);
536 else
538 SendMessage(m_hwnd, m_UpdateLastCommit, NULL, NULL);
541 git_repository_free(repository);
543 return 0;
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())
561 return;
563 CTGitPath path(filenames.front().c_str());
565 CString ProjectTopDir;
566 if(!path.HasAdminDir(&ProjectTopDir))
567 return;
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();
574 if (ret)
575 return;
577 CString username;
578 CString useremail;
579 CString autocrlf;
580 CString safecrlf;
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");
591 CString branch;
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);
621 else
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);
637 git_oid oid;
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('\\'))
648 ++stripLength;
650 bool allAreFiles = true;
651 for (auto it = filenames.cbegin(); it < filenames.cend(); ++it)
653 if (PathIsDirectory(it->c_str()))
655 allAreFiles = false;
656 break;
659 if (allAreFiles)
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))
669 break;
671 for (auto it = filenames.cbegin(); it < filenames.cend(); ++it)
673 CTGitPath file;
674 file.SetFromWin(CString(it->c_str()).Mid(stripLength));
675 CStringA pathA = CUnicodeUtils::GetMulti(file.GetGitPathString(), CP_UTF8);
676 size_t idx;
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)
682 ++assumevalid;
684 if (e->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE)
685 ++skipworktree;
687 if (e->mode & 0111)
688 ++executable;
690 else
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);
696 break;
699 git_index_free(index);
700 } while (0);
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);
707 else
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);
715 else
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);
723 else
724 SendMessage(GetDlgItem(m_hwnd, IDC_EXECUTABLE), BM_SETCHECK, (executable == 0) ? BST_UNCHECKED : BST_CHECKED, 0);
726 else
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);
740 else
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)
748 __try
750 return AddPages_Wrap(lpfnAddPage, lParam);
752 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
755 return E_FAIL;
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)
770 return S_OK;
772 if( CTGitPath(I->c_str()).HasAdminDir(&ProjectTopDir))
773 break;
774 else
775 return S_OK;
778 if (files_.empty())
779 return S_OK;
781 LoadLangDll();
782 PROPSHEETPAGE psp;
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);
800 if (hPage != NULL)
802 if (!lpfnAddPage (hPage, lParam))
804 delete sheetpage;
805 DestroyPropertySheetPage (hPage);
809 return S_OK;
812 STDMETHODIMP CShellExt::ReplacePage (UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)
814 return E_FAIL;