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