OSDN Git Service

62250c0206d9fef6da700f61da4c92f6778ebfab
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / GitLogListBase.cpp
1 // GitLogList.cpp : implementation file\r
2 //\r
3 /*\r
4         Description: qgit revision list view\r
5 \r
6         Author: Marco Costalba (C) 2005-2007\r
7 \r
8         Copyright: See COPYING file that comes with this distribution\r
9 \r
10 */\r
11 #include "stdafx.h"\r
12 #include "GitLogListBase.h"\r
13 #include "GitRev.h"\r
14 //#include "VssStyle.h"\r
15 #include "IconMenu.h"\r
16 // CGitLogListBase\r
17 #include "cursor.h"\r
18 #include "InputDlg.h"\r
19 #include "PropDlg.h"\r
20 #include "SVNProgressDlg.h"\r
21 #include "ProgressDlg.h"\r
22 //#include "RepositoryBrowser.h"\r
23 //#include "CopyDlg.h"\r
24 //#include "StatGraphDlg.h"\r
25 #include "Logdlg.h"\r
26 #include "MessageBox.h"\r
27 #include "Registry.h"\r
28 #include "AppUtils.h"\r
29 #include "PathUtils.h"\r
30 #include "StringUtils.h"\r
31 #include "UnicodeUtils.h"\r
32 #include "TempFile.h"\r
33 //#include "GitInfo.h"\r
34 //#include "GitDiff.h"\r
35 #include "IconMenu.h"\r
36 //#include "RevisionRangeDlg.h"\r
37 //#include "BrowseFolder.h"\r
38 //#include "BlameDlg.h"\r
39 //#include "Blame.h"\r
40 //#include "GitHelpers.h"\r
41 #include "GitStatus.h"\r
42 //#include "LogDlgHelper.h"\r
43 //#include "CachedLogInfo.h"\r
44 //#include "RepositoryInfo.h"\r
45 //#include "EditPropertiesDlg.h"\r
46 #include "FileDiffDlg.h"\r
47 #include "..\\TortoiseShell\\Resource.h"\r
48 \r
49 \r
50 \r
51 IMPLEMENT_DYNAMIC(CGitLogListBase, CHintListCtrl)\r
52 \r
53 CGitLogListBase::CGitLogListBase():CHintListCtrl()\r
54         ,m_regMaxBugIDColWidth(_T("Software\\TortoiseGit\\MaxBugIDColWidth"), 200)\r
55         ,m_nSearchIndex(0)\r
56         ,m_bNoDispUpdates(FALSE)\r
57         , m_bThreadRunning(FALSE)\r
58         , m_bStrictStopped(false)\r
59         , m_pStoreSelection(NULL)\r
60         , m_nSelectedFilter(LOGFILTER_ALL)\r
61 {\r
62         // use the default GUI font, create a copy of it and\r
63         // change the copy to BOLD (leave the rest of the font\r
64         // the same)\r
65         HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);\r
66         LOGFONT lf = {0};\r
67         GetObject(hFont, sizeof(LOGFONT), &lf);\r
68         lf.lfWeight = FW_BOLD;\r
69         m_boldFont = CreateFontIndirect(&lf);\r
70         \r
71         m_bShowBugtraqColumn=0;\r
72 \r
73         m_wcRev.m_CommitHash=GIT_REV_ZERO;\r
74         m_wcRev.m_Subject=_T("Working Copy");\r
75 \r
76         m_hModifiedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONMODIFIED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
77         m_hReplacedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONREPLACED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
78         m_hAddedIcon    =  (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONADDED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
79         m_hDeletedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONDELETED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
80 \r
81         m_bFilterWithRegex = !!CRegDWORD(_T("Software\\TortoiseGit\\UseRegexFilter"), TRUE);\r
82 \r
83         g_Git.GetMapHashToFriendName(m_HashMap);\r
84 \r
85         m_From=CTime(1970,1,2,0,0,0);\r
86         m_To=CTime::GetCurrentTime();\r
87 }\r
88 \r
89 CGitLogListBase::~CGitLogListBase()\r
90 {\r
91         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
92 \r
93         DestroyIcon(m_hModifiedIcon);\r
94         DestroyIcon(m_hReplacedIcon);\r
95         DestroyIcon(m_hAddedIcon);\r
96         DestroyIcon(m_hDeletedIcon);\r
97         m_logEntries.ClearAll();\r
98 \r
99         if (m_boldFont)\r
100                 DeleteObject(m_boldFont);\r
101 \r
102         if ( m_pStoreSelection )\r
103         {\r
104                 delete m_pStoreSelection;\r
105                 m_pStoreSelection = NULL;\r
106         }\r
107 }\r
108 \r
109 \r
110 BEGIN_MESSAGE_MAP(CGitLogListBase, CHintListCtrl)\r
111         ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdrawLoglist)\r
112         ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnLvnGetdispinfoLoglist)\r
113         ON_WM_CONTEXTMENU()\r
114         ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclkLoglist)\r
115         ON_NOTIFY_REFLECT(LVN_ODFINDITEM,OnLvnOdfinditemLoglist)\r
116         ON_WM_CREATE()\r
117 END_MESSAGE_MAP()\r
118 \r
119 int CGitLogListBase:: OnCreate(LPCREATESTRUCT lpCreateStruct)\r
120 {\r
121         PreSubclassWindow();\r
122         return CHintListCtrl::OnCreate(lpCreateStruct);\r
123 }\r
124 \r
125 void CGitLogListBase::PreSubclassWindow()\r
126 {\r
127         SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_SUBITEMIMAGES);\r
128         // load the icons for the action columns\r
129         m_Theme.SetWindowTheme(GetSafeHwnd(), L"Explorer", NULL);\r
130         CHintListCtrl::PreSubclassWindow();\r
131 }\r
132 \r
133 void CGitLogListBase::InsertGitColumn()\r
134 {\r
135         CString temp;\r
136 \r
137         int c = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
138         \r
139         while (c>=0)\r
140                 DeleteColumn(c--);\r
141         temp.LoadString(IDS_LOG_GRAPH);\r
142 \r
143         InsertColumn(this->LOGLIST_GRAPH, temp);\r
144         \r
145 #if 0   \r
146         // make the revision column right aligned\r
147         LVCOLUMN Column;\r
148         Column.mask = LVCF_FMT;\r
149         Column.fmt = LVCFMT_RIGHT;\r
150         SetColumn(0, &Column); \r
151 #endif  \r
152 //      CString log;\r
153 //      g_Git.GetLog(log);\r
154 \r
155         temp.LoadString(IDS_LOG_ACTIONS);\r
156         InsertColumn(this->LOGLIST_ACTION, temp);\r
157         \r
158         temp.LoadString(IDS_LOG_MESSAGE);\r
159         InsertColumn(this->LOGLIST_MESSAGE, temp);\r
160         \r
161         temp.LoadString(IDS_LOG_AUTHOR);\r
162         InsertColumn(this->LOGLIST_AUTHOR, temp);\r
163         \r
164         temp.LoadString(IDS_LOG_DATE);\r
165         InsertColumn(this->LOGLIST_DATE, temp);\r
166         \r
167 \r
168         if (m_bShowBugtraqColumn)\r
169         {\r
170 //              temp = m_ProjectProperties.sLabel;\r
171                 if (temp.IsEmpty())\r
172                         temp.LoadString(IDS_LOG_BUGIDS);\r
173                 InsertColumn(this->LOGLIST_BUG, temp);\r
174 \r
175         }\r
176         \r
177         SetRedraw(false);\r
178         ResizeAllListCtrlCols();\r
179         SetRedraw(true);\r
180 \r
181 }\r
182 \r
183 void CGitLogListBase::ResizeAllListCtrlCols()\r
184 {\r
185 \r
186         const int nMinimumWidth = ICONITEMBORDER+16*4;\r
187         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
188         int nItemCount = GetItemCount();\r
189         TCHAR textbuf[MAX_PATH];\r
190         CHeaderCtrl * pHdrCtrl = (CHeaderCtrl*)(GetDlgItem(0));\r
191         if (pHdrCtrl)\r
192         {\r
193                 for (int col = 0; col <= maxcol; col++)\r
194                 {\r
195                         HDITEM hdi = {0};\r
196                         hdi.mask = HDI_TEXT;\r
197                         hdi.pszText = textbuf;\r
198                         hdi.cchTextMax = sizeof(textbuf);\r
199                         pHdrCtrl->GetItem(col, &hdi);\r
200                         int cx = GetStringWidth(hdi.pszText)+20; // 20 pixels for col separator and margin\r
201                         for (int index = 0; index<nItemCount; ++index)\r
202                         {\r
203                                 // get the width of the string and add 14 pixels for the column separator and margins\r
204                                 int linewidth = GetStringWidth(GetItemText(index, col)) + 14;\r
205                                 if (index < m_arShownList.GetCount())\r
206                                 {\r
207                                         GitRev * pCurLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(index));\r
208                                         if ((pCurLogEntry)&&(pCurLogEntry->m_CommitHash == m_wcRev.m_CommitHash))\r
209                                         {\r
210                                                 // set the bold font and ask for the string width again\r
211                                                 SendMessage(WM_SETFONT, (WPARAM)m_boldFont, NULL);\r
212                                                 linewidth = GetStringWidth(GetItemText(index, col)) + 14;\r
213                                                 // restore the system font\r
214                                                 SendMessage(WM_SETFONT, NULL, NULL);\r
215                                         }\r
216                                 }\r
217                                 if (index == 0)\r
218                                 {\r
219                                         // add the image size\r
220                                         CImageList * pImgList = GetImageList(LVSIL_SMALL);\r
221                                         if ((pImgList)&&(pImgList->GetImageCount()))\r
222                                         {\r
223                                                 IMAGEINFO imginfo;\r
224                                                 pImgList->GetImageInfo(0, &imginfo);\r
225                                                 linewidth += (imginfo.rcImage.right - imginfo.rcImage.left);\r
226                                                 linewidth += 3; // 3 pixels between icon and text\r
227                                         }\r
228                                 }\r
229                                 if (cx < linewidth)\r
230                                         cx = linewidth;\r
231                         }\r
232                         // Adjust columns "Actions" containing icons\r
233                         if (col == this->LOGLIST_ACTION)\r
234                         {\r
235                                 if (cx < nMinimumWidth)\r
236                                 {\r
237                                         cx = nMinimumWidth;\r
238                                 }\r
239                         }\r
240                         \r
241                         if (col == this->LOGLIST_MESSAGE)\r
242                         {\r
243                                 if (cx > LOGLIST_MESSAGE_MAX)\r
244                                 {\r
245                                         cx = LOGLIST_MESSAGE_MAX;\r
246                                 }\r
247                                 if (cx < LOGLIST_MESSAGE_MIN)\r
248                                 {\r
249                                         cx = LOGLIST_MESSAGE_MIN;\r
250                                 }\r
251 \r
252                         }\r
253                         // keep the bug id column small\r
254                         if ((col == 4)&&(m_bShowBugtraqColumn))\r
255                         {\r
256                                 if (cx > (int)(DWORD)m_regMaxBugIDColWidth)\r
257                                 {\r
258                                         cx = (int)(DWORD)m_regMaxBugIDColWidth;\r
259                                 }\r
260                         }\r
261 \r
262                         SetColumnWidth(col, cx);\r
263                 }\r
264         }\r
265 \r
266 }\r
267 \r
268 \r
269 BOOL CGitLogListBase::GetShortName(CString ref, CString &shortname,CString prefix)\r
270 {\r
271         TRACE(_T("%s %s\r\n"),ref,prefix);\r
272         if(ref.Left(prefix.GetLength()) ==  prefix)\r
273         {\r
274                 shortname = ref.Right(ref.GetLength()-prefix.GetLength());\r
275                 if(shortname.Right(3)==_T("^{}"))\r
276                         shortname=shortname.Left(shortname.GetLength()-3);\r
277                 return TRUE;\r
278         }\r
279         return FALSE;\r
280 }\r
281 void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect)\r
282 {       \r
283 //      HBRUSH brush;\r
284         LVITEM   rItem;\r
285         SecureZeroMemory(&rItem, sizeof(LVITEM));\r
286         rItem.mask  = LVIF_STATE;\r
287         rItem.iItem = Index;\r
288         rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
289         GetItem(&rItem);\r
290 \r
291         if (m_Theme.IsAppThemed() && m_bVista)\r
292         {\r
293                 m_Theme.Open(m_hWnd, L"Explorer");\r
294                 int state = LISS_NORMAL;\r
295                 if (rItem.state & LVIS_SELECTED)\r
296                 {\r
297                         if (::GetFocus() == m_hWnd)\r
298                                 state |= LISS_SELECTED;\r
299                         else\r
300                                 state |= LISS_SELECTEDNOTFOCUS;\r
301                 }\r
302                 else\r
303                 {\r
304 #if 0\r
305                         if (pLogEntry->bCopiedSelf)\r
306                         {\r
307                                 // unfortunately, the pLVCD->nmcd.uItemState does not contain valid\r
308                                 // information at this drawing stage. But we can check the whether the\r
309                                 // previous stage changed the background color of the item\r
310                                 if (pLVCD->clrTextBk == GetSysColor(COLOR_MENU))\r
311                                 {\r
312                                         HBRUSH brush;\r
313                                         brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
314                                         if (brush)\r
315                                         {\r
316                                                 ::FillRect(pLVCD->nmcd.hdc, &rect, brush);\r
317                                                 ::DeleteObject(brush);\r
318                                         }\r
319                                 }\r
320                         }\r
321 #endif\r
322                 }\r
323 \r
324                 if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTDETAIL, state))\r
325                         m_Theme.DrawParentBackground(m_hWnd, hdc, &rect);\r
326 \r
327                         m_Theme.DrawBackground(hdc, LVP_LISTDETAIL, state, &rect, NULL);\r
328         }\r
329         else\r
330         {\r
331                 HBRUSH brush;\r
332                 if (rItem.state & LVIS_SELECTED)\r
333                 {\r
334                         if (::GetFocus() == m_hWnd)\r
335                                 brush = ::CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT));\r
336                         else\r
337                                 brush = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));\r
338                 }\r
339                 else\r
340                 {\r
341                         //if (pLogEntry->bCopiedSelf)\r
342                         //      brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
343                         //else\r
344                                 brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));\r
345                 }\r
346                 if (brush == NULL)\r
347                         return;\r
348 \r
349                 ::FillRect(hdc, &rect, brush);\r
350                 ::DeleteObject(brush);\r
351                 \r
352         }\r
353 }\r
354 \r
355 void CGitLogListBase::DrawTagBranch(HDC hdc,CRect &rect,INT_PTR index)\r
356 {\r
357         GitRev* data = (GitRev*)m_arShownList.GetAt(index);\r
358         CRect rt=rect;\r
359         LVITEM   rItem;\r
360         SecureZeroMemory(&rItem, sizeof(LVITEM));\r
361         rItem.mask  = LVIF_STATE;\r
362         rItem.iItem = index;\r
363         rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
364         GetItem(&rItem);\r
365 \r
366         for(int i=0;i<m_HashMap[data->m_CommitHash].size();i++)\r
367         {\r
368                 CString str;\r
369                 str=m_HashMap[data->m_CommitHash][i];\r
370                 \r
371                 CString shortname;\r
372                 HBRUSH brush=0;\r
373                 shortname=_T("");\r
374                 if(GetShortName(str,shortname,_T("refs/heads/")))\r
375                 {\r
376                         brush = ::CreateSolidBrush(RGB(0xff, 0, 0));\r
377                 }else if(GetShortName(str,shortname,_T("refs/remotes/")))\r
378                 {\r
379                         brush = ::CreateSolidBrush(RGB(0xff, 0xff, 0));\r
380                 }\r
381                 else if(GetShortName(str,shortname,_T("refs/tags/")))\r
382                 {\r
383                         brush = ::CreateSolidBrush(RGB(0, 0, 0xff));\r
384                 }\r
385 \r
386                 if(!shortname.IsEmpty())\r
387                 {\r
388                         SIZE size;\r
389                         memset(&size,0,sizeof(SIZE));\r
390                         GetTextExtentPoint32(hdc, shortname,shortname.GetLength(),&size);\r
391                 \r
392                         rt.SetRect(rt.left,rt.top,rt.left+size.cx,rt.bottom);\r
393                         rt.right+=4;\r
394                         ::FillRect(hdc, &rt, brush);\r
395                         if (rItem.state & LVIS_SELECTED)\r
396                         {\r
397                                 COLORREF   clrOld   = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT));   \r
398                                 ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER);\r
399                                 ::SetTextColor(hdc,clrOld);   \r
400                         }else\r
401                         {\r
402                                 ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER);\r
403                         }\r
404 \r
405                         \r
406                         ::MoveToEx(hdc,rt.left,rt.top,NULL);\r
407                         ::LineTo(hdc,rt.right,rt.top);\r
408                         ::LineTo(hdc,rt.right,rt.bottom);\r
409                         ::LineTo(hdc,rt.left,rt.bottom);\r
410                         ::LineTo(hdc,rt.left,rt.top);\r
411                                 \r
412                         rt.left=rt.right+3;\r
413                 }\r
414                 if(brush)\r
415                         ::DeleteObject(brush);\r
416         }               \r
417         rt.right=rect.right;\r
418 \r
419         if (rItem.state & LVIS_SELECTED)\r
420         {\r
421                 COLORREF   clrOld   = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT));   \r
422                 ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT);\r
423                 ::SetTextColor(hdc,clrOld);   \r
424         }else\r
425         {\r
426                 ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT);\r
427         }\r
428         \r
429 }\r
430 \r
431 void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, int x2,\r
432                                       const COLORREF& col,int top\r
433                                                                           )  \r
434 {\r
435         int h = laneHeight / 2;\r
436         int m = (x1 + x2) / 2;\r
437         int r = (x2 - x1) / 3;\r
438         int d =  2 * r;\r
439 \r
440         #define P_CENTER m , h+top\r
441         #define P_0      x2, h+top\r
442         #define P_90     m , 0+top\r
443         #define P_180    x1, h+top\r
444         #define P_270    m , 2 * h+top\r
445         #define R_CENTER m - r, h - r+top, m - r+d, h - r+top+d\r
446 \r
447         //static QPen myPen(Qt::black, 2); // fast path here\r
448         CPen pen;\r
449         pen.CreatePen(PS_SOLID,2,col);\r
450         //myPen.setColor(col);\r
451         HPEN oldpen=(HPEN)::SelectObject(hdc,(HPEN)pen);\r
452 \r
453         //p->setPen(myPen);\r
454 \r
455         // vertical line\r
456         switch (type) {\r
457         case Lanes::ACTIVE:\r
458         case Lanes::NOT_ACTIVE:\r
459         case Lanes::MERGE_FORK:\r
460         case Lanes::MERGE_FORK_R:\r
461         case Lanes::MERGE_FORK_L:\r
462         case Lanes::JOIN:\r
463         case Lanes::JOIN_R:\r
464         case Lanes::JOIN_L:\r
465                 DrawLine(hdc,P_90,P_270);\r
466                 //p->drawLine(P_90, P_270);\r
467                 break;\r
468         case Lanes::HEAD:\r
469         case Lanes::HEAD_R:\r
470         case Lanes::HEAD_L:\r
471         case Lanes::BRANCH:\r
472                 DrawLine(hdc,P_CENTER,P_270);\r
473                 //p->drawLine(P_CENTER, P_270);\r
474                 break;\r
475         case Lanes::TAIL:\r
476         case Lanes::TAIL_R:\r
477         case Lanes::TAIL_L:\r
478         case Lanes::INITIAL:\r
479         case Lanes::BOUNDARY:\r
480         case Lanes::BOUNDARY_C:\r
481         case Lanes::BOUNDARY_R:\r
482         case Lanes::BOUNDARY_L:\r
483                 DrawLine(hdc,P_90, P_CENTER);\r
484                 //p->drawLine(P_90, P_CENTER);\r
485                 break;\r
486         default:\r
487                 break;\r
488         }\r
489 \r
490         // horizontal line\r
491         switch (type) {\r
492         case Lanes::MERGE_FORK:\r
493         case Lanes::JOIN:\r
494         case Lanes::HEAD:\r
495         case Lanes::TAIL:\r
496         case Lanes::CROSS:\r
497         case Lanes::CROSS_EMPTY:\r
498         case Lanes::BOUNDARY_C:\r
499                 DrawLine(hdc,P_180,P_0);\r
500                 //p->drawLine(P_180, P_0);\r
501                 break;\r
502         case Lanes::MERGE_FORK_R:\r
503         case Lanes::JOIN_R:\r
504         case Lanes::HEAD_R:\r
505         case Lanes::TAIL_R:\r
506         case Lanes::BOUNDARY_R:\r
507                 DrawLine(hdc,P_180,P_CENTER);\r
508                 //p->drawLine(P_180, P_CENTER);\r
509                 break;\r
510         case Lanes::MERGE_FORK_L:\r
511         case Lanes::JOIN_L:\r
512         case Lanes::HEAD_L:\r
513         case Lanes::TAIL_L:\r
514         case Lanes::BOUNDARY_L:\r
515                 DrawLine(hdc,P_CENTER,P_0);\r
516                 //p->drawLine(P_CENTER, P_0);\r
517                 break;\r
518         default:\r
519                 break;\r
520         }\r
521 \r
522         CBrush brush;\r
523         brush.CreateSolidBrush(col);\r
524         HBRUSH oldbrush=(HBRUSH)::SelectObject(hdc,(HBRUSH)brush);\r
525         // center symbol, e.g. rect or ellipse\r
526         switch (type) {\r
527         case Lanes::ACTIVE:\r
528         case Lanes::INITIAL:\r
529         case Lanes::BRANCH:\r
530 \r
531                 //p->setPen(Qt::NoPen);\r
532                 //p->setBrush(col);\r
533                 ::Ellipse(hdc, R_CENTER);\r
534                 //p->drawEllipse(R_CENTER);\r
535                 break;\r
536         case Lanes::MERGE_FORK:\r
537         case Lanes::MERGE_FORK_R:\r
538         case Lanes::MERGE_FORK_L:\r
539                 //p->setPen(Qt::NoPen);\r
540                 //p->setBrush(col);\r
541                 //p->drawRect(R_CENTER);\r
542                 Rectangle(hdc,R_CENTER);\r
543                 break;\r
544         case Lanes::UNAPPLIED:\r
545                 // Red minus sign\r
546                 //p->setPen(Qt::NoPen);\r
547                 //p->setBrush(Qt::red);\r
548                 //p->drawRect(m - r, h - 1, d, 2);\r
549                 ::Rectangle(hdc,m-r,h-1,d,2);\r
550                 break;\r
551         case Lanes::APPLIED:\r
552                 // Green plus sign\r
553                 //p->setPen(Qt::NoPen);\r
554                 //p->setBrush(DARK_GREEN);\r
555                 //p->drawRect(m - r, h - 1, d, 2);\r
556                 //p->drawRect(m - 1, h - r, 2, d);\r
557                 ::Rectangle(hdc,m-r,h-1,d,2);\r
558                 ::Rectangle(hdc,m-1,h-r,2,d);\r
559                 break;\r
560         case Lanes::BOUNDARY:\r
561                 //p->setBrush(back);\r
562                 //p->drawEllipse(R_CENTER);\r
563                 ::Ellipse(hdc, R_CENTER);\r
564                 break;\r
565         case Lanes::BOUNDARY_C:\r
566         case Lanes::BOUNDARY_R:\r
567         case Lanes::BOUNDARY_L:\r
568                 //p->setBrush(back);\r
569                 //p->drawRect(R_CENTER);\r
570                 ::Rectangle(hdc,R_CENTER);\r
571                 break;\r
572         default:\r
573                 break;\r
574         }\r
575 \r
576         ::SelectObject(hdc,oldpen);\r
577         ::SelectObject(hdc,oldbrush);\r
578         #undef P_CENTER\r
579         #undef P_0\r
580         #undef P_90\r
581         #undef P_180\r
582         #undef P_270\r
583         #undef R_CENTER\r
584 }\r
585 \r
586 void CGitLogListBase::DrawGraph(HDC hdc,CRect &rect,INT_PTR index)\r
587 {\r
588         //todo unfinished\r
589 //      return;\r
590         GitRev* data = (GitRev*)m_arShownList.GetAt(index);\r
591         CRect rt=rect;\r
592         LVITEM   rItem;\r
593         SecureZeroMemory(&rItem, sizeof(LVITEM));\r
594         rItem.mask  = LVIF_STATE;\r
595         rItem.iItem = index;\r
596         rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
597         GetItem(&rItem);\r
598 \r
599         static const COLORREF colors[Lanes::COLORS_NUM] = { RGB(0,0,0), RGB(0xFF,0,0), RGB(0,0xFF,0),\r
600                                                    RGB(0,0,0xFF), RGB(128,128,128), RGB(128,128,0),\r
601                                                    RGB(0,128,128), RGB(128,0,128) };\r
602 \r
603 \r
604 //      p->translate(QPoint(opt.rect.left(), opt.rect.top()));\r
605 \r
606 \r
607 \r
608         if (data->m_Lanes.size() == 0)\r
609                 m_logEntries.setLane(data->m_CommitHash);\r
610 \r
611         std::vector<int>& lanes=data->m_Lanes;\r
612         UINT laneNum = lanes.size();\r
613         UINT mergeLane = 0;\r
614         for (UINT i = 0; i < laneNum; i++)\r
615                 if (Lanes::isMerge(lanes[i])) {\r
616                         mergeLane = i;\r
617                         break;\r
618                 }\r
619 \r
620         int x1 = 0, x2 = 0;\r
621         int maxWidth = rect.Width();\r
622         int lw = 3 * rect.Height() / 4; //laneWidth() \r
623         for (UINT i = 0; i < laneNum && x2 < maxWidth; i++) {\r
624 \r
625                 x1 = x2;\r
626                 x2 += lw;\r
627 \r
628                 int ln = lanes[i];\r
629                 if (ln == Lanes::EMPTY)\r
630                         continue;\r
631 \r
632                 UINT col = (  Lanes:: isHead(ln) ||Lanes:: isTail(ln) || Lanes::isJoin(ln)\r
633                             || ln ==Lanes:: CROSS_EMPTY) ? mergeLane : i;\r
634 \r
635                 if (ln == Lanes::CROSS) {\r
636                         paintGraphLane(hdc, rect.Height(),Lanes::NOT_ACTIVE, x1, x2, colors[col % Lanes::COLORS_NUM],rect.top);\r
637                         paintGraphLane(hdc, rect.Height(),Lanes::CROSS, x1, x2, colors[mergeLane % Lanes::COLORS_NUM],rect.top);\r
638                 } else\r
639                         paintGraphLane(hdc, rect.Height(),ln, x1, x2, colors[col % Lanes::COLORS_NUM],rect.top);\r
640         }\r
641 \r
642         TRACE(_T("index %d %d\r\n"),index,data->m_Lanes.size());\r
643 }\r
644 \r
645 void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
646 {\r
647 \r
648         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
649         // Take the default processing unless we set this to something else below.\r
650         *pResult = CDRF_DODEFAULT;\r
651 \r
652         if (m_bNoDispUpdates)\r
653                 return;\r
654 \r
655 \r
656 \r
657         switch (pLVCD->nmcd.dwDrawStage)\r
658         {\r
659         case CDDS_PREPAINT:\r
660                 {\r
661                         *pResult = CDRF_NOTIFYITEMDRAW;\r
662                         return;\r
663                 }\r
664                 break;\r
665         case CDDS_ITEMPREPAINT:\r
666                 {\r
667                         // This is the prepaint stage for an item. Here's where we set the\r
668                         // item's text color. \r
669                         \r
670                         // Tell Windows to send draw notifications for each subitem.\r
671                         *pResult = CDRF_NOTIFYSUBITEMDRAW;\r
672 \r
673                         COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
674 \r
675                         if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
676                         {\r
677                                 GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec);\r
678                                 if (data)\r
679                                 {\r
680 #if 0\r
681                                         if (data->bCopiedSelf)\r
682                                         {\r
683                                                 // only change the background color if the item is not 'hot' (on vista with m_Themes enabled)\r
684                                                 if (!m_Theme.IsAppm_Themed() || !m_bVista || ((pLVCD->nmcd.uItemState & CDIS_HOT)==0))\r
685                                                         pLVCD->clrTextBk = GetSysColor(COLOR_MENU);\r
686                                         }\r
687 \r
688                                         if (data->bCopies)\r
689                                                 crText = m_Colors.GetColor(CColors::Modified);\r
690 #endif\r
691 //                                      if ((data->childStackDepth)||(m_mergedRevs.find(data->Rev) != m_mergedRevs.end()))\r
692 //                                              crText = GetSysColor(COLOR_GRAYTEXT);\r
693 //                                      if (data->Rev == m_wcRev)\r
694 //                                      {\r
695 //                                              SelectObject(pLVCD->nmcd.hdc, m_boldFont);\r
696                                                 // We changed the font, so we're returning CDRF_NEWFONT. This\r
697                                                 // tells the control to recalculate the extent of the text.\r
698 //                                              *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;\r
699 //                                      }\r
700                                 }\r
701                         }\r
702                         if (m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
703                         {\r
704                                 if (m_bStrictStopped)\r
705                                         crText = GetSysColor(COLOR_GRAYTEXT);\r
706                         }\r
707                         // Store the color back in the NMLVCUSTOMDRAW struct.\r
708                         pLVCD->clrText = crText;\r
709                         return;\r
710                 }\r
711                 break;\r
712         case CDDS_ITEMPREPAINT|CDDS_ITEM|CDDS_SUBITEM:\r
713                 {\r
714                         if ((m_bStrictStopped)&&(m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec))\r
715                         {\r
716                                 pLVCD->nmcd.uItemState &= ~(CDIS_SELECTED|CDIS_FOCUS);\r
717                         }\r
718 \r
719                         if (pLVCD->iSubItem == LOGLIST_GRAPH)\r
720                         {\r
721                                 if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
722                                 {\r
723                                         CRect rect;\r
724                                         GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
725                                         \r
726                                         FillBackGround(pLVCD->nmcd.hdc, (INT_PTR)pLVCD->nmcd.dwItemSpec,rect);\r
727                                         DrawGraph(pLVCD->nmcd.hdc,rect,pLVCD->nmcd.dwItemSpec);\r
728 \r
729                                         *pResult = CDRF_SKIPDEFAULT;\r
730                                         return;\r
731                                 \r
732                                 }\r
733                         }\r
734 \r
735                         if (pLVCD->iSubItem == LOGLIST_MESSAGE)\r
736                         {\r
737                                 if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
738                                 {\r
739                                         GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec);\r
740                                         if(!data->m_IsFull)\r
741                                         {\r
742                                                 if(data->SafeFetchFullInfo(&g_Git))\r
743                                                         this->Invalidate();\r
744                                                 TRACE(_T("Update ... %d\r\n"),pLVCD->nmcd.dwItemSpec);\r
745                                         }\r
746 \r
747                                         if(m_HashMap[data->m_CommitHash].size()!=0)\r
748                                         {\r
749                                                 CRect rect;\r
750 \r
751                                                 GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
752                                         \r
753                                                 FillBackGround(pLVCD->nmcd.hdc, (INT_PTR)pLVCD->nmcd.dwItemSpec,rect);\r
754                                                 DrawTagBranch(pLVCD->nmcd.hdc,rect,pLVCD->nmcd.dwItemSpec);\r
755 \r
756                                                 *pResult = CDRF_SKIPDEFAULT;\r
757                                                 return;\r
758 \r
759                                         }\r
760                                 }\r
761                         }\r
762                         \r
763                         if (pLVCD->iSubItem == 1)\r
764                         {\r
765                                 *pResult = CDRF_DODEFAULT;\r
766 \r
767                                 if (m_arShownList.GetCount() <= (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
768                                         return;\r
769 \r
770                                 int             nIcons = 0;\r
771                                 int             iconwidth = ::GetSystemMetrics(SM_CXSMICON);\r
772                                 int             iconheight = ::GetSystemMetrics(SM_CYSMICON);\r
773 \r
774                                 GitRev* pLogEntry = reinterpret_cast<GitRev *>(m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec));\r
775                                 CRect rect;\r
776                                 GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
777                                 // Get the selected state of the\r
778                                 // item being drawn.                                                    \r
779 \r
780                                 // Fill the background\r
781                                 FillBackGround(pLVCD->nmcd.hdc, (INT_PTR)pLVCD->nmcd.dwItemSpec,rect);\r
782                                 \r
783                                 // Draw the icon(s) into the compatible DC\r
784                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_MODIFIED)\r
785                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left + ICONITEMBORDER, rect.top, m_hModifiedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
786                                 nIcons++;\r
787 \r
788                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_ADDED)\r
789                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hAddedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
790                                 nIcons++;\r
791 \r
792                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_DELETED)\r
793                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hDeletedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
794                                 nIcons++;\r
795 \r
796                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
797                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hReplacedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
798                                 nIcons++;\r
799                                 *pResult = CDRF_SKIPDEFAULT;\r
800                                 return;\r
801                         }\r
802                 }\r
803                 break;\r
804         }\r
805         *pResult = CDRF_DODEFAULT;\r
806 \r
807 }\r
808 \r
809 // CGitLogListBase message handlers\r
810 \r
811 void CGitLogListBase::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
812 {\r
813         NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);\r
814 \r
815         // Create a pointer to the item\r
816         LV_ITEM* pItem = &(pDispInfo)->item;\r
817 \r
818         // Do the list need text information?\r
819         if (!(pItem->mask & LVIF_TEXT))\r
820                 return;\r
821 \r
822         // By default, clear text buffer.\r
823         lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
824 \r
825         bool bOutOfRange = pItem->iItem >= ShownCountWithStopped();\r
826         \r
827         *pResult = 0;\r
828         if (m_bNoDispUpdates || bOutOfRange)\r
829                 return;\r
830 \r
831         // Which item number?\r
832         int itemid = pItem->iItem;\r
833         GitRev * pLogEntry = NULL;\r
834         if (itemid < m_arShownList.GetCount())\r
835                 pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(pItem->iItem));\r
836 \r
837             \r
838         // Which column?\r
839         switch (pItem->iSubItem)\r
840         {\r
841         case this->LOGLIST_GRAPH:       //Graphic\r
842                 if (pLogEntry)\r
843                 {\r
844                 }\r
845                 break;\r
846         case this->LOGLIST_ACTION: //action -- no text in the column\r
847                 break;\r
848         case this->LOGLIST_MESSAGE: //Message\r
849                 if (pLogEntry)\r
850                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_Subject, pItem->cchTextMax);\r
851                 break;\r
852         case this->LOGLIST_AUTHOR: //Author\r
853                 if (pLogEntry)\r
854                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorName, pItem->cchTextMax);\r
855                 break;\r
856         case this->LOGLIST_DATE: //Date\r
857                 if (pLogEntry)\r
858                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorDate.Format(_T("%Y-%m-%d %H:%M")), pItem->cchTextMax);\r
859                 break;\r
860                 \r
861         case 5:\r
862 \r
863                 break;\r
864         default:\r
865                 ASSERT(false);\r
866         }\r
867 }\r
868 \r
869 void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)\r
870 {\r
871 \r
872         int selIndex = GetSelectionMark();\r
873         if (selIndex < 0)\r
874                 return; // nothing selected, nothing to do with a context menu\r
875 \r
876         // if the user selected the info text telling about not all revisions shown due to\r
877         // the "stop on copy/rename" option, we also don't show the context menu\r
878         if ((m_bStrictStopped)&&(selIndex == m_arShownList.GetCount()))\r
879                 return;\r
880 \r
881         // if the context menu is invoked through the keyboard, we have to use\r
882         // a calculated position on where to anchor the menu on\r
883         if ((point.x == -1) && (point.y == -1))\r
884         {\r
885                 CRect rect;\r
886                 GetItemRect(selIndex, &rect, LVIR_LABEL);\r
887                 ClientToScreen(&rect);\r
888                 point = rect.CenterPoint();\r
889         }\r
890         m_nSearchIndex = selIndex;\r
891         m_bCancelled = FALSE;\r
892 \r
893         // calculate some information the context menu commands can use\r
894 //      CString pathURL = GetURLFromPath(m_path);\r
895 \r
896         POSITION pos = GetFirstSelectedItemPosition();\r
897         int indexNext = GetNextSelectedItem(pos);\r
898         if (indexNext < 0)\r
899                 return;\r
900 \r
901         GitRev* pSelLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(indexNext));\r
902 #if 0\r
903         GitRev revSelected = pSelLogEntry->Rev;\r
904         GitRev revPrevious = git_revnum_t(revSelected)-1;\r
905         if ((pSelLogEntry->pArChangedPaths)&&(pSelLogEntry->pArChangedPaths->GetCount() <= 2))\r
906         {\r
907                 for (int i=0; i<pSelLogEntry->pArChangedPaths->GetCount(); ++i)\r
908                 {\r
909                         LogChangedPath * changedpath = (LogChangedPath *)pSelLogEntry->pArChangedPaths->GetAt(i);\r
910                         if (changedpath->lCopyFromRev)\r
911                                 revPrevious = changedpath->lCopyFromRev;\r
912                 }\r
913         }\r
914         GitRev revSelected2;\r
915         if (pos)\r
916         {\r
917                 PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
918                 revSelected2 = pLogEntry->Rev;\r
919         }\r
920         bool bAllFromTheSameAuthor = true;\r
921         CString firstAuthor;\r
922         CLogDataVector selEntries;\r
923         GitRev revLowest, revHighest;\r
924         GitRevRangeArray revisionRanges;\r
925         {\r
926                 POSITION pos = GetFirstSelectedItemPosition();\r
927                 PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
928                 revisionRanges.AddRevision(pLogEntry->Rev);\r
929                 selEntries.push_back(pLogEntry);\r
930                 firstAuthor = pLogEntry->sAuthor;\r
931                 revLowest = pLogEntry->Rev;\r
932                 revHighest = pLogEntry->Rev;\r
933                 while (pos)\r
934                 {\r
935                         pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
936                         revisionRanges.AddRevision(pLogEntry->Rev);\r
937                         selEntries.push_back(pLogEntry);\r
938                         if (firstAuthor.Compare(pLogEntry->sAuthor))\r
939                                 bAllFromTheSameAuthor = false;\r
940                         revLowest = (git_revnum_t(pLogEntry->Rev) > git_revnum_t(revLowest) ? revLowest : pLogEntry->Rev);\r
941                         revHighest = (git_revnum_t(pLogEntry->Rev) < git_revnum_t(revHighest) ? revHighest : pLogEntry->Rev);\r
942                 }\r
943         }\r
944 \r
945 #endif\r
946 \r
947         int FirstSelect=-1, LastSelect=-1;\r
948         pos = GetFirstSelectedItemPosition();\r
949         FirstSelect = GetNextSelectedItem(pos);\r
950         while(pos)\r
951         {\r
952                 LastSelect = GetNextSelectedItem(pos);\r
953         }\r
954         //entry is selected, now show the popup menu\r
955         CIconMenu popup;\r
956         if (popup.CreatePopupMenu())\r
957         {\r
958                 if (GetSelectedCount() == 1)\r
959                 {\r
960 #if 0\r
961                         if (!m_path.IsDirectory())\r
962                         {\r
963                                 if (m_hasWC)\r
964                                 {\r
965                                         popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
966                                         popup.AppendMenuIcon(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME);\r
967                                 }\r
968                                 popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
969                                 popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
970                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
971                                 popup.AppendMenuIcon(ID_SAVEAS, IDS_LOG_POPUP_SAVE, IDI_SAVEAS);\r
972                                 popup.AppendMenuIcon(ID_OPEN, IDS_LOG_POPUP_OPEN, IDI_OPEN);\r
973                                 popup.AppendMenuIcon(ID_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
974                                 popup.AppendMenuIcon(ID_BLAME, IDS_LOG_POPUP_BLAME, IDI_BLAME);\r
975                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
976                         }\r
977                         else\r
978 #endif \r
979                         {\r
980                                 if (m_hasWC)\r
981                                 {\r
982                                         popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
983                                         // TODO:\r
984                                         // TortoiseMerge could be improved to take a /blame switch\r
985                                         // and then not 'cat' the files from a unified diff but\r
986                                         // blame then.\r
987                                         // But until that's implemented, the context menu entry for\r
988                                         // this feature is commented out.\r
989                                         //popup.AppendMenu(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME);\r
990                                 }\r
991                                 popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
992                                 popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
993                                 //popup.AppendMenuIcon(ID_BLAMEWITHPREVIOUS, IDS_LOG_POPUP_BLAMEWITHPREVIOUS, IDI_BLAME);\r
994                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
995                         }\r
996 \r
997 //                      if (!m_ProjectProperties.sWebViewerRev.IsEmpty())\r
998 //                      {\r
999 //                              popup.AppendMenuIcon(ID_VIEWREV, IDS_LOG_POPUP_VIEWREV);\r
1000 //                      }\r
1001 //                      if (!m_ProjectProperties.sWebViewerPathRev.IsEmpty())\r
1002 //                      {\r
1003 //                              popup.AppendMenuIcon(ID_VIEWPATHREV, IDS_LOG_POPUP_VIEWPATHREV);\r
1004 //                      }\r
1005 //                      if ((!m_ProjectProperties.sWebViewerPathRev.IsEmpty())||\r
1006 //                              (!m_ProjectProperties.sWebViewerRev.IsEmpty()))\r
1007 //                      {\r
1008 //                              popup.AppendMenu(MF_SEPARATOR, NULL);\r
1009 //                      }\r
1010 \r
1011                         //if (m_hasWC)\r
1012                         //      popup.AppendMenuIcon(ID_REVERTTOREV, IDS_LOG_POPUP_REVERTTOREV, IDI_REVERT);\r
1013                         //if (m_hasWC)\r
1014                         //      popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREV, IDI_REVERT);\r
1015                         //if (m_hasWC)\r
1016                         //      popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREV, IDI_MERGE);\r
1017                         \r
1018                         popup.AppendMenuIcon(ID_SWITCHTOREV, _T("Switch/Checkout to this") , IDI_SWITCH);\r
1019                         popup.AppendMenuIcon(ID_CREATE_BRANCH, _T("Create Branch at this version") , IDI_COPY);\r
1020                         popup.AppendMenuIcon(ID_CREATE_TAG, _T("Create Tag at this version"), IDI_COPY);\r
1021                         popup.AppendMenuIcon(ID_CHERRY_PICK, _T("Cherry Pick this version"), IDI_EXPORT);\r
1022                         popup.AppendMenuIcon(ID_EXPORT, _T("Export this version"), IDI_EXPORT);\r
1023                         \r
1024 \r
1025                         popup.AppendMenu(MF_SEPARATOR, NULL);\r
1026                 }\r
1027                 else if (GetSelectedCount() >= 2)\r
1028                 {\r
1029                         bool bAddSeparator = false;\r
1030                         if (IsSelectionContinuous() || (GetSelectedCount() == 2))\r
1031                         {\r
1032                                 popup.AppendMenuIcon(ID_COMPARETWO, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);\r
1033                         }\r
1034                         if (GetSelectedCount() == 2)\r
1035                         {\r
1036                                 //popup.AppendMenuIcon(ID_BLAMETWO, IDS_LOG_POPUP_BLAMEREVS, IDI_BLAME);\r
1037                                 popup.AppendMenuIcon(ID_GNUDIFF2, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
1038                                 bAddSeparator = true;\r
1039                         }\r
1040                         if (m_hasWC)\r
1041                         {\r
1042                                 //popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREVS, IDI_REVERT);\r
1043 //                              if (m_hasWC)\r
1044 //                                      popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREVS, IDI_MERGE);\r
1045                                 bAddSeparator = true;\r
1046                         }\r
1047                         if (bAddSeparator)\r
1048                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
1049                 }\r
1050 #if 0\r
1051 //              if ((selEntries.size() > 0)&&(bAllFromTheSameAuthor))\r
1052 //              {\r
1053 //                      popup.AppendMenuIcon(ID_EDITAUTHOR, IDS_LOG_POPUP_EDITAUTHOR);\r
1054 //              }\r
1055 //              if (GetSelectedCount() == 1)\r
1056 //              {\r
1057 //                      popup.AppendMenuIcon(ID_EDITLOG, IDS_LOG_POPUP_EDITLOG);\r
1058 //                      popup.AppendMenuIcon(ID_REVPROPS, IDS_REPOBROWSE_SHOWREVPROP, IDI_PROPERTIES); // "Show Revision Properties"\r
1059 //                      popup.AppendMenu(MF_SEPARATOR, NULL);\r
1060 //              }\r
1061 #endif\r
1062 \r
1063                 \r
1064                 if (GetSelectedCount() == 1)\r
1065                 {\r
1066                         popup.AppendMenuIcon(ID_COPYHASH, _T("Copy Commit Hash"));\r
1067                 }\r
1068                 if (GetSelectedCount() != 0)\r
1069                 {\r
1070                         popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD);\r
1071                 }\r
1072                 popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND);\r
1073 \r
1074                 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
1075 //              DialogEnableWindow(IDOK, FALSE);\r
1076 //              SetPromptApp(&theApp);\r
1077         \r
1078                 this->ContextMenuAction(cmd, FirstSelect, LastSelect);\r
1079                 \r
1080 //              EnableOKButton();\r
1081         } // if (popup.CreatePopupMenu())\r
1082 \r
1083 }\r
1084 \r
1085 bool CGitLogListBase::IsSelectionContinuous()\r
1086 {\r
1087         if ( GetSelectedCount()==1 )\r
1088         {\r
1089                 // if only one revision is selected, the selection is of course\r
1090                 // continuous\r
1091                 return true;\r
1092         }\r
1093 \r
1094         POSITION pos = GetFirstSelectedItemPosition();\r
1095         bool bContinuous = (m_arShownList.GetCount() == (INT_PTR)m_logEntries.size());\r
1096         if (bContinuous)\r
1097         {\r
1098                 int itemindex = GetNextSelectedItem(pos);\r
1099                 while (pos)\r
1100                 {\r
1101                         int nextindex = GetNextSelectedItem(pos);\r
1102                         if (nextindex - itemindex > 1)\r
1103                         {\r
1104                                 bContinuous = false;\r
1105                                 break;\r
1106                         }\r
1107                         itemindex = nextindex;\r
1108                 }\r
1109         }\r
1110         return bContinuous;\r
1111 }\r
1112 \r
1113 void CGitLogListBase::CopySelectionToClipBoard(bool HashOnly)\r
1114 {\r
1115 \r
1116         CString sClipdata;\r
1117         POSITION pos = GetFirstSelectedItemPosition();\r
1118         if (pos != NULL)\r
1119         {\r
1120                 CString sRev;\r
1121                 sRev.LoadString(IDS_LOG_REVISION);\r
1122                 CString sAuthor;\r
1123                 sAuthor.LoadString(IDS_LOG_AUTHOR);\r
1124                 CString sDate;\r
1125                 sDate.LoadString(IDS_LOG_DATE);\r
1126                 CString sMessage;\r
1127                 sMessage.LoadString(IDS_LOG_MESSAGE);\r
1128                 while (pos)\r
1129                 {\r
1130                         CString sLogCopyText;\r
1131                         CString sPaths;\r
1132                         GitRev * pLogEntry = reinterpret_cast<GitRev *>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
1133 \r
1134                         if(!HashOnly)\r
1135                         {\r
1136                                 //pLogEntry->m_Files\r
1137                                 //LogChangedPathArray * cpatharray = pLogEntry->pArChangedPaths;\r
1138                         \r
1139                                 for (int cpPathIndex = 0; cpPathIndex<pLogEntry->m_Files.GetCount(); ++cpPathIndex)\r
1140                                 {\r
1141                                         sPaths += ((CTGitPath&)pLogEntry->m_Files[cpPathIndex]).GetActionName() + _T(" : ") + pLogEntry->m_Files[cpPathIndex].GetGitPathString();\r
1142                                         sPaths += _T("\r\n");\r
1143                                 }\r
1144                                 sPaths.Trim();\r
1145                                 sLogCopyText.Format(_T("%s: %s\r\n%s: %s\r\n%s: %s\r\n%s:\r\n%s\r\n----\r\n%s\r\n\r\n"),\r
1146                                         (LPCTSTR)sRev, pLogEntry->m_CommitHash,\r
1147                                         (LPCTSTR)sAuthor, (LPCTSTR)pLogEntry->m_AuthorName,\r
1148                                         (LPCTSTR)sDate, (LPCTSTR)pLogEntry->m_AuthorDate.Format(_T("%Y-%m-%d %H:%M")),\r
1149                                         (LPCTSTR)sMessage, pLogEntry->m_Subject+_T("\r\n")+pLogEntry->m_Body,\r
1150                                         (LPCTSTR)sPaths);\r
1151                                 sClipdata +=  sLogCopyText;\r
1152                         }else\r
1153                         {\r
1154                                 sClipdata += pLogEntry->m_CommitHash;\r
1155                                 break;\r
1156                         }\r
1157 \r
1158                 }\r
1159                 CStringUtils::WriteAsciiStringToClipboard(sClipdata, GetSafeHwnd());\r
1160         }\r
1161 \r
1162 }\r
1163 \r
1164 void CGitLogListBase::DiffSelectedRevWithPrevious()\r
1165 {\r
1166 #if 0\r
1167         if (m_bThreadRunning)\r
1168                 return;\r
1169         UpdateLogInfoLabel();\r
1170         int selIndex = m_LogList.GetSelectionMark();\r
1171         if (selIndex < 0)\r
1172                 return;\r
1173         int selCount = m_LogList.GetSelectedCount();\r
1174         if (selCount != 1)\r
1175                 return;\r
1176 \r
1177         // Find selected entry in the log list\r
1178         POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
1179         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
1180         long rev1 = pLogEntry->Rev;\r
1181         long rev2 = rev1-1;\r
1182         CTGitPath path = m_path;\r
1183 \r
1184         // See how many files under the relative root were changed in selected revision\r
1185         int nChanged = 0;\r
1186         LogChangedPath * changed = NULL;\r
1187         for (INT_PTR c = 0; c < pLogEntry->pArChangedPaths->GetCount(); ++c)\r
1188         {\r
1189                 LogChangedPath * cpath = pLogEntry->pArChangedPaths->GetAt(c);\r
1190                 if (cpath  &&  cpath -> sPath.Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)==0)\r
1191                 {\r
1192                         ++nChanged;\r
1193                         changed = cpath;\r
1194                 }\r
1195         }\r
1196 \r
1197         if (m_path.IsDirectory() && nChanged == 1) \r
1198         {\r
1199                 // We're looking at the log for a directory and only one file under dir was changed in the revision\r
1200                 // Do diff on that file instead of whole directory\r
1201                 path.AppendPathString(changed->sPath.Mid(m_sRelativeRoot.GetLength()));\r
1202         } \r
1203 \r
1204         m_bCancelled = FALSE;\r
1205         DialogEnableWindow(IDOK, FALSE);\r
1206         SetPromptApp(&theApp);\r
1207         theApp.DoWaitCursor(1);\r
1208 \r
1209         if (PromptShown())\r
1210         {\r
1211                 GitDiff diff(this, m_hWnd, true);\r
1212                 diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
1213                 diff.SetHEADPeg(m_LogRevision);\r
1214                 diff.ShowCompare(path, rev2, path, rev1);\r
1215         }\r
1216         else\r
1217         {\r
1218                 CAppUtils::StartShowCompare(m_hWnd, path, rev2, path, rev1, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
1219         }\r
1220 \r
1221         theApp.DoWaitCursor(-1);\r
1222         EnableOKButton();\r
1223 #endif\r
1224 }\r
1225 \r
1226 void CGitLogListBase::OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
1227 {\r
1228         LPNMLVFINDITEM pFindInfo = reinterpret_cast<LPNMLVFINDITEM>(pNMHDR);\r
1229         *pResult = -1;\r
1230         \r
1231         if (pFindInfo->lvfi.flags & LVFI_PARAM)\r
1232                 return; \r
1233         if ((pFindInfo->iStart < 0)||(pFindInfo->iStart >= m_arShownList.GetCount()))\r
1234                 return;\r
1235         if (pFindInfo->lvfi.psz == 0)\r
1236                 return;\r
1237 #if 0\r
1238         CString sCmp = pFindInfo->lvfi.psz;\r
1239         CString sRev;   \r
1240         for (int i=pFindInfo->iStart; i<m_arShownList.GetCount(); ++i)\r
1241         {\r
1242                 GitRev * pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(i));\r
1243                 sRev.Format(_T("%ld"), pLogEntry->Rev);\r
1244                 if (pFindInfo->lvfi.flags & LVFI_PARTIAL)\r
1245                 {\r
1246                         if (sCmp.Compare(sRev.Left(sCmp.GetLength()))==0)\r
1247                         {\r
1248                                 *pResult = i;\r
1249                                 return;\r
1250                         }\r
1251                 }\r
1252                 else\r
1253                 {\r
1254                         if (sCmp.Compare(sRev)==0)\r
1255                         {\r
1256                                 *pResult = i;\r
1257                                 return;\r
1258                         }\r
1259                 }\r
1260         }\r
1261         if (pFindInfo->lvfi.flags & LVFI_WRAP)\r
1262         {\r
1263                 for (int i=0; i<pFindInfo->iStart; ++i)\r
1264                 {\r
1265                         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(i));\r
1266                         sRev.Format(_T("%ld"), pLogEntry->Rev);\r
1267                         if (pFindInfo->lvfi.flags & LVFI_PARTIAL)\r
1268                         {\r
1269                                 if (sCmp.Compare(sRev.Left(sCmp.GetLength()))==0)\r
1270                                 {\r
1271                                         *pResult = i;\r
1272                                         return;\r
1273                                 }\r
1274                         }\r
1275                         else\r
1276                         {\r
1277                                 if (sCmp.Compare(sRev)==0)\r
1278                                 {\r
1279                                         *pResult = i;\r
1280                                         return;\r
1281                                 }\r
1282                         }\r
1283                 }\r
1284         }\r
1285 #endif\r
1286         *pResult = -1;\r
1287 }\r
1288 \r
1289 int CGitLogListBase::FillGitShortLog()\r
1290 {\r
1291         ClearText();\r
1292 \r
1293         this->m_logEntries.ClearAll();\r
1294         this->m_logEntries.ParserShortLog();\r
1295 \r
1296         //this->m_logEntries.ParserFromLog();\r
1297         SetItemCountEx(this->m_logEntries.size());\r
1298 \r
1299         this->m_arShownList.RemoveAll();\r
1300 \r
1301         for(int i=0;i<m_logEntries.size();i++)\r
1302                 this->m_arShownList.Add(&m_logEntries[i]);\r
1303 \r
1304         return 0;\r
1305 }\r
1306 \r
1307 BOOL CGitLogListBase::PreTranslateMessage(MSG* pMsg)\r
1308 {\r
1309         // Skip Ctrl-C when copying text out of the log message or search filter\r
1310         BOOL bSkipAccelerator = ( pMsg->message == WM_KEYDOWN && pMsg->wParam=='C' && (GetFocus()==GetDlgItem(IDC_MSGVIEW) || GetFocus()==GetDlgItem(IDC_SEARCHEDIT) ) && GetKeyState(VK_CONTROL)&0x8000 );\r
1311         if (pMsg->message == WM_KEYDOWN && pMsg->wParam=='\r')\r
1312         {\r
1313                 //if (GetFocus()==GetDlgItem(IDC_LOGLIST))\r
1314                 {\r
1315                         if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
1316                         {\r
1317                                 DiffSelectedRevWithPrevious();\r
1318                                 return TRUE;\r
1319                         }\r
1320                 }\r
1321 #if 0\r
1322                 if (GetFocus()==GetDlgItem(IDC_LOGMSG))\r
1323                 {\r
1324                         DiffSelectedFile();\r
1325                         return TRUE;\r
1326                 }\r
1327 #endif\r
1328         }\r
1329 \r
1330 #if 0\r
1331         if (m_hAccel && !bSkipAccelerator)\r
1332         {\r
1333                 int ret = TranslateAccelerator(m_hWnd, m_hAccel, pMsg);\r
1334                 if (ret)\r
1335                         return TRUE;\r
1336         }\r
1337         \r
1338 #endif\r
1339         //m_tooltips.RelayEvent(pMsg);\r
1340         return __super::PreTranslateMessage(pMsg);\r
1341 }\r
1342 \r
1343 void CGitLogListBase::OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult)\r
1344 {\r
1345         // a double click on an entry in the revision list has happened\r
1346         *pResult = 0;\r
1347 \r
1348   if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
1349           DiffSelectedRevWithPrevious();\r
1350 }\r
1351 \r
1352 int CGitLogListBase::FetchLogAsync(CALLBACK_PROCESS *proc,void * data)\r
1353 {\r
1354         m_ProcCallBack=proc;\r
1355         m_ProcData=data;\r
1356 \r
1357         InterlockedExchange(&m_bThreadRunning, TRUE);\r
1358         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
1359         if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
1360         {\r
1361                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
1362                 InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
1363                 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
1364                 return -1;\r
1365         }\r
1366         return 0;\r
1367 }\r
1368 \r
1369 //this is the thread function which calls the subversion function\r
1370 UINT CGitLogListBase::LogThreadEntry(LPVOID pVoid)\r
1371 {\r
1372         return ((CGitLogListBase*)pVoid)->LogThread();\r
1373 }\r
1374 \r
1375 void CGitLogListBase::GetTimeRange(CTime &oldest, CTime &latest)\r
1376 {\r
1377         //CTime time;\r
1378         oldest=CTime::GetCurrentTime();\r
1379         latest=CTime(1971,1,2,0,0,0);\r
1380         for(int i=0;i<m_logEntries.size();i++)\r
1381         {\r
1382                 if(m_logEntries[i].m_AuthorDate.GetTime() < oldest.GetTime())\r
1383                         oldest = m_logEntries[i].m_AuthorDate.GetTime();\r
1384 \r
1385                 if(m_logEntries[i].m_AuthorDate.GetTime() > latest.GetTime())\r
1386                         latest = m_logEntries[i].m_AuthorDate.GetTime();\r
1387 \r
1388         }\r
1389 }\r
1390 \r
1391 UINT CGitLogListBase::LogThread()\r
1392 {\r
1393 \r
1394         if(m_ProcCallBack)\r
1395                 m_ProcCallBack(m_ProcData,GITLOG_START);\r
1396 \r
1397         InterlockedExchange(&m_bThreadRunning, TRUE);\r
1398         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
1399 \r
1400     //does the user force the cache to refresh (shift or control key down)?\r
1401     bool refresh =    (GetKeyState (VK_CONTROL) < 0) \r
1402                    || (GetKeyState (VK_SHIFT) < 0);\r
1403 \r
1404         //disable the "Get All" button while we're receiving\r
1405         //log messages.\r
1406 \r
1407         CString temp;\r
1408         temp.LoadString(IDS_PROGRESSWAIT);\r
1409         ShowText(temp, true);\r
1410 \r
1411         FillGitShortLog();\r
1412         \r
1413         \r
1414 \r
1415         RedrawItems(0, m_arShownList.GetCount());\r
1416         SetRedraw(false);\r
1417         ResizeAllListCtrlCols();\r
1418         SetRedraw(true);\r
1419 \r
1420         if ( m_pStoreSelection )\r
1421         {\r
1422                 // Deleting the instance will restore the\r
1423                 // selection of the CLogDlg.\r
1424                 delete m_pStoreSelection;\r
1425                 m_pStoreSelection = NULL;\r
1426         }\r
1427         else\r
1428         {\r
1429                 // If no selection has been set then this must be the first time\r
1430                 // the revisions are shown. Let's preselect the topmost revision.\r
1431                 if ( GetItemCount()>0 )\r
1432                 {\r
1433                         SetSelectionMark(0);\r
1434                         SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);\r
1435                 }\r
1436         }\r
1437         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
1438 \r
1439         int index=0;\r
1440         int updated=0;\r
1441         int percent=0;\r
1442         while(1)\r
1443         {\r
1444                 for(int i=0;i<m_logEntries.size();i++)\r
1445                 {\r
1446                         if(!m_logEntries.FetchFullInfo(i))\r
1447                         {\r
1448                                 updated++;\r
1449                         }\r
1450                         \r
1451                         percent=updated*98/m_logEntries.size() + GITLOG_START+1;\r
1452                         if(percent == GITLOG_END)\r
1453                                 percent == GITLOG_END -1;\r
1454                         \r
1455                         if(m_ProcCallBack)\r
1456                                 m_ProcCallBack(m_ProcData,percent);\r
1457                 }\r
1458                 if(updated==m_logEntries.size())\r
1459                         break;\r
1460         }\r
1461 \r
1462         //RefreshCursor();\r
1463         // make sure the filter is applied (if any) now, after we refreshed/fetched\r
1464         // the log messages\r
1465 \r
1466         \r
1467 \r
1468         if(m_ProcCallBack)\r
1469                 m_ProcCallBack(m_ProcData,GITLOG_END);\r
1470 \r
1471         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1472 \r
1473         return 0;\r
1474 }\r
1475 \r
1476 void CGitLogListBase::Refresh()\r
1477 {\r
1478         if(!m_bThreadRunning)\r
1479         {\r
1480                 this->SetItemCountEx(0);\r
1481                 m_logEntries.clear();\r
1482                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
1483                 InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
1484                 if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
1485                 {\r
1486                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1487                         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
1488                         CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
1489                 }\r
1490                 m_sFilterText.Empty();\r
1491                 m_From=CTime(1970,1,2,0,0,0);\r
1492                 m_To=CTime::GetCurrentTime();\r
1493         }\r
1494 }\r
1495 bool CGitLogListBase::ValidateRegexp(LPCTSTR regexp_str, tr1::wregex& pat, bool bMatchCase /* = false */)\r
1496 {\r
1497         try\r
1498         {\r
1499                 tr1::regex_constants::syntax_option_type type = tr1::regex_constants::ECMAScript;\r
1500                 if (!bMatchCase)\r
1501                         type |= tr1::regex_constants::icase;\r
1502                 pat = tr1::wregex(regexp_str, type);\r
1503                 return true;\r
1504         }\r
1505         catch (exception) {}\r
1506         return false;\r
1507 }\r
1508 \r
1509 void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist)\r
1510 {\r
1511 \r
1512         pShownlist->RemoveAll();\r
1513         tr1::wregex pat;//(_T("Remove"), tr1::regex_constants::icase);\r
1514         bool bRegex = false;\r
1515         if (m_bFilterWithRegex)\r
1516                 bRegex = ValidateRegexp(m_sFilterText, pat, false);\r
1517 \r
1518         tr1::regex_constants::match_flag_type flags = tr1::regex_constants::match_any;\r
1519         CString sRev;\r
1520         for (DWORD i=0; i<m_logEntries.size(); ++i)\r
1521         {\r
1522                 if ((bRegex)&&(m_bFilterWithRegex))\r
1523                 {\r
1524 #if 0\r
1525                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_BUGID))\r
1526                         {\r
1527                                 ATLTRACE(_T("bugID = \"%s\"\n"), (LPCTSTR)m_logEntries[i]->sBugIDs);\r
1528                                 if (regex_search(wstring((LPCTSTR)m_logEntries[i]->sBugIDs), pat, flags)&&IsEntryInDateRange(i))\r
1529                                 {\r
1530                                         pShownlist->Add(m_logEntries[i]);\r
1531                                         continue;\r
1532                                 }\r
1533                         }\r
1534 #endif\r
1535                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_MESSAGES))\r
1536                         {\r
1537                                 ATLTRACE(_T("messge = \"%s\"\n"),m_logEntries[i].m_Subject);\r
1538                                 if (regex_search(wstring((LPCTSTR)m_logEntries[i].m_Subject), pat, flags)&&IsEntryInDateRange(i))\r
1539                                 {\r
1540                                         pShownlist->Add(&m_logEntries[i]);\r
1541                                         continue;\r
1542                                 }\r
1543 \r
1544                                 ATLTRACE(_T("messge = \"%s\"\n"),m_logEntries[i].m_Body);\r
1545                                 if (regex_search(wstring((LPCTSTR)m_logEntries[i].m_Body), pat, flags)&&IsEntryInDateRange(i))\r
1546                                 {\r
1547                                         pShownlist->Add(&m_logEntries[i]);\r
1548                                         continue;\r
1549                                 }\r
1550                         }\r
1551 #if 0\r
1552                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_PATHS))\r
1553                         {\r
1554                                 LogChangedPathArray * cpatharray = m_logEntries[i]->pArChangedPaths;\r
1555 \r
1556                                 bool bGoing = true;\r
1557                                 for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount() && bGoing; ++cpPathIndex)\r
1558                                 {\r
1559                                         LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
1560                                         if (regex_search(wstring((LPCTSTR)cpath->sCopyFromPath), pat, flags)&&IsEntryInDateRange(i))\r
1561                                         {\r
1562                                                 pShownlist->Add(m_logEntries[i]);\r
1563                                                 bGoing = false;\r
1564                                                 continue;\r
1565                                         }\r
1566                                         if (regex_search(wstring((LPCTSTR)cpath->sPath), pat, flags)&&IsEntryInDateRange(i))\r
1567                                         {\r
1568                                                 pShownlist->Add(m_logEntries[i]);\r
1569                                                 bGoing = false;\r
1570                                                 continue;\r
1571                                         }\r
1572                                         if (regex_search(wstring((LPCTSTR)cpath->GetAction()), pat, flags)&&IsEntryInDateRange(i))\r
1573                                         {\r
1574                                                 pShownlist->Add(m_logEntries[i]);\r
1575                                                 bGoing = false;\r
1576                                                 continue;\r
1577                                         }\r
1578                                 }\r
1579                                 if (!bGoing)\r
1580                                         continue;\r
1581                         }\r
1582 #endif\r
1583                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_AUTHORS))\r
1584                         {\r
1585                                 if (regex_search(wstring((LPCTSTR)m_logEntries[i].m_AuthorName), pat, flags)&&IsEntryInDateRange(i))\r
1586                                 {\r
1587                                         pShownlist->Add(&m_logEntries[i]);\r
1588                                         continue;\r
1589                                 }\r
1590                         }\r
1591                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_REVS))\r
1592                         {\r
1593                                 sRev.Format(_T("%ld"), m_logEntries[i].m_CommitHash);\r
1594                                 if (regex_search(wstring((LPCTSTR)sRev), pat, flags)&&IsEntryInDateRange(i))\r
1595                                 {\r
1596                                         pShownlist->Add(&m_logEntries[i]);\r
1597                                         continue;\r
1598                                 }\r
1599                         }\r
1600                 } // if (bRegex)\r
1601                 else\r
1602                 {\r
1603                         CString find = m_sFilterText;\r
1604                         find.MakeLower();\r
1605 #if 0\r
1606                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_BUGID))\r
1607                         {\r
1608                                 CString sBugIDs = m_logEntries[i]->sBugIDs;\r
1609 \r
1610                                 sBugIDs = sBugIDs.MakeLower();\r
1611                                 if ((sBugIDs.Find(find) >= 0)&&(IsEntryInDateRange(i)))\r
1612                                 {\r
1613                                         pShownlist->Add(m_logEntries[i]);\r
1614                                         continue;\r
1615                                 }\r
1616                         }\r
1617 #endif\r
1618                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_MESSAGES))\r
1619                         {\r
1620                                 CString msg = m_logEntries[i].m_Subject;\r
1621 \r
1622                                 msg = msg.MakeLower();\r
1623                                 if ((msg.Find(find) >= 0)&&(IsEntryInDateRange(i)))\r
1624                                 {\r
1625                                         pShownlist->Add(&m_logEntries[i]);\r
1626                                         continue;\r
1627                                 }\r
1628                                 msg = m_logEntries[i].m_Body;\r
1629 \r
1630                                 msg = msg.MakeLower();\r
1631                                 if ((msg.Find(find) >= 0)&&(IsEntryInDateRange(i)))\r
1632                                 {\r
1633                                         pShownlist->Add(&m_logEntries[i]);\r
1634                                         continue;\r
1635                                 }\r
1636                         }\r
1637 #if 0\r
1638                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_PATHS))\r
1639                         {\r
1640                                 LogChangedPathArray * cpatharray = m_logEntries[i]->pArChangedPaths;\r
1641 \r
1642                                 bool bGoing = true;\r
1643                                 for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount() && bGoing; ++cpPathIndex)\r
1644                                 {\r
1645                                         LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
1646                                         CString path = cpath->sCopyFromPath;\r
1647                                         path.MakeLower();\r
1648                                         if ((path.Find(find)>=0)&&(IsEntryInDateRange(i)))\r
1649                                         {\r
1650                                                 pShownlist->Add(m_logEntries[i]);\r
1651                                                 bGoing = false;\r
1652                                                 continue;\r
1653                                         }\r
1654                                         path = cpath->sPath;\r
1655                                         path.MakeLower();\r
1656                                         if ((path.Find(find)>=0)&&(IsEntryInDateRange(i)))\r
1657                                         {\r
1658                                                 pShownlist->Add(m_logEntries[i]);\r
1659                                                 bGoing = false;\r
1660                                                 continue;\r
1661                                         }\r
1662                                         path = cpath->GetAction();\r
1663                                         path.MakeLower();\r
1664                                         if ((path.Find(find)>=0)&&(IsEntryInDateRange(i)))\r
1665                                         {\r
1666                                                 pShownlist->Add(m_logEntries[i]);\r
1667                                                 bGoing = false;\r
1668                                                 continue;\r
1669                                         }\r
1670                                 }\r
1671                         }\r
1672 #endif\r
1673                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_AUTHORS))\r
1674                         {\r
1675                                 CString msg = m_logEntries[i].m_AuthorName;\r
1676                                 msg = msg.MakeLower();\r
1677                                 if ((msg.Find(find) >= 0)&&(IsEntryInDateRange(i)))\r
1678                                 {\r
1679                                         pShownlist->Add(&m_logEntries[i]);\r
1680                                         continue;\r
1681                                 }\r
1682                         }\r
1683                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_REVS))\r
1684                         {\r
1685                                 sRev.Format(_T("%ld"), m_logEntries[i].m_CommitHash);\r
1686                                 if ((sRev.Find(find) >= 0)&&(IsEntryInDateRange(i)))\r
1687                                 {\r
1688                                         pShownlist->Add(&m_logEntries[i]);\r
1689                                         continue;\r
1690                                 }\r
1691                         }\r
1692                 } // else (from if (bRegex))    \r
1693         } // for (DWORD i=0; i<m_logEntries.size(); ++i) \r
1694 \r
1695 }\r
1696 \r
1697 BOOL CGitLogListBase::IsEntryInDateRange(int i)\r
1698 {\r
1699         __time64_t time = m_logEntries[i].m_AuthorDate.GetTime();\r
1700         if ((time >= m_From.GetTime())&&(time <= m_To.GetTime()))\r
1701                 return TRUE;\r
1702 \r
1703         return FALSE;\r
1704 \r
1705 //      return TRUE;\r
1706 }\r
1707 void CGitLogListBase::StartFilter()\r
1708 {\r
1709         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
1710         RecalculateShownList(&m_arShownList);\r
1711         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
1712 \r
1713 \r
1714         DeleteAllItems();\r
1715         SetItemCountEx(ShownCountWithStopped());\r
1716         RedrawItems(0, ShownCountWithStopped());\r
1717         SetRedraw(false);\r
1718         //ResizeAllListCtrlCols();\r
1719         SetRedraw(true);\r
1720         Invalidate();\r
1721 }\r
1722 void CGitLogListBase::RemoveFilter()\r
1723 {\r
1724 \r
1725         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
1726 \r
1727         m_arShownList.RemoveAll();\r
1728 \r
1729         // reset the time filter too\r
1730 #if 0\r
1731         m_timFrom = (__time64_t(m_tFrom));\r
1732         m_timTo = (__time64_t(m_tTo));\r
1733         m_DateFrom.SetTime(&m_timFrom);\r
1734         m_DateTo.SetTime(&m_timTo);\r
1735         m_DateFrom.SetRange(&m_timFrom, &m_timTo);\r
1736         m_DateTo.SetRange(&m_timFrom, &m_timTo);\r
1737 #endif\r
1738 \r
1739         for (DWORD i=0; i<m_logEntries.size(); ++i)\r
1740         {\r
1741                 m_arShownList.Add(&m_logEntries[i]);\r
1742         }\r
1743 //      InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
1744         DeleteAllItems();\r
1745         SetItemCountEx(ShownCountWithStopped());\r
1746         RedrawItems(0, ShownCountWithStopped());\r
1747         SetRedraw(false);\r
1748         ResizeAllListCtrlCols();\r
1749         SetRedraw(true);\r
1750 \r
1751         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
1752 }