3 #include "HintListCtrl.h"
5 #include "CommonResource.h"
7 #include "ProjectProperties.h"
10 #include "SplitterControl.h"
12 #include "MenuButton.h"
13 #include "LogDlgHelper.h"
14 #include "FilterEdit.h"
17 //#include "GitLogList.h"
19 #include "GitLogCache.h"
21 #include <GitStatusListCtrl.h>
25 #if (NTDDI_VERSION < NTDDI_LONGHORN)
27 enum LISTITEMSTATES_MINE
{
32 LISS_SELECTEDNOTFOCUS
= 5,
36 // these defines must be in the order the columns are inserted!
39 #define MCS_NOTRAILINGDATES 0x0040
40 #define MCS_SHORTDAYSOFWEEK 0x0080
41 #define MCS_NOSELCHANGEONNAV 0x0100
43 #define DTM_SETMCSTYLE (DTM_FIRST + 11)
47 #define ICONITEMBORDER 5
49 #define GITLOG_START 0
50 #define GITLOG_START_ALL 1
51 #define GITLOG_END 100
53 #define LOGFILTER_ALL 1
54 #define LOGFILTER_MESSAGES 2
55 #define LOGFILTER_PATHS 3
56 #define LOGFILTER_AUTHORS 4
57 #define LOGFILTER_REVS 5
58 #define LOGFILTER_REGEX 6
59 #define LOGFILTER_BUGID 7
61 //typedef void CALLBACK_PROCESS(void * data, int progress);
62 #define MSG_LOADED (WM_USER+110)
63 #define MSG_LOAD_PERCENTAGE (WM_USER+111)
64 #define MSG_REFLOG_CHANGED (WM_USER+112)
65 #define MSG_FETCHED_DIFF (WM_USER+113)
67 class CThreadSafePtrArray
: public CPtrArray
69 CComCriticalSection
*m_critSec
;
71 CThreadSafePtrArray(CComCriticalSection
*section
){ m_critSec
= section
;}
72 void * SafeGetAt(INT_PTR i
)
77 if( i
<0 || i
>=GetCount())
90 INT_PTR
SafeAdd(void *newElement
)
95 ret
= Add(newElement
);
112 class CGitLogListBase
: public CHintListCtrl
114 DECLARE_DYNAMIC(CGitLogListBase
)
118 virtual ~CGitLogListBase();
119 ProjectProperties m_ProjectProperties
;
121 CFilterData m_Filter
;
123 void UpdateProjectProperties()
125 m_ProjectProperties
.ReadProps(this->m_Path
);
127 if ((!m_ProjectProperties
.sUrl
.IsEmpty())||(!m_ProjectProperties
.sCheckRe
.IsEmpty()))
128 m_bShowBugtraqColumn
= true;
130 m_bShowBugtraqColumn
= false;
135 m_wcRev
.GetBody()=_T("Fetching Status...");
136 m_wcRev
.m_CallDiffAsync
= DiffAsync
;
137 InterlockedExchange(&m_wcRev
.m_IsDiffFiles
, FALSE
);
139 void SetProjectPropertiesPath(const CTGitPath
& path
) {m_ProjectProperties
.ReadProps(path
);}
141 volatile LONG m_bNoDispUpdates
;
142 BOOL m_IsIDReplaceAction
;
144 void hideFromContextMenu(unsigned __int64 hideMask
, bool exclusivelyShow
);
145 BOOL m_IsRebaseReplaceGraph
;
147 void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct
);
149 BOOL m_bStrictStopped
;
150 BOOL m_bShowBugtraqColumn
;
153 unsigned __int64 m_ContextMenuMask
;
158 volatile LONG m_bThreadRunning
;
159 CLogCache m_LogCache
;
164 // don't forget to bump BLAME_COLUMN_VERSION in GitStatusListCtrlHelpers.cpp if you change columns
177 LOGLIST_COMMIT_EMAIL
,
180 LOGLIST_MESSAGE_MAX
=300,
181 LOGLIST_MESSAGE_MIN
=200,
183 GIT_LOG_GRAPH
= 1<< LOGLIST_GRAPH
,
184 GIT_LOG_REBASE
= 1<< LOGLIST_REBASE
,
185 GIT_LOG_ID
= 1<< LOGLIST_ID
,
186 GIT_LOG_HASH
= 1<< LOGLIST_HASH
,
187 GIT_LOG_ACTIONS
= 1<< LOGLIST_ACTION
,
188 GIT_LOG_MESSAGE
= 1<< LOGLIST_MESSAGE
,
189 GIT_LOG_AUTHOR
= 1<< LOGLIST_AUTHOR
,
190 GIT_LOG_DATE
= 1<< LOGLIST_DATE
,
191 GIT_LOG_EMAIL
= 1<< LOGLIST_EMAIL
,
192 GIT_LOG_COMMIT_NAME
= 1<< LOGLIST_COMMIT_NAME
,
193 GIT_LOG_COMMIT_EMAIL
= 1<< LOGLIST_COMMIT_EMAIL
,
194 GIT_LOG_COMMIT_DATE
= 1<< LOGLIST_COMMIT_DATE
,
195 GIT_LOGLIST_BUG
= 1<< LOGLIST_BUG
,
200 // needs to start with 1, since 0 is the return value if *nothing* is clicked on in the context menu
230 ID_COMPAREWITHPREVIOUS
,
231 ID_BLAMEWITHPREVIOUS
,
247 ID_REBASE_TO_VERSION
,
252 inline unsigned __int64
GetContextMenuBit(int i
){ return ((unsigned __int64
)0x1)<<i
;}
253 void InsertGitColumn();
254 void ResizeAllListCtrlCols();
255 void CopySelectionToClipBoard(bool hashonly
=FALSE
);
256 void DiffSelectedRevWithPrevious();
257 bool IsSelectionContinuous();
259 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
);
261 CFindDlg
*m_pFindDialog
;
262 static const UINT m_FindDialogMessage
;
265 inline int ShownCountWithStopped() const { return (int)m_arShownList
.GetCount() + (m_bStrictStopped
? 1 : 0); }
266 int FetchLogAsync(void * data
=NULL
);
267 CThreadSafePtrArray m_arShownList
;
268 void Refresh(BOOL IsCleanFilter
=TRUE
);
269 void RecalculateShownList(CThreadSafePtrArray
* pShownlist
);
272 int m_nSelectedFilter
;
273 bool m_bFilterWithRegex
;
274 CLogDataVector m_logEntries
;
277 bool ValidateRegexp(LPCTSTR regexp_str
, tr1::wregex
& pat
, bool bMatchCase
= false );
278 CString m_sFilterText
;
286 void GetTimeRange(CTime
&oldest
,CTime
&latest
);
287 virtual void ContextMenuAction(int cmd
,int FirstSelect
, int LastSelect
, CMenu
* menu
)=0;
291 g_Git
.GetMapHashToFriendName(m_HashMap
);
292 m_CurrentBranch
=g_Git
.GetCurrentBranch();
293 this->m_HeadHash
=g_Git
.GetHash(_T("HEAD"));
294 m_wcRev
.m_ParentHash
.clear();
295 m_wcRev
.m_ParentHash
.push_back(m_HeadHash
);
297 void SafeTerminateThread()
299 if(m_LoadingThread
!=NULL
)
301 InterlockedExchange(&m_bExitThread
,TRUE
);
302 DWORD ret
=::WaitForSingleObject(m_LoadingThread
->m_hThread
,20000);
303 if(ret
== WAIT_TIMEOUT
)
304 ::TerminateThread(m_LoadingThread
,0);
305 m_LoadingThread
= NULL
;
309 bool IsInWorkingThread()
311 return (AfxGetThread() == m_LoadingThread
);
314 void SetStartRef(const CString
& StartRef
)
319 CString
GetStartRef() const {return m_StartRef
;}
323 volatile LONG m_bExitThread
;
324 CWinThread
* m_LoadingThread
;
325 MAP_HASH_NAME m_HashMap
;
328 CString m_ColumnRegKey
;
331 DECLARE_MESSAGE_MAP()
332 afx_msg
void OnDestroy();
333 virtual afx_msg
void OnNMCustomdrawLoglist(NMHDR
*pNMHDR
, LRESULT
*pResult
);
334 virtual afx_msg
void OnLvnGetdispinfoLoglist(NMHDR
*pNMHDR
, LRESULT
*pResult
);
335 afx_msg LRESULT
OnFindDialogMessage(WPARAM wParam
, LPARAM lParam
);
336 afx_msg
int OnCreate(LPCREATESTRUCT lpCreateStruct
);
337 afx_msg
void OnContextMenu(CWnd
* pWnd
, CPoint point
);
338 afx_msg LRESULT
OnLoad(WPARAM wParam
, LPARAM lParam
);
339 afx_msg
void OnHdnBegintrack(NMHDR
*pNMHDR
, LRESULT
*pResult
);
340 afx_msg
void OnHdnItemchanging(NMHDR
*pNMHDR
, LRESULT
*pResult
);
341 afx_msg
void OnColumnResized(NMHDR
*pNMHDR
, LRESULT
*pResult
);
342 afx_msg
void OnColumnMoved(NMHDR
*pNMHDR
, LRESULT
*pResult
);
343 void OnNMDblclkLoglist(NMHDR
* /*pNMHDR*/, LRESULT
*pResult
);
344 afx_msg
void OnLvnOdfinditemLoglist(NMHDR
*pNMHDR
, LRESULT
*pResult
);
345 void PreSubclassWindow();
346 virtual BOOL
PreTranslateMessage(MSG
* pMsg
);
347 static UINT
LogThreadEntry(LPVOID pVoid
);
349 void FetchLastLogInfo();
350 void FetchFullLogInfo(CString
&from
, CString
&to
);
351 void FillBackGround(HDC hdc
, int Index
,CRect
&rect
);
352 void DrawTagBranch(HDC
,CRect
&rect
,INT_PTR index
);
353 void DrawGraph(HDC
,CRect
&rect
,INT_PTR index
);
355 BOOL
GetShortName(CString ref
, CString
&shortname
,CString prefix
);
356 void paintGraphLane(HDC hdc
,int laneHeight
, int type
, int x1
, int x2
,
357 const COLORREF
& col
,const COLORREF
& activeColor
, int top
) ;
358 void DrawLine(HDC hdc
, int x1
, int y1
, int x2
, int y2
){::MoveToEx(hdc
,x1
,y1
,NULL
);::LineTo(hdc
,x2
,y2
);}
360 * Save column widths to the registry
362 void SaveColumnWidths(); // save col widths to the registry
364 BOOL
IsEntryInDateRange(int i
);
368 std::vector
<GitRev
*> m_AsynDiffList
;
369 CComCriticalSection m_AysnDiffListLock
;
370 HANDLE m_AsyncDiffEvent
;
371 volatile LONG m_AsyncThreadExit
;
372 CWinThread
* m_DiffingThread
;
374 static int DiffAsync(GitRev
*rev
, void *data
)
376 ULONGLONG offset
=((CGitLogListBase
*)data
)->m_LogCache
.GetOffset(rev
->m_CommitHash
);
379 ((CGitLogListBase
*)data
)->m_AysnDiffListLock
.Lock();
380 ((CGitLogListBase
*)data
)->m_AsynDiffList
.push_back(rev
);
381 ((CGitLogListBase
*)data
)->m_AysnDiffListLock
.Unlock();
382 ::SetEvent(((CGitLogListBase
*)data
)->m_AsyncDiffEvent
);
385 if(((CGitLogListBase
*)data
)->m_LogCache
.LoadOneItem(*rev
,offset
))
387 ((CGitLogListBase
*)data
)->m_AysnDiffListLock
.Lock();
388 ((CGitLogListBase
*)data
)->m_AsynDiffList
.push_back(rev
);
389 ((CGitLogListBase
*)data
)->m_AysnDiffListLock
.Unlock();
390 ::SetEvent(((CGitLogListBase
*)data
)->m_AsyncDiffEvent
);
392 InterlockedExchange(&rev
->m_IsDiffFiles
, TRUE
);
393 if(rev
->m_IsDiffFiles
&& rev
->m_IsCommitParsed
)
394 InterlockedExchange(&rev
->m_IsFull
, TRUE
);
399 static UINT
AsyncThread(LPVOID data
)
401 return ((CGitLogListBase
*)data
)->AsyncDiffThread();
404 int AsyncDiffThread();
406 void SafeTerminateAsyncDiffThread()
408 if(m_DiffingThread
!=NULL
&& m_AsyncThreadExit
!= TRUE
)
410 m_AsyncThreadExit
= TRUE
;
411 ::SetEvent(m_AsyncDiffEvent
);
412 DWORD ret
= WAIT_TIMEOUT
;
413 // do not block here, but process messages and ask until the thread ends
414 while (ret
== WAIT_TIMEOUT
)
416 AfxGetThread()->PumpMessage(); // process messages, so that GetTopIndex and so on in the thread work
417 ret
= ::WaitForSingleObject(m_DiffingThread
->m_hThread
, 100);
419 m_DiffingThread
= NULL
;
424 CComCriticalSection m_critSec
;
429 HICON m_hModifiedIcon
;
430 HICON m_hReplacedIcon
;
432 HICON m_hDeletedIcon
;
437 CRegDWORD m_regMaxBugIDColWidth
;
440 CStoreSelection
* m_pStoreSelection
;
444 CString m_CurrentBranch
;
447 CString m_StartRef
; //Ref of the top-commit
449 COLORREF m_LineColors
[Lanes::COLORS_NUM
];
450 DWORD m_DateFormat
; // DATE_SHORTDATE or DATE_LONGDATE
451 bool m_bRelativeTimes
; // Show relative times
454 ColumnManager m_ColumnManager
;
455 DWORD m_dwDefaultColumns
;