Use correct function
[TortoiseGit.git] / src / TortoiseProc / GitLogListBase.h
blob1a031caabde0426ba32a63d86931e3cc35a17243
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2012 - 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 "GitRev.h"
34 #include "Tooltip.h"
35 //#include "GitLogList.h"
36 #include "lanes.h"
37 #include "GitLogCache.h"
38 #include <regex>
39 #include <GitStatusListCtrl.h>
40 #include "FindDlg.h"
42 // CGitLogList
43 #if (NTDDI_VERSION < NTDDI_LONGHORN)
45 enum LISTITEMSTATES_MINE {
46 LISS_NORMAL = 1,
47 LISS_HOT = 2,
48 LISS_SELECTED = 3,
49 LISS_DISABLED = 4,
50 LISS_SELECTEDNOTFOCUS = 5,
51 LISS_HOTSELECTED = 6,
54 // these defines must be in the order the columns are inserted!
57 #define MCS_NOTRAILINGDATES 0x0040
58 #define MCS_SHORTDAYSOFWEEK 0x0080
59 #define MCS_NOSELCHANGEONNAV 0x0100
61 #define DTM_SETMCSTYLE (DTM_FIRST + 11)
63 #endif
65 #define ICONITEMBORDER 5
67 #define GITLOG_START 0
68 #define GITLOG_START_ALL 1
69 #define GITLOG_END 100
71 #define LOGFILTER_ALL 0xFFFF
72 #define LOGFILTER_MESSAGES 0x0001
73 #define LOGFILTER_PATHS 0x0002
74 #define LOGFILTER_AUTHORS 0x0004
75 #define LOGFILTER_REVS 0x0008
76 #define LOGFILTER_REGEX 0x0010
77 #define LOGFILTER_BUGID 0x0020
78 #define LOGFILTER_SUBJECT 0x0040
79 #define LOGFILTER_REFNAME 0x0080 // only used in RefBrowser so far
81 //typedef void CALLBACK_PROCESS(void * data, int progress);
82 #define MSG_LOADED (WM_USER+110)
83 #define MSG_LOAD_PERCENTAGE (WM_USER+111)
84 #define MSG_REFLOG_CHANGED (WM_USER+112)
85 #define MSG_FETCHED_DIFF (WM_USER+113)
87 class CThreadSafePtrArray: public CPtrArray
89 CComCriticalSection *m_critSec;
90 public:
91 CThreadSafePtrArray(CComCriticalSection *section){ m_critSec = section ;}
92 void * SafeGetAt(INT_PTR i)
94 if(m_critSec)
95 m_critSec->Lock();
97 if( i<0 || i>=GetCount())
99 if(m_critSec)
100 m_critSec->Unlock();
102 return NULL;
105 if(m_critSec)
106 m_critSec->Unlock();
108 return GetAt(i);
110 INT_PTR SafeAdd(void *newElement)
112 INT_PTR ret;
113 if(m_critSec)
114 m_critSec->Lock();
115 ret = Add(newElement);
116 if(m_critSec)
117 m_critSec->Unlock();
118 return ret;
121 void SafeRemoveAll()
123 if(m_critSec)
124 m_critSec->Lock();
125 RemoveAll();
126 if(m_critSec)
127 m_critSec->Unlock();
132 class CGitLogListBase : public CHintListCtrl
134 DECLARE_DYNAMIC(CGitLogListBase)
136 public:
137 CGitLogListBase();
138 virtual ~CGitLogListBase();
139 ProjectProperties m_ProjectProperties;
141 CFilterData m_Filter;
143 void UpdateProjectProperties()
145 m_ProjectProperties.ReadProps(this->m_Path);
147 if ((!m_ProjectProperties.sUrl.IsEmpty())||(!m_ProjectProperties.sCheckRe.IsEmpty()))
148 m_bShowBugtraqColumn = true;
149 else
150 m_bShowBugtraqColumn = false;
153 void ResetWcRev(bool refresh = false)
155 m_wcRev.Clear();
156 m_wcRev.GetSubject() = CString(MAKEINTRESOURCE(IDS_LOG_WORKINGDIRCHANGES));
157 m_wcRev.m_Mark = _T('-');
158 m_wcRev.GetBody() = CString(MAKEINTRESOURCE(IDS_LOG_FETCHINGSTATUS));
159 m_wcRev.m_CallDiffAsync = DiffAsync;
160 InterlockedExchange(&m_wcRev.m_IsDiffFiles, FALSE);
161 if (refresh && m_bShowWC)
162 m_arShownList[0] = &m_wcRev;
164 void SetProjectPropertiesPath(const CTGitPath& path) {m_ProjectProperties.ReadProps(path);}
166 volatile LONG m_bNoDispUpdates;
167 BOOL m_IsIDReplaceAction;
168 BOOL m_IsOldFirst;
169 void hideFromContextMenu(unsigned __int64 hideMask, bool exclusivelyShow);
170 BOOL m_IsRebaseReplaceGraph;
171 BOOL m_bNoHightlightHead;
173 void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
175 BOOL m_bStrictStopped;
176 BOOL m_bShowBugtraqColumn;
177 BOOL m_bSearchIndex;
178 BOOL m_bCancelled;
179 unsigned __int64 m_ContextMenuMask;
181 bool m_hasWC;
182 bool m_bShowWC;
183 GitRev m_wcRev;
184 volatile LONG m_bThreadRunning;
185 CLogCache m_LogCache;
187 CString m_startrev;
188 CString m_endrev;
190 // don't forget to bump BLAME_COLUMN_VERSION in GitStatusListCtrlHelpers.cpp if you change columns
191 enum
193 LOGLIST_GRAPH,
194 LOGLIST_REBASE,
195 LOGLIST_ID,
196 LOGLIST_HASH,
197 LOGLIST_ACTION,
198 LOGLIST_MESSAGE,
199 LOGLIST_AUTHOR,
200 LOGLIST_DATE,
201 LOGLIST_EMAIL,
202 LOGLIST_COMMIT_NAME,
203 LOGLIST_COMMIT_EMAIL,
204 LOGLIST_COMMIT_DATE,
205 LOGLIST_BUG,
206 LOGLIST_MESSAGE_MAX=300,
207 LOGLIST_MESSAGE_MIN=200,
209 GIT_LOG_GRAPH = 1<< LOGLIST_GRAPH,
210 GIT_LOG_REBASE = 1<< LOGLIST_REBASE,
211 GIT_LOG_ID = 1<< LOGLIST_ID,
212 GIT_LOG_HASH = 1<< LOGLIST_HASH,
213 GIT_LOG_ACTIONS = 1<< LOGLIST_ACTION,
214 GIT_LOG_MESSAGE = 1<< LOGLIST_MESSAGE,
215 GIT_LOG_AUTHOR = 1<< LOGLIST_AUTHOR,
216 GIT_LOG_DATE = 1<< LOGLIST_DATE,
217 GIT_LOG_EMAIL = 1<< LOGLIST_EMAIL,
218 GIT_LOG_COMMIT_NAME = 1<< LOGLIST_COMMIT_NAME,
219 GIT_LOG_COMMIT_EMAIL= 1<< LOGLIST_COMMIT_EMAIL,
220 GIT_LOG_COMMIT_DATE = 1<< LOGLIST_COMMIT_DATE,
221 GIT_LOGLIST_BUG = 1<< LOGLIST_BUG,
224 enum
226 // needs to start with 1, since 0 is the return value if *nothing* is clicked on in the context menu
227 ID_COMPARE = 1, // compare revision with WC
228 ID_SAVEAS,
229 ID_COMPARETWO, // compare two revisions
230 ID_COPY,
231 ID_REVERTREV,
232 ID_MERGEREV,
233 ID_GNUDIFF1, // compare with WC, unified
234 ID_GNUDIFF2, // compare two revisions, unified
235 ID_FINDENTRY,
236 ID_OPEN,
237 ID_BLAME,
238 ID_REPOBROWSE,
239 ID_LOG,
240 ID_EDITNOTE,
241 ID_DIFF,
242 ID_OPENWITH,
243 ID_COPYCLIPBOARD,
244 ID_COPYHASH,
245 ID_REVERTTOREV,
246 ID_BLAMECOMPARE,
247 ID_BLAMEDIFF,
248 ID_VIEWREV,
249 ID_VIEWPATHREV,
250 ID_EXPORT,
251 ID_COMPAREWITHPREVIOUS,
252 ID_BLAMEWITHPREVIOUS,
253 ID_CHERRY_PICK,
254 ID_CREATE_BRANCH,
255 ID_CREATE_TAG,
256 ID_SWITCHTOREV,
257 ID_SWITCHBRANCH,
258 ID_RESET,
259 ID_REBASE_PICK,
260 ID_REBASE_EDIT,
261 ID_REBASE_SQUASH,
262 ID_REBASE_SKIP,
263 ID_COMBINE_COMMIT,
264 ID_STASH_SAVE,
265 ID_STASH_LIST,
266 ID_STASH_POP,
267 ID_REFLOG_STASH_APPLY,
268 ID_REFLOG_DEL,
269 ID_REBASE_TO_VERSION,
270 ID_CREATE_PATCH,
271 ID_DELETE,
272 ID_COMMIT,
273 ID_PUSH,
274 ID_FETCH,
275 ID_SHOWBRANCHES,
276 ID_COPYCLIPBOARDMESSAGES,
277 ID_BISECTSTART,
279 enum
281 ID_COPY_ALL,
282 ID_COPY_MESSAGE,
283 ID_COPY_SUBJECT,
284 ID_COPY_HASH,
286 inline unsigned __int64 GetContextMenuBit(int i){ return ((unsigned __int64 )0x1)<<i ;}
287 void InsertGitColumn();
288 void ResizeAllListCtrlCols();
289 void CopySelectionToClipBoard(int toCopy = ID_COPY_ALL);
290 void DiffSelectedRevWithPrevious();
291 bool IsSelectionContinuous();
292 int BeginFetchLog();
293 int FillGitLog(CTGitPath *path,int infomask=CGit:: LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE,CString *from=NULL,CString *to=NULL);
294 BOOL IsMatchFilter(bool bRegex, GitRev *pRev, tr1::wregex &pat);
296 CFindDlg *m_pFindDialog;
297 static const UINT m_FindDialogMessage;
298 void OnFind();
300 static const UINT m_ScrollToMessage;
302 inline int ShownCountWithStopped() const { return (int)m_arShownList.GetCount() + (m_bStrictStopped ? 1 : 0); }
303 int FetchLogAsync(void * data=NULL);
304 CThreadSafePtrArray m_arShownList;
305 void Refresh(BOOL IsCleanFilter=TRUE);
306 void RecalculateShownList(CThreadSafePtrArray * pShownlist);
307 void Clear();
309 DWORD m_SelectedFilters;
310 bool m_bFilterWithRegex;
311 CLogDataVector m_logEntries;
312 void RemoveFilter();
313 void StartFilter();
314 bool ValidateRegexp(LPCTSTR regexp_str, tr1::wregex& pat, bool bMatchCase = false );
315 CString m_sFilterText;
317 __time64_t m_From;
318 __time64_t m_To;
320 CTGitPath m_Path;
321 int m_ShowMask;
322 CGitHash m_lastSelectedHash;
324 void GetTimeRange(CTime &oldest,CTime &latest);
325 virtual void ContextMenuAction(int cmd,int FirstSelect, int LastSelect, CMenu * menu)=0;
326 void ReloadHashMap()
328 m_HashMap.clear();
329 g_Git.GetMapHashToFriendName(m_HashMap);
330 m_CurrentBranch=g_Git.GetCurrentBranch();
331 this->m_HeadHash=g_Git.GetHash(_T("HEAD"));
332 m_wcRev.m_ParentHash.clear();
333 m_wcRev.m_ParentHash.push_back(m_HeadHash);
335 void SafeTerminateThread()
337 if (m_LoadingThread!=NULL && InterlockedExchange(&m_bExitThread, TRUE) == FALSE)
339 DWORD ret = WAIT_TIMEOUT;
340 for (int i = 0; i < 200 && m_bThreadRunning; i++)
341 ret =::WaitForSingleObject(m_LoadingThread->m_hThread, 100);
342 if (ret == WAIT_TIMEOUT && m_bThreadRunning)
343 ::TerminateThread(m_LoadingThread, 0);
344 m_LoadingThread = NULL;
348 bool IsInWorkingThread()
350 return (AfxGetThread() == m_LoadingThread);
353 void SetStartRef(const CString& StartRef)
355 m_StartRef=StartRef;
358 CString GetStartRef() const {return m_StartRef;}
360 int m_nSearchIndex;
362 volatile LONG m_bExitThread;
363 CWinThread* m_LoadingThread;
364 MAP_HASH_NAME m_HashMap;
366 public:
367 CString m_ColumnRegKey;
369 protected:
370 DECLARE_MESSAGE_MAP()
371 afx_msg void OnDestroy();
372 virtual afx_msg void OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult);
373 virtual afx_msg void OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult);
374 afx_msg LRESULT OnFindDialogMessage(WPARAM wParam, LPARAM lParam);
375 afx_msg LRESULT OnScrollToMessage(WPARAM wParam, LPARAM lParam);
376 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
377 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
378 afx_msg LRESULT OnLoad(WPARAM wParam, LPARAM lParam);
379 afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);
380 afx_msg void OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
381 afx_msg void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult);
382 afx_msg void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult);
383 void OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult);
384 afx_msg void OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult);
385 void PreSubclassWindow();
386 virtual BOOL PreTranslateMessage(MSG* pMsg);
387 static UINT LogThreadEntry(LPVOID pVoid);
388 UINT LogThread();
389 void FetchLastLogInfo();
390 void FetchFullLogInfo(CString &from, CString &to);
391 void FillBackGround(HDC hdc, DWORD_PTR Index, CRect &rect);
392 void DrawTagBranch(HDC,CRect &rect,INT_PTR index);
393 void DrawGraph(HDC,CRect &rect,INT_PTR index);
395 BOOL GetShortName(CString ref, CString &shortname,CString prefix);
396 void paintGraphLane(HDC hdc,int laneHeight, int type, int x1, int x2,
397 const COLORREF& col,const COLORREF& activeColor, int top) ;
398 void DrawLine(HDC hdc, int x1, int y1, int x2, int y2){::MoveToEx(hdc,x1,y1,NULL);::LineTo(hdc,x2,y2);}
400 * Save column widths to the registry
402 void SaveColumnWidths(); // save col widths to the registry
404 BOOL IsEntryInDateRange(int i);
406 int GetHeadIndex();
408 std::vector<GitRev*> m_AsynDiffList;
409 CComCriticalSection m_AsynDiffListLock;
410 HANDLE m_AsyncDiffEvent;
411 volatile LONG m_AsyncThreadExit;
412 CWinThread* m_DiffingThread;
414 static int DiffAsync(GitRev *rev, void *data)
416 ULONGLONG offset=((CGitLogListBase*)data)->m_LogCache.GetOffset(rev->m_CommitHash);
417 if(!offset)
419 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
420 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
421 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
422 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
424 else
426 if(((CGitLogListBase*)data)->m_LogCache.LoadOneItem(*rev,offset))
428 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
429 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
430 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
431 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
433 InterlockedExchange(&rev->m_IsDiffFiles, TRUE);
434 if(rev->m_IsDiffFiles && rev->m_IsCommitParsed)
435 InterlockedExchange(&rev->m_IsFull, TRUE);
437 return 0;
440 static UINT AsyncThread(LPVOID data)
442 return ((CGitLogListBase*)data)->AsyncDiffThread();
445 int AsyncDiffThread();
446 bool m_AsyncThreadExited;
448 public:
449 void SafeTerminateAsyncDiffThread()
451 if(m_DiffingThread!=NULL && m_AsyncThreadExit != TRUE)
453 m_AsyncThreadExit = TRUE;
454 ::SetEvent(m_AsyncDiffEvent);
455 DWORD ret = WAIT_TIMEOUT;
456 // do not block here, but process messages and ask until the thread ends
457 while (ret == WAIT_TIMEOUT && !m_AsyncThreadExited)
459 AfxGetThread()->PumpMessage(); // process messages, so that GetTopIndex and so on in the thread work
460 ret = ::WaitForSingleObject(m_DiffingThread->m_hThread, 100);
462 m_DiffingThread = NULL;
466 protected:
467 CComCriticalSection m_critSec;
469 HICON m_hModifiedIcon;
470 HICON m_hReplacedIcon;
471 HICON m_hAddedIcon;
472 HICON m_hDeletedIcon;
473 HICON m_hFetchIcon;
475 HFONT m_boldFont;
477 CRegDWORD m_regMaxBugIDColWidth;
479 void *m_ProcData;
480 CStoreSelection* m_pStoreSelection;
482 CColors m_Colors;
484 CString m_CurrentBranch;
485 CGitHash m_HeadHash;
487 CString m_StartRef; //Ref of the top-commit
489 COLORREF m_LineColors[Lanes::COLORS_NUM];
490 DWORD m_DateFormat; // DATE_SHORTDATE or DATE_LONGDATE
491 bool m_bRelativeTimes; // Show relative times
492 GIT_LOG m_DllGitLog;
494 ColumnManager m_ColumnManager;
495 DWORD m_dwDefaultColumns;