OSDN Git Service

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