OSDN Git Service

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