Improve error handling in GitRev
[TortoiseGit.git] / src / TortoiseProc / GitLogListBase.h
blob28011193521e445c788b36035311cc954aef492e
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.
19 // GitLogList.cpp : implementation file
21 #pragma once
23 #include "HintListCtrl.h"
24 #include "Git.h"
25 #include "ProjectProperties.h"
26 #include "TGitPath.h"
27 #include "registry.h"
28 #include "SplitterControl.h"
29 #include "Colors.h"
30 #include "MenuButton.h"
31 #include "LogDlgHelper.h"
32 #include "FilterEdit.h"
33 #include "GitRevLoglist.h"
34 #include "Tooltip.h"
35 #include "lanes.h"
36 #include "GitLogCache.h"
37 #include <regex>
38 #include "GitStatusListCtrl.h"
39 #include "FindDlg.h"
41 // CGitLogList
42 #define ICONITEMBORDER 5
44 #define GITLOG_START 0
45 #define GITLOG_START_ALL 1
46 #define GITLOG_END 100
48 #define LOGFILTER_ALL 0xFFFF
49 #define LOGFILTER_TOGGLE 0x8000
50 #define LOGFILTER_MESSAGES 0x0001
51 #define LOGFILTER_PATHS 0x0002
52 #define LOGFILTER_AUTHORS 0x0004
53 #define LOGFILTER_REVS 0x0008
54 #define LOGFILTER_REGEX 0x0010
55 #define LOGFILTER_BUGID 0x0020
56 #define LOGFILTER_SUBJECT 0x0040
57 #define LOGFILTER_REFNAME 0x0080
58 #define LOGFILTER_EMAILS 0x0100
59 #define LOGFILTER_CASE 0x0200
61 #define LOGLIST_SHOWNOTHING 0x0000
62 #define LOGLIST_SHOWLOCALBRANCHES 0x0001
63 #define LOGLIST_SHOWREMOTEBRANCHES 0x0002
64 #define LOGLIST_SHOWTAGS 0x0004
65 #define LOGLIST_SHOWSTASH 0x0008
66 #define LOGLIST_SHOWBISECT 0x0010
67 #define LOGLIST_SHOWALLREFS 0xFFFF
69 //typedef void CALLBACK_PROCESS(void * data, int progress);
70 #define MSG_LOADED (WM_USER+110)
71 #define MSG_LOAD_PERCENTAGE (WM_USER+111)
72 #define MSG_REFLOG_CHANGED (WM_USER+112)
73 #define MSG_FETCHED_DIFF (WM_USER+113)
75 class SelectionHistory
77 #define HISTORYLENGTH 50
78 public:
79 SelectionHistory(void)
80 : location(0)
82 lastselected.reserve(HISTORYLENGTH);
84 void Add(CGitHash &hash)
86 if (hash.IsEmpty())
87 return;
89 size_t size = lastselected.size();
91 // re-select last selected commit
92 if (size > 0 && hash == lastselected[size - 1])
94 // reset location
95 if (location != size - 1)
96 location = size - 1;
97 return;
100 // go back and some commit was highlight
101 if (size > 0 && location != size - 1)
103 // Re-select current one, it may be a forked point.
104 if (hash == lastselected[location])
105 // Discard it later.
106 // That is that discarding forward history when a forked entry is really coming.
107 // And user has the chance to Go Forward again in this situation.
108 // IOW, (hash != lastselected[location]) means user wants a forked history,
109 // and this change saves one step from old behavior.
110 return;
112 // Discard forward history if any
113 while (lastselected.size() - 1 > location)
114 lastselected.pop_back();
117 if (lastselected.size() >= HISTORYLENGTH)
118 lastselected.erase(lastselected.cbegin());
120 lastselected.push_back(hash);
121 location = lastselected.size() - 1;
123 BOOL GoBack(CGitHash& historyEntry)
125 if (location < 1)
126 return FALSE;
128 historyEntry = lastselected[--location];
130 return TRUE;
132 BOOL GoForward(CGitHash& historyEntry)
134 if (location >= lastselected.size() - 1)
135 return FALSE;
137 historyEntry = lastselected[++location];
139 return TRUE;
141 private:
142 std::vector<CGitHash> lastselected;
143 size_t location;
146 class CThreadSafePtrArray: public CPtrArray
148 CComCriticalSection *m_critSec;
149 public:
150 CThreadSafePtrArray(CComCriticalSection *section){ m_critSec = section ;}
151 void * SafeGetAt(INT_PTR i)
153 if(m_critSec)
154 m_critSec->Lock();
156 if( i<0 || i>=GetCount())
158 if(m_critSec)
159 m_critSec->Unlock();
161 return NULL;
164 if(m_critSec)
165 m_critSec->Unlock();
167 return GetAt(i);
169 INT_PTR SafeAdd(void *newElement)
171 INT_PTR ret;
172 if(m_critSec)
173 m_critSec->Lock();
174 ret = Add(newElement);
175 if(m_critSec)
176 m_critSec->Unlock();
177 return ret;
180 void SafeRemoveAll()
182 if(m_critSec)
183 m_critSec->Lock();
184 RemoveAll();
185 if(m_critSec)
186 m_critSec->Unlock();
191 class CGitLogListBase : public CHintListCtrl
193 DECLARE_DYNAMIC(CGitLogListBase)
195 public:
196 CGitLogListBase();
197 virtual ~CGitLogListBase();
198 ProjectProperties m_ProjectProperties;
200 CFilterData m_Filter;
202 void UpdateProjectProperties()
204 m_ProjectProperties.ReadProps();
206 if ((!m_ProjectProperties.sUrl.IsEmpty())||(!m_ProjectProperties.sCheckRe.IsEmpty()))
207 m_bShowBugtraqColumn = true;
208 else
209 m_bShowBugtraqColumn = false;
212 void ResetWcRev(bool refresh = false)
214 m_wcRev.Clear();
215 m_wcRev.GetSubject() = CString(MAKEINTRESOURCE(IDS_LOG_WORKINGDIRCHANGES));
216 m_wcRev.m_Mark = _T('-');
217 m_wcRev.GetBody() = CString(MAKEINTRESOURCE(IDS_LOG_FETCHINGSTATUS));
218 m_wcRev.m_CallDiffAsync = DiffAsync;
219 InterlockedExchange(&m_wcRev.m_IsDiffFiles, FALSE);
220 if (refresh && m_bShowWC)
221 m_arShownList[0] = &m_wcRev;
224 volatile LONG m_bNoDispUpdates;
225 BOOL m_IsIDReplaceAction;
226 BOOL m_IsOldFirst;
227 void hideFromContextMenu(unsigned __int64 hideMask, bool exclusivelyShow);
228 BOOL m_IsRebaseReplaceGraph;
229 BOOL m_bNoHightlightHead;
231 void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
233 BOOL m_bStrictStopped;
234 BOOL m_bShowBugtraqColumn;
235 BOOL m_bSearchIndex;
236 BOOL m_bCancelled;
237 unsigned __int64 m_ContextMenuMask;
239 bool m_hasWC;
240 bool m_bShowWC;
241 GitRevLoglist m_wcRev;
242 volatile LONG m_bThreadRunning;
243 CLogCache m_LogCache;
245 CString m_sRange;
246 // don't forget to bump BLAME_COLUMN_VERSION in GitStatusListCtrlHelpers.cpp if you change columns
247 enum
249 LOGLIST_GRAPH,
250 LOGLIST_REBASE,
251 LOGLIST_ID,
252 LOGLIST_HASH,
253 LOGLIST_ACTION,
254 LOGLIST_MESSAGE,
255 LOGLIST_AUTHOR,
256 LOGLIST_DATE,
257 LOGLIST_EMAIL,
258 LOGLIST_COMMIT_NAME,
259 LOGLIST_COMMIT_EMAIL,
260 LOGLIST_COMMIT_DATE,
261 LOGLIST_BUG,
262 LOGLIST_SVNREV,
263 LOGLIST_MESSAGE_MAX=300,
264 LOGLIST_MESSAGE_MIN=200,
266 GIT_LOG_GRAPH = 1<< LOGLIST_GRAPH,
267 GIT_LOG_REBASE = 1<< LOGLIST_REBASE,
268 GIT_LOG_ID = 1<< LOGLIST_ID,
269 GIT_LOG_HASH = 1<< LOGLIST_HASH,
270 GIT_LOG_ACTIONS = 1<< LOGLIST_ACTION,
271 GIT_LOG_MESSAGE = 1<< LOGLIST_MESSAGE,
272 GIT_LOG_AUTHOR = 1<< LOGLIST_AUTHOR,
273 GIT_LOG_DATE = 1<< LOGLIST_DATE,
274 GIT_LOG_EMAIL = 1<< LOGLIST_EMAIL,
275 GIT_LOG_COMMIT_NAME = 1<< LOGLIST_COMMIT_NAME,
276 GIT_LOG_COMMIT_EMAIL= 1<< LOGLIST_COMMIT_EMAIL,
277 GIT_LOG_COMMIT_DATE = 1<< LOGLIST_COMMIT_DATE,
278 GIT_LOGLIST_BUG = 1<< LOGLIST_BUG,
279 GIT_LOGLIST_SVNREV = 1<< LOGLIST_SVNREV,
282 enum
284 // needs to start with 1, since 0 is the return value if *nothing* is clicked on in the context menu
285 ID_COMPARE = 1, // compare revision with WC
286 ID_SAVEAS,
287 ID_COMPARETWO, // compare two revisions
288 ID_COPY,
289 ID_REVERTREV,
290 ID_MERGEREV,
291 ID_GNUDIFF1, // compare with WC, unified
292 ID_GNUDIFF2, // compare two revisions, unified
293 ID_FINDENTRY,
294 ID_OPEN,
295 ID_BLAME,
296 ID_REPOBROWSE,
297 ID_LOG,
298 ID_EDITNOTE,
299 ID_DIFF,
300 ID_OPENWITH,
301 ID_COPYCLIPBOARD,
302 ID_COPYHASH,
303 ID_REVERTTOREV,
304 ID_BLAMECOMPARE,
305 ID_BLAMEDIFF,
306 ID_VIEWREV,
307 ID_VIEWPATHREV,
308 ID_EXPORT,
309 ID_COMPAREWITHPREVIOUS,
310 ID_BLAMEPREVIOUS,
311 ID_CHERRY_PICK,
312 ID_CREATE_BRANCH,
313 ID_CREATE_TAG,
314 ID_SWITCHTOREV,
315 ID_SWITCHBRANCH,
316 ID_RESET,
317 ID_REBASE_PICK,
318 ID_REBASE_EDIT,
319 ID_REBASE_SQUASH,
320 ID_REBASE_SKIP,
321 ID_COMBINE_COMMIT,
322 ID_STASH_SAVE,
323 ID_STASH_LIST,
324 ID_STASH_POP,
325 ID_REFLOG_STASH_APPLY,
326 ID_REFLOG_DEL,
327 ID_REBASE_TO_VERSION,
328 ID_CREATE_PATCH,
329 ID_DELETE,
330 ID_COMMIT,
331 ID_PUSH,
332 ID_PULL,
333 ID_FETCH,
334 ID_SHOWBRANCHES,
335 ID_COPYCLIPBOARDMESSAGES,
336 ID_BISECTSTART,
337 ID_LOG_VIEWRANGE,
338 ID_LOG_VIEWRANGE_REACHABLEFROMONLYONE,
339 ID_MERGE_ABORT,
340 ID_CLEANUP,
341 ID_SUBMODULE_UPDATE,
343 enum
345 ID_COPY_ALL,
346 ID_COPY_MESSAGE,
347 ID_COPY_SUBJECT,
348 ID_COPY_HASH,
350 enum FilterShow
352 FILTERSHOW_REFS = 1,
353 FILTERSHOW_MERGEPOINTS = 2,
354 FILTERSHOW_ANYCOMMIT = 4,
355 FILTERSHOW_ALL = FILTERSHOW_ANYCOMMIT | FILTERSHOW_REFS | FILTERSHOW_MERGEPOINTS
357 enum : unsigned int
359 // For Rebase only
360 LOGACTIONS_REBASE_CURRENT = 0x08000000,
361 LOGACTIONS_REBASE_PICK = 0x04000000,
362 LOGACTIONS_REBASE_SQUASH = 0x02000000,
363 LOGACTIONS_REBASE_EDIT = 0x01000000,
364 LOGACTIONS_REBASE_DONE = 0x00800000,
365 LOGACTIONS_REBASE_SKIP = 0x00400000,
366 LOGACTIONS_REBASE_MASK = 0x0FC00000,
367 LOGACTIONS_REBASE_MODE_MASK = 0x07C00000,
369 inline unsigned __int64 GetContextMenuBit(int i){ return ((unsigned __int64 )0x1)<<i ;}
370 static CString GetRebaseActionName(int action);
371 void InsertGitColumn();
372 void ResizeAllListCtrlCols();
373 void CopySelectionToClipBoard(int toCopy = ID_COPY_ALL);
374 void DiffSelectedRevWithPrevious();
375 bool IsSelectionContinuous();
376 int BeginFetchLog();
377 int FillGitLog(CTGitPath *path, CString *range = NULL, int infomask = CGit::LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
378 int FillGitLog(std::set<CGitHash>& hashes);
379 BOOL IsMatchFilter(bool bRegex, GitRevLoglist* pRev, std::tr1::wregex& pat);
380 bool ShouldShowFilter(GitRevLoglist* pRev, const std::map<CGitHash, std::set<CGitHash>>& commitChildren);
381 void ShowGraphColumn(bool bShow);
382 CString GetTagInfo(GitRev* pLogEntry);
384 CFindDlg *m_pFindDialog;
385 static const UINT m_FindDialogMessage;
386 void OnFind();
388 static const UINT m_ScrollToMessage;
389 static const UINT m_RebaseActionMessage;
391 inline int ShownCountWithStopped() const { return (int)m_arShownList.GetCount() + (m_bStrictStopped ? 1 : 0); }
392 int FetchLogAsync(void * data=NULL);
393 CThreadSafePtrArray m_arShownList;
394 void Refresh(BOOL IsCleanFilter=TRUE);
395 void RecalculateShownList(CThreadSafePtrArray * pShownlist);
396 void Clear();
398 DWORD m_SelectedFilters;
399 FilterShow m_ShowFilter;
400 bool m_bFilterWithRegex;
401 bool m_bFilterCaseSensitively;
402 CLogDataVector m_logEntries;
403 void RemoveFilter();
404 void StartFilter();
405 bool ValidateRegexp(LPCTSTR regexp_str, std::tr1::wregex& pat, bool bMatchCase = false );
406 CString m_sFilterText;
408 __time64_t m_From;
409 __time64_t m_To;
411 CTGitPath m_Path;
412 int m_ShowMask;
413 CGitHash m_lastSelectedHash;
414 SelectionHistory m_selectionHistory;
415 CGitHash m_highlight;
416 int m_ShowRefMask;
418 void GetTimeRange(CTime &oldest,CTime &latest);
419 virtual void GetParentHashes(GitRev* pRev, GIT_REV_LIST& parentHash);
420 virtual void ContextMenuAction(int cmd,int FirstSelect, int LastSelect, CMenu * menu)=0;
421 void ReloadHashMap()
423 m_HashMap.clear();
425 if (g_Git.GetMapHashToFriendName(m_HashMap))
426 MessageBox(g_Git.GetGitLastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR);
428 m_CurrentBranch=g_Git.GetCurrentBranch();
430 if (g_Git.GetHash(m_HeadHash, _T("HEAD")))
432 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash. Quitting...")), _T("TortoiseGit"), MB_ICONERROR);
433 ExitProcess(1);
436 m_wcRev.m_ParentHash.clear();
437 m_wcRev.m_ParentHash.push_back(m_HeadHash);
439 FetchRemoteList();
440 FetchTrackingBranchList();
442 void SafeTerminateThread()
444 if (m_LoadingThread!=NULL && InterlockedExchange(&m_bExitThread, TRUE) == FALSE)
446 DWORD ret = WAIT_TIMEOUT;
447 for (int i = 0; i < 200 && m_bThreadRunning; ++i)
448 ret =::WaitForSingleObject(m_LoadingThread->m_hThread, 100);
449 if (ret == WAIT_TIMEOUT && m_bThreadRunning)
450 ::TerminateThread(m_LoadingThread, 0);
451 m_LoadingThread = NULL;
455 bool IsInWorkingThread()
457 return (AfxGetThread() == m_LoadingThread);
460 void SetRange(const CString& range)
462 m_sRange = range;
465 CString GetRange() const { return m_sRange; }
467 bool HasFilterText() const { return !m_sFilterText.IsEmpty() && m_sFilterText != _T("!"); }
469 int m_nSearchIndex;
471 volatile LONG m_bExitThread;
472 CWinThread* m_LoadingThread;
473 MAP_HASH_NAME m_HashMap;
474 std::map<CString, std::pair<CString, CString>> m_TrackingMap;
476 public:
477 CString m_ColumnRegKey;
478 CComCriticalSection m_critSec_AsyncDiff;
480 protected:
481 typedef struct {
482 CString name;
483 COLORREF color;
484 CString simplifiedName;
485 bool singleRemote;
486 bool hasTracking;
487 bool sameName;
488 bool annotatedTag;
489 } REFLABEL;
491 DECLARE_MESSAGE_MAP()
492 afx_msg void OnDestroy();
493 virtual afx_msg void OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult);
494 virtual afx_msg void OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult);
495 afx_msg LRESULT OnFindDialogMessage(WPARAM wParam, LPARAM lParam);
496 afx_msg LRESULT OnScrollToMessage(WPARAM wParam, LPARAM lParam);
497 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
498 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
499 afx_msg LRESULT OnLoad(WPARAM wParam, LPARAM lParam);
500 afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);
501 afx_msg void OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
502 afx_msg void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult);
503 afx_msg void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult);
504 void OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult);
505 afx_msg void OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult);
506 void PreSubclassWindow();
507 virtual BOOL PreTranslateMessage(MSG* pMsg);
508 static UINT LogThreadEntry(LPVOID pVoid);
509 UINT LogThread();
510 bool IsOnStash(int index);
511 bool IsStash(const GitRev * pSelLogEntry);
512 void FetchRemoteList();
513 void FetchTrackingBranchList();
514 void FetchLastLogInfo();
515 void FetchFullLogInfo(CString &from, CString &to);
517 virtual afx_msg BOOL OnToolTipText(UINT id, NMHDR * pNMHDR, LRESULT * pResult);
518 virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO * pTI) const;
519 CString GetToolTipText(int nItem, int nSubItem);
521 void FillBackGround(HDC hdc, DWORD_PTR Index, CRect &rect);
522 void DrawTagBranchMessage(HDC hdc, CRect &rect, INT_PTR index, std::vector<REFLABEL> &refList);
523 void DrawTagBranch(HDC hdc, CDC& W_Dc, HTHEME hTheme, CRect& rect, CRect& rt, LVITEM& rItem, GitRevLoglist* data, std::vector<REFLABEL>& refList);
524 void DrawGraph(HDC,CRect &rect,INT_PTR index);
526 void paintGraphLane(HDC hdc,int laneHeight, int type, int x1, int x2,
527 const COLORREF& col,const COLORREF& activeColor, int top) ;
528 void DrawLine(HDC hdc, int x1, int y1, int x2, int y2){::MoveToEx(hdc,x1,y1,NULL);::LineTo(hdc,x2,y2);}
530 * Save column widths to the registry
532 void SaveColumnWidths(); // save col widths to the registry
534 BOOL IsEntryInDateRange(int i);
536 int GetHeadIndex();
538 std::vector<GitRevLoglist*> m_AsynDiffList;
539 CComCriticalSection m_AsynDiffListLock;
540 HANDLE m_AsyncDiffEvent;
541 volatile LONG m_AsyncThreadExit;
542 CWinThread* m_DiffingThread;
544 static int DiffAsync(GitRevLoglist* rev, void* data)
546 ULONGLONG offset=((CGitLogListBase*)data)->m_LogCache.GetOffset(rev->m_CommitHash);
547 if(!offset)
549 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
550 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
551 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
552 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
554 else
556 if(((CGitLogListBase*)data)->m_LogCache.LoadOneItem(*rev,offset))
558 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
559 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
560 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
561 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
563 InterlockedExchange(&rev->m_IsDiffFiles, TRUE);
564 if(rev->m_IsDiffFiles && rev->m_IsCommitParsed)
565 InterlockedExchange(&rev->m_IsFull, TRUE);
567 return 0;
570 static UINT AsyncThread(LPVOID data)
572 return ((CGitLogListBase*)data)->AsyncDiffThread();
575 int AsyncDiffThread();
576 bool m_AsyncThreadExited;
578 public:
579 void SafeTerminateAsyncDiffThread()
581 if(m_DiffingThread!=NULL && m_AsyncThreadExit != TRUE)
583 m_AsyncThreadExit = TRUE;
584 ::SetEvent(m_AsyncDiffEvent);
585 DWORD ret = WAIT_TIMEOUT;
586 // do not block here, but process messages and ask until the thread ends
587 while (ret == WAIT_TIMEOUT && !m_AsyncThreadExited)
589 MSG msg;
590 if (::PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE))
591 AfxGetThread()->PumpMessage(); // process messages, so that GetTopIndex and so on in the thread work
592 ret = ::WaitForSingleObject(m_DiffingThread->m_hThread, 100);
594 m_DiffingThread = NULL;
598 protected:
599 CComCriticalSection m_critSec;
601 HICON m_hModifiedIcon;
602 HICON m_hReplacedIcon;
603 HICON m_hAddedIcon;
604 HICON m_hDeletedIcon;
605 HICON m_hFetchIcon;
607 HFONT m_boldFont;
608 HFONT m_FontItalics;
609 HFONT m_boldItalicsFont;
611 CRegDWORD m_regMaxBugIDColWidth;
613 void *m_ProcData;
614 CStoreSelection* m_pStoreSelection;
616 CColors m_Colors;
618 CString m_CurrentBranch;
619 CGitHash m_HeadHash;
621 COLORREF m_LineColors[Lanes::COLORS_NUM];
622 DWORD m_LineWidth;
623 DWORD m_NodeSize;
624 DWORD m_DateFormat; // DATE_SHORTDATE or DATE_LONGDATE
625 bool m_bRelativeTimes; // Show relative times
626 GIT_LOG m_DllGitLog;
627 CString m_SingleRemote;
628 bool m_bTagsBranchesOnRightSide;
629 bool m_bSymbolizeRefNames;
630 bool m_bIncludeBoundaryCommits;
632 ColumnManager m_ColumnManager;
633 DWORD m_dwDefaultColumns;
635 typedef HRESULT (WINAPI *FNDRAWTHEMETEXTEX) (HTHEME, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const DTTOPTS *);
636 HMODULE hUxTheme;
637 FNDRAWTHEMETEXTEX pfnDrawThemeTextEx;
638 TCHAR m_wszTip[8192];
639 char m_szTip[8192];