OSDN Git Service

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