Make sure buffer is large enough for the nul terminator
[TortoiseGit.git] / src / TortoiseProc / GitLogListBase.h
blob3ea3c77b39afbe6d25dda3e3df444eb6dda023d7
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 BOOL IsMatchFilter(bool bRegex, GitRevLoglist* pRev, std::tr1::wregex& pat);
376 bool ShouldShowFilter(GitRevLoglist* pRev, const std::map<CGitHash, std::set<CGitHash>>& commitChildren);
377 void ShowGraphColumn(bool bShow);
378 CString GetTagInfo(GitRev* pLogEntry);
380 CFindDlg *m_pFindDialog;
381 static const UINT m_FindDialogMessage;
382 void OnFind();
384 static const UINT m_ScrollToMessage;
385 static const UINT m_RebaseActionMessage;
387 inline int ShownCountWithStopped() const { return (int)m_arShownList.GetCount() + (m_bStrictStopped ? 1 : 0); }
388 int FetchLogAsync(void * data=NULL);
389 CThreadSafePtrArray m_arShownList;
390 void Refresh(BOOL IsCleanFilter=TRUE);
391 void RecalculateShownList(CThreadSafePtrArray * pShownlist);
392 void Clear();
394 DWORD m_SelectedFilters;
395 FilterShow m_ShowFilter;
396 bool m_bFilterWithRegex;
397 bool m_bFilterCaseSensitively;
398 CLogDataVector m_logEntries;
399 void RemoveFilter();
400 void StartFilter();
401 bool ValidateRegexp(LPCTSTR regexp_str, std::tr1::wregex& pat, bool bMatchCase = false );
402 CString m_sFilterText;
404 __time64_t m_From;
405 __time64_t m_To;
407 CTGitPath m_Path;
408 int m_ShowMask;
409 CGitHash m_lastSelectedHash;
410 SelectionHistory m_selectionHistory;
411 CGitHash m_highlight;
412 int m_ShowRefMask;
414 void GetTimeRange(CTime &oldest,CTime &latest);
415 virtual void GetParentHashes(GitRev* pRev, GIT_REV_LIST& parentHash);
416 virtual void ContextMenuAction(int cmd,int FirstSelect, int LastSelect, CMenu * menu)=0;
417 void ReloadHashMap()
419 m_HashMap.clear();
421 if (g_Git.GetMapHashToFriendName(m_HashMap))
422 MessageBox(g_Git.GetGitLastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR);
424 m_CurrentBranch=g_Git.GetCurrentBranch();
426 if (g_Git.GetHash(m_HeadHash, _T("HEAD")))
428 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash. Quitting...")), _T("TortoiseGit"), MB_ICONERROR);
429 ExitProcess(1);
432 m_wcRev.m_ParentHash.clear();
433 m_wcRev.m_ParentHash.push_back(m_HeadHash);
435 FetchRemoteList();
436 FetchTrackingBranchList();
438 void SafeTerminateThread()
440 if (m_LoadingThread!=NULL && InterlockedExchange(&m_bExitThread, TRUE) == FALSE)
442 DWORD ret = WAIT_TIMEOUT;
443 for (int i = 0; i < 200 && m_bThreadRunning; ++i)
444 ret =::WaitForSingleObject(m_LoadingThread->m_hThread, 100);
445 if (ret == WAIT_TIMEOUT && m_bThreadRunning)
446 ::TerminateThread(m_LoadingThread, 0);
447 m_LoadingThread = NULL;
451 bool IsInWorkingThread()
453 return (AfxGetThread() == m_LoadingThread);
456 void SetRange(const CString& range)
458 m_sRange = range;
461 CString GetRange() const { return m_sRange; }
463 bool HasFilterText() const { return !m_sFilterText.IsEmpty() && m_sFilterText != _T("!"); }
465 int m_nSearchIndex;
467 volatile LONG m_bExitThread;
468 CWinThread* m_LoadingThread;
469 MAP_HASH_NAME m_HashMap;
470 std::map<CString, std::pair<CString, CString>> m_TrackingMap;
472 public:
473 CString m_ColumnRegKey;
474 CComCriticalSection m_critSec_AsyncDiff;
476 protected:
477 typedef struct {
478 CString name;
479 COLORREF color;
480 CString simplifiedName;
481 bool singleRemote;
482 bool hasTracking;
483 bool sameName;
484 bool annotatedTag;
485 } REFLABEL;
487 DECLARE_MESSAGE_MAP()
488 afx_msg void OnDestroy();
489 virtual afx_msg void OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult);
490 virtual afx_msg void OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult);
491 afx_msg LRESULT OnFindDialogMessage(WPARAM wParam, LPARAM lParam);
492 afx_msg LRESULT OnScrollToMessage(WPARAM wParam, LPARAM lParam);
493 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
494 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
495 afx_msg LRESULT OnLoad(WPARAM wParam, LPARAM lParam);
496 afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);
497 afx_msg void OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
498 afx_msg void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult);
499 afx_msg void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult);
500 void OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult);
501 afx_msg void OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult);
502 void PreSubclassWindow();
503 virtual BOOL PreTranslateMessage(MSG* pMsg);
504 static UINT LogThreadEntry(LPVOID pVoid);
505 UINT LogThread();
506 bool IsOnStash(int index);
507 bool IsStash(const GitRev * pSelLogEntry);
508 void FetchRemoteList();
509 void FetchTrackingBranchList();
510 void FetchLastLogInfo();
511 void FetchFullLogInfo(CString &from, CString &to);
513 virtual afx_msg BOOL OnToolTipText(UINT id, NMHDR * pNMHDR, LRESULT * pResult);
514 virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO * pTI) const;
515 CString GetToolTipText(int nItem, int nSubItem);
517 void FillBackGround(HDC hdc, DWORD_PTR Index, CRect &rect);
518 void DrawTagBranchMessage(HDC hdc, CRect &rect, INT_PTR index, std::vector<REFLABEL> &refList);
519 void DrawTagBranch(HDC hdc, CDC& W_Dc, HTHEME hTheme, CRect& rect, CRect& rt, LVITEM& rItem, GitRevLoglist* data, std::vector<REFLABEL>& refList);
520 void DrawGraph(HDC,CRect &rect,INT_PTR index);
522 void paintGraphLane(HDC hdc,int laneHeight, int type, int x1, int x2,
523 const COLORREF& col,const COLORREF& activeColor, int top) ;
524 void DrawLine(HDC hdc, int x1, int y1, int x2, int y2){::MoveToEx(hdc,x1,y1,NULL);::LineTo(hdc,x2,y2);}
526 * Save column widths to the registry
528 void SaveColumnWidths(); // save col widths to the registry
530 BOOL IsEntryInDateRange(int i);
532 int GetHeadIndex();
534 std::vector<GitRevLoglist*> m_AsynDiffList;
535 CComCriticalSection m_AsynDiffListLock;
536 HANDLE m_AsyncDiffEvent;
537 volatile LONG m_AsyncThreadExit;
538 CWinThread* m_DiffingThread;
540 static int DiffAsync(GitRevLoglist* rev, void* data)
542 ULONGLONG offset=((CGitLogListBase*)data)->m_LogCache.GetOffset(rev->m_CommitHash);
543 if(!offset)
545 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
546 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
547 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
548 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
550 else
552 if(((CGitLogListBase*)data)->m_LogCache.LoadOneItem(*rev,offset))
554 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
555 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
556 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
557 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
559 InterlockedExchange(&rev->m_IsDiffFiles, TRUE);
560 if(rev->m_IsDiffFiles && rev->m_IsCommitParsed)
561 InterlockedExchange(&rev->m_IsFull, TRUE);
563 return 0;
566 static UINT AsyncThread(LPVOID data)
568 return ((CGitLogListBase*)data)->AsyncDiffThread();
571 int AsyncDiffThread();
572 bool m_AsyncThreadExited;
574 public:
575 void SafeTerminateAsyncDiffThread()
577 if(m_DiffingThread!=NULL && m_AsyncThreadExit != TRUE)
579 m_AsyncThreadExit = TRUE;
580 ::SetEvent(m_AsyncDiffEvent);
581 DWORD ret = WAIT_TIMEOUT;
582 // do not block here, but process messages and ask until the thread ends
583 while (ret == WAIT_TIMEOUT && !m_AsyncThreadExited)
585 MSG msg;
586 if (::PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE))
587 AfxGetThread()->PumpMessage(); // process messages, so that GetTopIndex and so on in the thread work
588 ret = ::WaitForSingleObject(m_DiffingThread->m_hThread, 100);
590 m_DiffingThread = NULL;
594 protected:
595 CComCriticalSection m_critSec;
597 HICON m_hModifiedIcon;
598 HICON m_hReplacedIcon;
599 HICON m_hConflictedIcon;
600 HICON m_hAddedIcon;
601 HICON m_hDeletedIcon;
602 HICON m_hFetchIcon;
604 HFONT m_boldFont;
605 HFONT m_FontItalics;
606 HFONT m_boldItalicsFont;
608 CRegDWORD m_regMaxBugIDColWidth;
610 void *m_ProcData;
611 CStoreSelection* m_pStoreSelection;
613 CColors m_Colors;
615 CString m_CurrentBranch;
616 CGitHash m_HeadHash;
618 COLORREF m_LineColors[Lanes::COLORS_NUM];
619 DWORD m_LineWidth;
620 DWORD m_NodeSize;
621 DWORD m_DateFormat; // DATE_SHORTDATE or DATE_LONGDATE
622 bool m_bRelativeTimes; // Show relative times
623 GIT_LOG m_DllGitLog;
624 CString m_SingleRemote;
625 bool m_bTagsBranchesOnRightSide;
626 bool m_bSymbolizeRefNames;
627 bool m_bIncludeBoundaryCommits;
629 ColumnManager m_ColumnManager;
630 DWORD m_dwDefaultColumns;
632 typedef HRESULT (WINAPI *FNDRAWTHEMETEXTEX) (HTHEME, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const DTTOPTS *);
633 HMODULE hUxTheme;
634 FNDRAWTHEMETEXTEX pfnDrawThemeTextEx;
635 TCHAR m_wszTip[8192];
636 char m_szTip[8192];