Fixed issue #933: implement git stash --include-untracked
[TortoiseGit.git] / src / TortoiseProc / GitLogListBase.h
blob2eba099462979b3540a816df8fc227a783087afe
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2011 - 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 "CommonResource.h"
25 #include "Git.h"
26 #include "ProjectProperties.h"
27 #include "TGitPath.h"
28 #include "registry.h"
29 #include "SplitterControl.h"
30 #include "Colors.h"
31 #include "MenuButton.h"
32 #include "LogDlgHelper.h"
33 #include "FilterEdit.h"
34 #include "GitRev.h"
35 #include "Tooltip.h"
36 //#include "GitLogList.h"
37 #include "lanes.h"
38 #include "GitLogCache.h"
39 #include <regex>
40 #include <GitStatusListCtrl.h>
41 #include "FindDlg.h"
43 // CGitLogList
44 #if (NTDDI_VERSION < NTDDI_LONGHORN)
46 enum LISTITEMSTATES_MINE {
47 LISS_NORMAL = 1,
48 LISS_HOT = 2,
49 LISS_SELECTED = 3,
50 LISS_DISABLED = 4,
51 LISS_SELECTEDNOTFOCUS = 5,
52 LISS_HOTSELECTED = 6,
55 // these defines must be in the order the columns are inserted!
58 #define MCS_NOTRAILINGDATES 0x0040
59 #define MCS_SHORTDAYSOFWEEK 0x0080
60 #define MCS_NOSELCHANGEONNAV 0x0100
62 #define DTM_SETMCSTYLE (DTM_FIRST + 11)
64 #endif
66 #define ICONITEMBORDER 5
68 #define GITLOG_START 0
69 #define GITLOG_START_ALL 1
70 #define GITLOG_END 100
72 #define LOGFILTER_ALL 1
73 #define LOGFILTER_MESSAGES 2
74 #define LOGFILTER_PATHS 3
75 #define LOGFILTER_AUTHORS 4
76 #define LOGFILTER_REVS 5
77 #define LOGFILTER_REGEX 6
78 #define LOGFILTER_BUGID 7
80 //typedef void CALLBACK_PROCESS(void * data, int progress);
81 #define MSG_LOADED (WM_USER+110)
82 #define MSG_LOAD_PERCENTAGE (WM_USER+111)
83 #define MSG_REFLOG_CHANGED (WM_USER+112)
84 #define MSG_FETCHED_DIFF (WM_USER+113)
86 class CThreadSafePtrArray: public CPtrArray
88 CComCriticalSection *m_critSec;
89 public:
90 CThreadSafePtrArray(CComCriticalSection *section){ m_critSec = section ;}
91 void * SafeGetAt(INT_PTR i)
93 if(m_critSec)
94 m_critSec->Lock();
96 if( i<0 || i>=GetCount())
98 if(m_critSec)
99 m_critSec->Unlock();
101 return NULL;
104 if(m_critSec)
105 m_critSec->Unlock();
107 return GetAt(i);
109 INT_PTR SafeAdd(void *newElement)
111 INT_PTR ret;
112 if(m_critSec)
113 m_critSec->Lock();
114 ret = Add(newElement);
115 if(m_critSec)
116 m_critSec->Unlock();
117 return ret;
120 void SafeRemoveAll()
122 if(m_critSec)
123 m_critSec->Lock();
124 RemoveAll();
125 if(m_critSec)
126 m_critSec->Unlock();
131 class CGitLogListBase : public CHintListCtrl
133 DECLARE_DYNAMIC(CGitLogListBase)
135 public:
136 CGitLogListBase();
137 virtual ~CGitLogListBase();
138 ProjectProperties m_ProjectProperties;
140 CFilterData m_Filter;
142 void UpdateProjectProperties()
144 m_ProjectProperties.ReadProps(this->m_Path);
146 if ((!m_ProjectProperties.sUrl.IsEmpty())||(!m_ProjectProperties.sCheckRe.IsEmpty()))
147 m_bShowBugtraqColumn = true;
148 else
149 m_bShowBugtraqColumn = false;
152 void ResetWcRev()
154 m_wcRev.GetBody()=_T("Fetching Status...");
155 m_wcRev.m_CallDiffAsync = DiffAsync;
156 InterlockedExchange(&m_wcRev.m_IsDiffFiles, FALSE);
158 void SetProjectPropertiesPath(const CTGitPath& path) {m_ProjectProperties.ReadProps(path);}
160 volatile LONG m_bNoDispUpdates;
161 BOOL m_IsIDReplaceAction;
162 BOOL m_IsOldFirst;
163 void hideFromContextMenu(unsigned __int64 hideMask, bool exclusivelyShow);
164 BOOL m_IsRebaseReplaceGraph;
166 void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
168 BOOL m_bStrictStopped;
169 BOOL m_bShowBugtraqColumn;
170 BOOL m_bSearchIndex;
171 BOOL m_bCancelled;
172 unsigned __int64 m_ContextMenuMask;
174 bool m_hasWC;
175 bool m_bShowWC;
176 GitRev m_wcRev;
177 volatile LONG m_bThreadRunning;
178 CLogCache m_LogCache;
180 CString m_startrev;
181 CString m_endrev;
183 // don't forget to bump BLAME_COLUMN_VERSION in GitStatusListCtrlHelpers.cpp if you change columns
184 enum
186 LOGLIST_GRAPH,
187 LOGLIST_REBASE,
188 LOGLIST_ID,
189 LOGLIST_HASH,
190 LOGLIST_ACTION,
191 LOGLIST_MESSAGE,
192 LOGLIST_AUTHOR,
193 LOGLIST_DATE,
194 LOGLIST_EMAIL,
195 LOGLIST_COMMIT_NAME,
196 LOGLIST_COMMIT_EMAIL,
197 LOGLIST_COMMIT_DATE,
198 LOGLIST_BUG,
199 LOGLIST_MESSAGE_MAX=300,
200 LOGLIST_MESSAGE_MIN=200,
202 GIT_LOG_GRAPH = 1<< LOGLIST_GRAPH,
203 GIT_LOG_REBASE = 1<< LOGLIST_REBASE,
204 GIT_LOG_ID = 1<< LOGLIST_ID,
205 GIT_LOG_HASH = 1<< LOGLIST_HASH,
206 GIT_LOG_ACTIONS = 1<< LOGLIST_ACTION,
207 GIT_LOG_MESSAGE = 1<< LOGLIST_MESSAGE,
208 GIT_LOG_AUTHOR = 1<< LOGLIST_AUTHOR,
209 GIT_LOG_DATE = 1<< LOGLIST_DATE,
210 GIT_LOG_EMAIL = 1<< LOGLIST_EMAIL,
211 GIT_LOG_COMMIT_NAME = 1<< LOGLIST_COMMIT_NAME,
212 GIT_LOG_COMMIT_EMAIL= 1<< LOGLIST_COMMIT_EMAIL,
213 GIT_LOG_COMMIT_DATE = 1<< LOGLIST_COMMIT_DATE,
214 GIT_LOGLIST_BUG = 1<< LOGLIST_BUG,
217 enum
219 // needs to start with 1, since 0 is the return value if *nothing* is clicked on in the context menu
220 ID_COMPARE = 1,
221 ID_SAVEAS,
222 ID_COMPARETWO,
223 ID_UPDATE,
224 ID_COPY,
225 ID_REVERTREV,
226 ID_MERGEREV,
227 ID_GNUDIFF1,
228 ID_GNUDIFF2,
229 ID_FINDENTRY,
230 ID_OPEN,
231 ID_BLAME,
232 ID_REPOBROWSE,
233 ID_LOG,
234 ID_POPPROPS,
235 ID_EDITNOTE,
236 ID_EDITLOG,
237 ID_DIFF,
238 ID_OPENWITH,
239 ID_COPYCLIPBOARD,
240 ID_COPYHASH,
241 ID_REVERTTOREV,
242 ID_BLAMECOMPARE,
243 ID_BLAMETWO,
244 ID_BLAMEDIFF,
245 ID_VIEWREV,
246 ID_VIEWPATHREV,
247 ID_EXPORT,
248 ID_COMPAREWITHPREVIOUS,
249 ID_BLAMEWITHPREVIOUS,
250 ID_GETMERGELOGS,
251 ID_REVPROPS,
252 ID_CHERRY_PICK,
253 ID_CREATE_BRANCH,
254 ID_CREATE_TAG,
255 ID_SWITCHTOREV,
256 ID_SWITCHBRANCH,
257 ID_RESET,
258 ID_REBASE_PICK,
259 ID_REBASE_EDIT,
260 ID_REBASE_SQUASH,
261 ID_REBASE_SKIP,
262 ID_COMBINE_COMMIT,
263 ID_STASH_APPLY,
264 ID_REFLOG_DEL,
265 ID_REBASE_TO_VERSION,
266 ID_CREATE_PATCH,
267 ID_DELETE,
268 ID_COMMIT,
269 ID_PUSH,
271 inline unsigned __int64 GetContextMenuBit(int i){ return ((unsigned __int64 )0x1)<<i ;}
272 void InsertGitColumn();
273 void ResizeAllListCtrlCols();
274 void CopySelectionToClipBoard(bool hashonly=FALSE);
275 void DiffSelectedRevWithPrevious();
276 bool IsSelectionContinuous();
277 int BeginFetchLog();
278 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);
279 BOOL IsMatchFilter(bool bRegex, GitRev *pRev, tr1::wregex &pat);
281 CFindDlg *m_pFindDialog;
282 static const UINT m_FindDialogMessage;
283 void OnFind();
285 inline int ShownCountWithStopped() const { return (int)m_arShownList.GetCount() + (m_bStrictStopped ? 1 : 0); }
286 int FetchLogAsync(void * data=NULL);
287 CThreadSafePtrArray m_arShownList;
288 void Refresh(BOOL IsCleanFilter=TRUE);
289 void RecalculateShownList(CThreadSafePtrArray * pShownlist);
290 void Clear();
292 int m_nSelectedFilter;
293 bool m_bFilterWithRegex;
294 CLogDataVector m_logEntries;
295 void RemoveFilter();
296 void StartFilter();
297 bool ValidateRegexp(LPCTSTR regexp_str, tr1::wregex& pat, bool bMatchCase = false );
298 CString m_sFilterText;
300 __time64_t m_From;
301 __time64_t m_To;
303 CTGitPath m_Path;
304 int m_ShowMask;
305 CGitHash m_lastSelectedHash;
307 void GetTimeRange(CTime &oldest,CTime &latest);
308 virtual void ContextMenuAction(int cmd,int FirstSelect, int LastSelect, CMenu * menu)=0;
309 void ReloadHashMap()
311 m_HashMap.clear();
312 g_Git.GetMapHashToFriendName(m_HashMap);
313 m_CurrentBranch=g_Git.GetCurrentBranch();
314 this->m_HeadHash=g_Git.GetHash(_T("HEAD"));
315 m_wcRev.m_ParentHash.clear();
316 m_wcRev.m_ParentHash.push_back(m_HeadHash);
318 void SafeTerminateThread()
320 if(m_LoadingThread!=NULL)
322 InterlockedExchange(&m_bExitThread,TRUE);
323 DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000);
324 if(ret == WAIT_TIMEOUT)
325 ::TerminateThread(m_LoadingThread,0);
326 m_LoadingThread = NULL;
330 bool IsInWorkingThread()
332 return (AfxGetThread() == m_LoadingThread);
335 void SetStartRef(const CString& StartRef)
337 m_StartRef=StartRef;
340 CString GetStartRef() const {return m_StartRef;}
342 int m_nSearchIndex;
344 volatile LONG m_bExitThread;
345 CWinThread* m_LoadingThread;
346 MAP_HASH_NAME m_HashMap;
348 public:
349 CString m_ColumnRegKey;
351 protected:
352 DECLARE_MESSAGE_MAP()
353 afx_msg void OnDestroy();
354 virtual afx_msg void OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult);
355 virtual afx_msg void OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult);
356 afx_msg LRESULT OnFindDialogMessage(WPARAM wParam, LPARAM lParam);
357 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
358 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
359 afx_msg LRESULT OnLoad(WPARAM wParam, LPARAM lParam);
360 afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);
361 afx_msg void OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
362 afx_msg void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult);
363 afx_msg void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult);
364 void OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult);
365 afx_msg void OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult);
366 void PreSubclassWindow();
367 virtual BOOL PreTranslateMessage(MSG* pMsg);
368 static UINT LogThreadEntry(LPVOID pVoid);
369 UINT LogThread();
370 void FetchLastLogInfo();
371 void FetchFullLogInfo(CString &from, CString &to);
372 void FillBackGround(HDC hdc, int Index,CRect &rect);
373 void DrawTagBranch(HDC,CRect &rect,INT_PTR index);
374 void DrawGraph(HDC,CRect &rect,INT_PTR index);
376 BOOL GetShortName(CString ref, CString &shortname,CString prefix);
377 void paintGraphLane(HDC hdc,int laneHeight, int type, int x1, int x2,
378 const COLORREF& col,const COLORREF& activeColor, int top) ;
379 void DrawLine(HDC hdc, int x1, int y1, int x2, int y2){::MoveToEx(hdc,x1,y1,NULL);::LineTo(hdc,x2,y2);}
381 * Save column widths to the registry
383 void SaveColumnWidths(); // save col widths to the registry
385 BOOL IsEntryInDateRange(int i);
387 int GetHeadIndex();
389 std::vector<GitRev*> m_AsynDiffList;
390 CComCriticalSection m_AsynDiffListLock;
391 HANDLE m_AsyncDiffEvent;
392 volatile LONG m_AsyncThreadExit;
393 CWinThread* m_DiffingThread;
395 static int DiffAsync(GitRev *rev, void *data)
397 ULONGLONG offset=((CGitLogListBase*)data)->m_LogCache.GetOffset(rev->m_CommitHash);
398 if(!offset)
400 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
401 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
402 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
403 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
405 else
407 if(((CGitLogListBase*)data)->m_LogCache.LoadOneItem(*rev,offset))
409 ((CGitLogListBase*)data)->m_AsynDiffListLock.Lock();
410 ((CGitLogListBase*)data)->m_AsynDiffList.push_back(rev);
411 ((CGitLogListBase*)data)->m_AsynDiffListLock.Unlock();
412 ::SetEvent(((CGitLogListBase*)data)->m_AsyncDiffEvent);
414 InterlockedExchange(&rev->m_IsDiffFiles, TRUE);
415 if(rev->m_IsDiffFiles && rev->m_IsCommitParsed)
416 InterlockedExchange(&rev->m_IsFull, TRUE);
418 return 0;
421 static UINT AsyncThread(LPVOID data)
423 return ((CGitLogListBase*)data)->AsyncDiffThread();
426 int AsyncDiffThread();
427 bool m_AsyncThreadExited;
429 public:
430 void SafeTerminateAsyncDiffThread()
432 if(m_DiffingThread!=NULL && m_AsyncThreadExit != TRUE)
434 m_AsyncThreadExit = TRUE;
435 ::SetEvent(m_AsyncDiffEvent);
436 DWORD ret = WAIT_TIMEOUT;
437 // do not block here, but process messages and ask until the thread ends
438 while (ret == WAIT_TIMEOUT && !m_AsyncThreadExited)
440 AfxGetThread()->PumpMessage(); // process messages, so that GetTopIndex and so on in the thread work
441 ret = ::WaitForSingleObject(m_DiffingThread->m_hThread, 100);
443 m_DiffingThread = NULL;
447 protected:
448 CComCriticalSection m_critSec;
450 bool m_bVista;
452 HICON m_hModifiedIcon;
453 HICON m_hReplacedIcon;
454 HICON m_hAddedIcon;
455 HICON m_hDeletedIcon;
456 HICON m_hFetchIcon;
458 HFONT m_boldFont;
460 CRegDWORD m_regMaxBugIDColWidth;
462 void *m_ProcData;
463 CStoreSelection* m_pStoreSelection;
465 CColors m_Colors;
467 CString m_CurrentBranch;
468 CGitHash m_HeadHash;
470 CString m_StartRef; //Ref of the top-commit
472 COLORREF m_LineColors[Lanes::COLORS_NUM];
473 DWORD m_DateFormat; // DATE_SHORTDATE or DATE_LONGDATE
474 bool m_bRelativeTimes; // Show relative times
475 GIT_LOG m_DllGitLog;
477 ColumnManager m_ColumnManager;
478 DWORD m_dwDefaultColumns;