OSDN Git Service

build success
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / GitLogList.cpp
1 // GitLogList.cpp : implementation file\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "TortoiseProc.h"\r
6 #include "GitLogList.h"\r
7 #include "GitRev.h"\r
8 //#include "VssStyle.h"\r
9 #include "IconMenu.h"\r
10 // CGitLogList\r
11 #include "cursor.h"\r
12 #include "InputDlg.h"\r
13 #include "PropDlg.h"\r
14 #include "SVNProgressDlg.h"\r
15 #include "ProgressDlg.h"\r
16 //#include "RepositoryBrowser.h"\r
17 //#include "CopyDlg.h"\r
18 //#include "StatGraphDlg.h"\r
19 #include "Logdlg.h"\r
20 #include "MessageBox.h"\r
21 #include "Registry.h"\r
22 #include "AppUtils.h"\r
23 #include "PathUtils.h"\r
24 #include "StringUtils.h"\r
25 #include "UnicodeUtils.h"\r
26 #include "TempFile.h"\r
27 //#include "GitInfo.h"\r
28 //#include "GitDiff.h"\r
29 #include "IconMenu.h"\r
30 //#include "RevisionRangeDlg.h"\r
31 //#include "BrowseFolder.h"\r
32 //#include "BlameDlg.h"\r
33 //#include "Blame.h"\r
34 //#include "GitHelpers.h"\r
35 #include "GitStatus.h"\r
36 //#include "LogDlgHelper.h"\r
37 //#include "CachedLogInfo.h"\r
38 //#include "RepositoryInfo.h"\r
39 //#include "EditPropertiesDlg.h"\r
40 #include "FileDiffDlg.h"\r
41 \r
42 \r
43 \r
44 \r
45 IMPLEMENT_DYNAMIC(CGitLogList, CHintListCtrl)\r
46 \r
47 CGitLogList::CGitLogList():CHintListCtrl()\r
48         ,m_regMaxBugIDColWidth(_T("Software\\TortoiseGit\\MaxBugIDColWidth"), 200)\r
49         ,m_nSearchIndex(0)\r
50 {\r
51         // use the default GUI font, create a copy of it and\r
52         // change the copy to BOLD (leave the rest of the font\r
53         // the same)\r
54         HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);\r
55         LOGFONT lf = {0};\r
56         GetObject(hFont, sizeof(LOGFONT), &lf);\r
57         lf.lfWeight = FW_BOLD;\r
58         m_boldFont = CreateFontIndirect(&lf);\r
59 \r
60 }\r
61 \r
62 CGitLogList::~CGitLogList()\r
63 {\r
64         DestroyIcon(m_hModifiedIcon);\r
65         DestroyIcon(m_hReplacedIcon);\r
66         DestroyIcon(m_hAddedIcon);\r
67         DestroyIcon(m_hDeletedIcon);\r
68         m_logEntries.ClearAll();\r
69 \r
70         if (m_boldFont)\r
71                 DeleteObject(m_boldFont);\r
72 \r
73 }\r
74 \r
75 \r
76 BEGIN_MESSAGE_MAP(CGitLogList, CHintListCtrl)\r
77         ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdrawLoglist)\r
78         ON_NOTIFY(LVN_GETDISPINFO, 0, OnLvnGetdispinfoLoglist)\r
79         ON_WM_CONTEXTMENU()\r
80         ON_NOTIFY(NM_DBLCLK, 0, OnNMDblclkLoglist)\r
81         ON_NOTIFY(LVN_ODFINDITEM, IDC_LOGLIST, OnLvnOdfinditemLoglist)\r
82 END_MESSAGE_MAP()\r
83 \r
84 int CGitLogList:: OnCreate(LPCREATESTRUCT lpCreateStruct)\r
85 {\r
86         SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_SUBITEMIMAGES);\r
87         // load the icons for the action columns\r
88         m_hModifiedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONMODIFIED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
89         m_hReplacedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONREPLACED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
90         m_hAddedIcon    =  (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONADDED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
91         m_hDeletedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONDELETED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
92 \r
93         return CHintListCtrl::OnCreate(lpCreateStruct);\r
94 }\r
95 \r
96 void CGitLogList::InsertGitColumn()\r
97 {\r
98         CString temp;\r
99 \r
100         int c = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
101         \r
102         while (c>=0)\r
103                 DeleteColumn(c--);\r
104         temp.LoadString(IDS_LOG_GRAPH);\r
105 \r
106         InsertColumn(this->LOGLIST_GRAPH, temp);\r
107         \r
108 #if 0   \r
109         // make the revision column right aligned\r
110         LVCOLUMN Column;\r
111         Column.mask = LVCF_FMT;\r
112         Column.fmt = LVCFMT_RIGHT;\r
113         SetColumn(0, &Column); \r
114 #endif  \r
115 //      CString log;\r
116 //      g_Git.GetLog(log);\r
117 \r
118         temp.LoadString(IDS_LOG_ACTIONS);\r
119         InsertColumn(this->LOGLIST_ACTION, temp);\r
120         \r
121         temp.LoadString(IDS_LOG_MESSAGE);\r
122         InsertColumn(this->LOGLIST_MESSAGE, temp);\r
123         \r
124         temp.LoadString(IDS_LOG_AUTHOR);\r
125         InsertColumn(this->LOGLIST_AUTHOR, temp);\r
126         \r
127         temp.LoadString(IDS_LOG_DATE);\r
128         InsertColumn(this->LOGLIST_DATE, temp);\r
129         \r
130 \r
131         if (m_bShowBugtraqColumn)\r
132         {\r
133 //              temp = m_ProjectProperties.sLabel;\r
134                 if (temp.IsEmpty())\r
135                         temp.LoadString(IDS_LOG_BUGIDS);\r
136                 InsertColumn(this->LOGLIST_BUG, temp);\r
137 \r
138         }\r
139         \r
140         SetRedraw(false);\r
141         ResizeAllListCtrlCols();\r
142         SetRedraw(true);\r
143 \r
144 }\r
145 \r
146 void CGitLogList::ResizeAllListCtrlCols()\r
147 {\r
148 \r
149         const int nMinimumWidth = ICONITEMBORDER+16*4;\r
150         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
151         int nItemCount = GetItemCount();\r
152         TCHAR textbuf[MAX_PATH];\r
153         CHeaderCtrl * pHdrCtrl = (CHeaderCtrl*)(GetDlgItem(0));\r
154         if (pHdrCtrl)\r
155         {\r
156                 for (int col = 0; col <= maxcol; col++)\r
157                 {\r
158                         HDITEM hdi = {0};\r
159                         hdi.mask = HDI_TEXT;\r
160                         hdi.pszText = textbuf;\r
161                         hdi.cchTextMax = sizeof(textbuf);\r
162                         pHdrCtrl->GetItem(col, &hdi);\r
163                         int cx = GetStringWidth(hdi.pszText)+20; // 20 pixels for col separator and margin\r
164                         for (int index = 0; index<nItemCount; ++index)\r
165                         {\r
166                                 // get the width of the string and add 14 pixels for the column separator and margins\r
167                                 int linewidth = GetStringWidth(GetItemText(index, col)) + 14;\r
168                                 if (index < m_arShownList.GetCount())\r
169                                 {\r
170                                         GitRev * pCurLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(index));\r
171                                         if ((pCurLogEntry)&&(pCurLogEntry->m_CommitHash == m_wcRev.m_CommitHash))\r
172                                         {\r
173                                                 // set the bold font and ask for the string width again\r
174                                                 SendMessage(WM_SETFONT, (WPARAM)m_boldFont, NULL);\r
175                                                 linewidth = GetStringWidth(GetItemText(index, col)) + 14;\r
176                                                 // restore the system font\r
177                                                 SendMessage(WM_SETFONT, NULL, NULL);\r
178                                         }\r
179                                 }\r
180                                 if (index == 0)\r
181                                 {\r
182                                         // add the image size\r
183                                         CImageList * pImgList = GetImageList(LVSIL_SMALL);\r
184                                         if ((pImgList)&&(pImgList->GetImageCount()))\r
185                                         {\r
186                                                 IMAGEINFO imginfo;\r
187                                                 pImgList->GetImageInfo(0, &imginfo);\r
188                                                 linewidth += (imginfo.rcImage.right - imginfo.rcImage.left);\r
189                                                 linewidth += 3; // 3 pixels between icon and text\r
190                                         }\r
191                                 }\r
192                                 if (cx < linewidth)\r
193                                         cx = linewidth;\r
194                         }\r
195                         // Adjust columns "Actions" containing icons\r
196                         if (col == this->LOGLIST_ACTION)\r
197                         {\r
198                                 if (cx < nMinimumWidth)\r
199                                 {\r
200                                         cx = nMinimumWidth;\r
201                                 }\r
202                         }\r
203                         \r
204                         if (col == this->LOGLIST_MESSAGE)\r
205                         {\r
206                                 if (cx > LOGLIST_MESSAGE_MAX)\r
207                                 {\r
208                                         cx = LOGLIST_MESSAGE_MAX;\r
209                                 }\r
210 \r
211                         }\r
212                         // keep the bug id column small\r
213                         if ((col == 4)&&(m_bShowBugtraqColumn))\r
214                         {\r
215                                 if (cx > (int)(DWORD)m_regMaxBugIDColWidth)\r
216                                 {\r
217                                         cx = (int)(DWORD)m_regMaxBugIDColWidth;\r
218                                 }\r
219                         }\r
220 \r
221                         SetColumnWidth(col, cx);\r
222                 }\r
223         }\r
224 \r
225 }\r
226 \r
227 \r
228 void CGitLogList::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
229 {\r
230 \r
231         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
232         // Take the default processing unless we set this to something else below.\r
233         *pResult = CDRF_DODEFAULT;\r
234 \r
235         if (m_bNoDispUpdates)\r
236                 return;\r
237 \r
238         switch (pLVCD->nmcd.dwDrawStage)\r
239         {\r
240         case CDDS_PREPAINT:\r
241                 {\r
242                         *pResult = CDRF_NOTIFYITEMDRAW;\r
243                         return;\r
244                 }\r
245                 break;\r
246         case CDDS_ITEMPREPAINT:\r
247                 {\r
248                         // This is the prepaint stage for an item. Here's where we set the\r
249                         // item's text color. \r
250                         \r
251                         // Tell Windows to send draw notifications for each subitem.\r
252                         *pResult = CDRF_NOTIFYSUBITEMDRAW;\r
253 \r
254                         COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
255 \r
256                         if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
257                         {\r
258                                 GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec);\r
259                                 if (data)\r
260                                 {\r
261 #if 0\r
262                                         if (data->bCopiedSelf)\r
263                                         {\r
264                                                 // only change the background color if the item is not 'hot' (on vista with m_Themes enabled)\r
265                                                 if (!m_Theme.IsAppm_Themed() || !m_bVista || ((pLVCD->nmcd.uItemState & CDIS_HOT)==0))\r
266                                                         pLVCD->clrTextBk = GetSysColor(COLOR_MENU);\r
267                                         }\r
268 \r
269                                         if (data->bCopies)\r
270                                                 crText = m_Colors.GetColor(CColors::Modified);\r
271 #endif\r
272 //                                      if ((data->childStackDepth)||(m_mergedRevs.find(data->Rev) != m_mergedRevs.end()))\r
273 //                                              crText = GetSysColor(COLOR_GRAYTEXT);\r
274 //                                      if (data->Rev == m_wcRev)\r
275 //                                      {\r
276 //                                              SelectObject(pLVCD->nmcd.hdc, m_boldFont);\r
277                                                 // We changed the font, so we're returning CDRF_NEWFONT. This\r
278                                                 // tells the control to recalculate the extent of the text.\r
279 //                                              *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;\r
280 //                                      }\r
281                                 }\r
282                         }\r
283                         if (m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
284                         {\r
285                                 if (m_bStrictStopped)\r
286                                         crText = GetSysColor(COLOR_GRAYTEXT);\r
287                         }\r
288                         // Store the color back in the NMLVCUSTOMDRAW struct.\r
289                         pLVCD->clrText = crText;\r
290                         return;\r
291                 }\r
292                 break;\r
293         case CDDS_ITEMPREPAINT|CDDS_ITEM|CDDS_SUBITEM:\r
294                 {\r
295                         if ((m_bStrictStopped)&&(m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec))\r
296                         {\r
297                                 pLVCD->nmcd.uItemState &= ~(CDIS_SELECTED|CDIS_FOCUS);\r
298                         }\r
299                         if (pLVCD->iSubItem == 1)\r
300                         {\r
301                                 *pResult = CDRF_DODEFAULT;\r
302 \r
303                                 if (m_arShownList.GetCount() <= (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
304                                         return;\r
305 \r
306                                 int             nIcons = 0;\r
307                                 int             iconwidth = ::GetSystemMetrics(SM_CXSMICON);\r
308                                 int             iconheight = ::GetSystemMetrics(SM_CYSMICON);\r
309 \r
310                                 GitRev* pLogEntry = reinterpret_cast<GitRev *>(m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec));\r
311 \r
312                                 // Get the selected state of the\r
313                                 // item being drawn.\r
314                                 LVITEM   rItem;\r
315                                 SecureZeroMemory(&rItem, sizeof(LVITEM));\r
316                                 rItem.mask  = LVIF_STATE;\r
317                                 rItem.iItem = pLVCD->nmcd.dwItemSpec;\r
318                                 rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
319                                 GetItem(&rItem);\r
320 \r
321                                 CRect rect;\r
322                                 GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
323 \r
324                                 // Fill the background\r
325                                 if (m_Theme.IsAppThemed() && m_bVista)\r
326                                 {\r
327                                         m_Theme.Open(m_hWnd, L"Explorer");\r
328                                         int state = LISS_NORMAL;\r
329                                         if (rItem.state & LVIS_SELECTED)\r
330                                         {\r
331                                                 if (::GetFocus() == m_hWnd)\r
332                                                         state |= LISS_SELECTED;\r
333                                                 else\r
334                                                         state |= LISS_SELECTEDNOTFOCUS;\r
335                                         }\r
336                                         else\r
337                                         {\r
338 #if 0\r
339                                                 if (pLogEntry->bCopiedSelf)\r
340                                                 {\r
341                                                         // unfortunately, the pLVCD->nmcd.uItemState does not contain valid\r
342                                                         // information at this drawing stage. But we can check the whether the\r
343                                                         // previous stage changed the background color of the item\r
344                                                         if (pLVCD->clrTextBk == GetSysColor(COLOR_MENU))\r
345                                                         {\r
346                                                                 HBRUSH brush;\r
347                                                                 brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
348                                                                 if (brush)\r
349                                                                 {\r
350                                                                         ::FillRect(pLVCD->nmcd.hdc, &rect, brush);\r
351                                                                         ::DeleteObject(brush);\r
352                                                                 }\r
353                                                         }\r
354                                                 }\r
355 #endif\r
356                                         }\r
357 \r
358                                         if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTDETAIL, state))\r
359                                                 m_Theme.DrawParentBackground(m_hWnd, pLVCD->nmcd.hdc, &rect);\r
360 \r
361                                         m_Theme.DrawBackground(pLVCD->nmcd.hdc, LVP_LISTDETAIL, state, &rect, NULL);\r
362                                 }\r
363                                 else\r
364                                 {\r
365                                         HBRUSH brush;\r
366                                         if (rItem.state & LVIS_SELECTED)\r
367                                         {\r
368                                                 if (::GetFocus() == m_hWnd)\r
369                                                         brush = ::CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT));\r
370                                                 else\r
371                                                         brush = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));\r
372                                         }\r
373                                         else\r
374                                         {\r
375                                                 //if (pLogEntry->bCopiedSelf)\r
376                                                 //      brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
377                                                 //else\r
378                                                         brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));\r
379                                         }\r
380                                         if (brush == NULL)\r
381                                                 return;\r
382 \r
383                                         ::FillRect(pLVCD->nmcd.hdc, &rect, brush);\r
384                                         ::DeleteObject(brush);\r
385                                 }\r
386 \r
387                                 // Draw the icon(s) into the compatible DC\r
388                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_MODIFIED)\r
389                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left + ICONITEMBORDER, rect.top, m_hModifiedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
390                                 nIcons++;\r
391 \r
392                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_ADDED)\r
393                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hAddedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
394                                 nIcons++;\r
395 \r
396                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_DELETED)\r
397                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hDeletedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
398                                 nIcons++;\r
399 \r
400                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
401                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hReplacedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
402                                 nIcons++;\r
403                                 *pResult = CDRF_SKIPDEFAULT;\r
404                                 return;\r
405                         }\r
406                 }\r
407                 break;\r
408         }\r
409         *pResult = CDRF_DODEFAULT;\r
410 \r
411 }\r
412 \r
413 // CGitLogList message handlers\r
414 \r
415 void CGitLogList::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
416 {\r
417         NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);\r
418 \r
419         // Create a pointer to the item\r
420         LV_ITEM* pItem = &(pDispInfo)->item;\r
421 \r
422         // Do the list need text information?\r
423         if (!(pItem->mask & LVIF_TEXT))\r
424                 return;\r
425 \r
426         // By default, clear text buffer.\r
427         lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
428 \r
429         bool bOutOfRange = pItem->iItem >= ShownCountWithStopped();\r
430         \r
431         *pResult = 0;\r
432         if (m_bNoDispUpdates || m_bThreadRunning || bOutOfRange)\r
433                 return;\r
434 \r
435         // Which item number?\r
436         int itemid = pItem->iItem;\r
437         GitRev * pLogEntry = NULL;\r
438         if (itemid < m_arShownList.GetCount())\r
439                 pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(pItem->iItem));\r
440     \r
441         // Which column?\r
442         switch (pItem->iSubItem)\r
443         {\r
444         case this->LOGLIST_GRAPH:       //Graphic\r
445                 if (pLogEntry)\r
446                 {\r
447                 }\r
448                 break;\r
449         case this->LOGLIST_ACTION: //action -- no text in the column\r
450                 break;\r
451         case this->LOGLIST_MESSAGE: //Message\r
452                 if (pLogEntry)\r
453                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_Subject, pItem->cchTextMax);\r
454                 break;\r
455         case this->LOGLIST_AUTHOR: //Author\r
456                 if (pLogEntry)\r
457                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorName, pItem->cchTextMax);\r
458                 break;\r
459         case this->LOGLIST_DATE: //Date\r
460                 if (pLogEntry)\r
461                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorDate.Format(_T("%Y-%m-%d %H:%M")), pItem->cchTextMax);\r
462                 break;\r
463                 \r
464         case 5:\r
465 \r
466                 break;\r
467         default:\r
468                 ASSERT(false);\r
469         }\r
470 }\r
471 \r
472 void CGitLogList::OnContextMenu(CWnd* pWnd, CPoint point)\r
473 {\r
474 \r
475         int selIndex = GetSelectionMark();\r
476         if (selIndex < 0)\r
477                 return; // nothing selected, nothing to do with a context menu\r
478 \r
479         // if the user selected the info text telling about not all revisions shown due to\r
480         // the "stop on copy/rename" option, we also don't show the context menu\r
481         if ((m_bStrictStopped)&&(selIndex == m_arShownList.GetCount()))\r
482                 return;\r
483 \r
484         // if the context menu is invoked through the keyboard, we have to use\r
485         // a calculated position on where to anchor the menu on\r
486         if ((point.x == -1) && (point.y == -1))\r
487         {\r
488                 CRect rect;\r
489                 GetItemRect(selIndex, &rect, LVIR_LABEL);\r
490                 ClientToScreen(&rect);\r
491                 point = rect.CenterPoint();\r
492         }\r
493         m_nSearchIndex = selIndex;\r
494         m_bCancelled = FALSE;\r
495 \r
496         // calculate some information the context menu commands can use\r
497 //      CString pathURL = GetURLFromPath(m_path);\r
498 \r
499         POSITION pos = GetFirstSelectedItemPosition();\r
500         int indexNext = GetNextSelectedItem(pos);\r
501         if (indexNext < 0)\r
502                 return;\r
503 \r
504         GitRev* pSelLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(indexNext));\r
505 #if 0\r
506         GitRev revSelected = pSelLogEntry->Rev;\r
507         GitRev revPrevious = git_revnum_t(revSelected)-1;\r
508         if ((pSelLogEntry->pArChangedPaths)&&(pSelLogEntry->pArChangedPaths->GetCount() <= 2))\r
509         {\r
510                 for (int i=0; i<pSelLogEntry->pArChangedPaths->GetCount(); ++i)\r
511                 {\r
512                         LogChangedPath * changedpath = (LogChangedPath *)pSelLogEntry->pArChangedPaths->GetAt(i);\r
513                         if (changedpath->lCopyFromRev)\r
514                                 revPrevious = changedpath->lCopyFromRev;\r
515                 }\r
516         }\r
517         GitRev revSelected2;\r
518         if (pos)\r
519         {\r
520                 PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
521                 revSelected2 = pLogEntry->Rev;\r
522         }\r
523         bool bAllFromTheSameAuthor = true;\r
524         CString firstAuthor;\r
525         CLogDataVector selEntries;\r
526         GitRev revLowest, revHighest;\r
527         GitRevRangeArray revisionRanges;\r
528         {\r
529                 POSITION pos = GetFirstSelectedItemPosition();\r
530                 PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
531                 revisionRanges.AddRevision(pLogEntry->Rev);\r
532                 selEntries.push_back(pLogEntry);\r
533                 firstAuthor = pLogEntry->sAuthor;\r
534                 revLowest = pLogEntry->Rev;\r
535                 revHighest = pLogEntry->Rev;\r
536                 while (pos)\r
537                 {\r
538                         pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
539                         revisionRanges.AddRevision(pLogEntry->Rev);\r
540                         selEntries.push_back(pLogEntry);\r
541                         if (firstAuthor.Compare(pLogEntry->sAuthor))\r
542                                 bAllFromTheSameAuthor = false;\r
543                         revLowest = (git_revnum_t(pLogEntry->Rev) > git_revnum_t(revLowest) ? revLowest : pLogEntry->Rev);\r
544                         revHighest = (git_revnum_t(pLogEntry->Rev) < git_revnum_t(revHighest) ? revHighest : pLogEntry->Rev);\r
545                 }\r
546         }\r
547 \r
548 #endif\r
549 \r
550         int FirstSelect=-1, LastSelect=-1;\r
551         pos = GetFirstSelectedItemPosition();\r
552         FirstSelect = GetNextSelectedItem(pos);\r
553         while(pos)\r
554         {\r
555                 LastSelect = GetNextSelectedItem(pos);\r
556         }\r
557         //entry is selected, now show the popup menu\r
558         CIconMenu popup;\r
559         if (popup.CreatePopupMenu())\r
560         {\r
561                 if (GetSelectedCount() == 1)\r
562                 {\r
563 #if 0\r
564                         if (!m_path.IsDirectory())\r
565                         {\r
566                                 if (m_hasWC)\r
567                                 {\r
568                                         popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
569                                         popup.AppendMenuIcon(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME);\r
570                                 }\r
571                                 popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
572                                 popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
573                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
574                                 popup.AppendMenuIcon(ID_SAVEAS, IDS_LOG_POPUP_SAVE, IDI_SAVEAS);\r
575                                 popup.AppendMenuIcon(ID_OPEN, IDS_LOG_POPUP_OPEN, IDI_OPEN);\r
576                                 popup.AppendMenuIcon(ID_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
577                                 popup.AppendMenuIcon(ID_BLAME, IDS_LOG_POPUP_BLAME, IDI_BLAME);\r
578                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
579                         }\r
580                         else\r
581 #endif \r
582                         {\r
583                                 if (m_hasWC)\r
584                                 {\r
585                                         popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
586                                         // TODO:\r
587                                         // TortoiseMerge could be improved to take a /blame switch\r
588                                         // and then not 'cat' the files from a unified diff but\r
589                                         // blame then.\r
590                                         // But until that's implemented, the context menu entry for\r
591                                         // this feature is commented out.\r
592                                         //popup.AppendMenu(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME);\r
593                                 }\r
594                                 popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
595                                 popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
596                                 popup.AppendMenuIcon(ID_BLAMEWITHPREVIOUS, IDS_LOG_POPUP_BLAMEWITHPREVIOUS, IDI_BLAME);\r
597                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
598                         }\r
599 \r
600 //                      if (!m_ProjectProperties.sWebViewerRev.IsEmpty())\r
601 //                      {\r
602 //                              popup.AppendMenuIcon(ID_VIEWREV, IDS_LOG_POPUP_VIEWREV);\r
603 //                      }\r
604 //                      if (!m_ProjectProperties.sWebViewerPathRev.IsEmpty())\r
605 //                      {\r
606 //                              popup.AppendMenuIcon(ID_VIEWPATHREV, IDS_LOG_POPUP_VIEWPATHREV);\r
607 //                      }\r
608 //                      if ((!m_ProjectProperties.sWebViewerPathRev.IsEmpty())||\r
609 //                              (!m_ProjectProperties.sWebViewerRev.IsEmpty()))\r
610 //                      {\r
611 //                              popup.AppendMenu(MF_SEPARATOR, NULL);\r
612 //                      }\r
613 \r
614 //                      popup.AppendMenuIcon(ID_REPOBROWSE, IDS_LOG_BROWSEREPO, IDI_REPOBROWSE);\r
615 //                      popup.AppendMenuIcon(ID_COPY, IDS_LOG_POPUP_COPY);\r
616 //                      if (m_hasWC)\r
617 //                              popup.AppendMenuIcon(ID_UPDATE, IDS_LOG_POPUP_UPDATE, IDI_UPDATE);\r
618                         if (m_hasWC)\r
619                                 popup.AppendMenuIcon(ID_REVERTTOREV, IDS_LOG_POPUP_REVERTTOREV, IDI_REVERT);\r
620                         if (m_hasWC)\r
621                                 popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREV, IDI_REVERT);\r
622 //                      if (m_hasWC)\r
623 //                              popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREV, IDI_MERGE);\r
624                         popup.AppendMenuIcon(ID_CHECKOUT, IDS_MENUCHECKOUT, IDI_CHECKOUT);\r
625                         popup.AppendMenuIcon(ID_EXPORT, IDS_MENUEXPORT, IDI_EXPORT);\r
626                         popup.AppendMenu(MF_SEPARATOR, NULL);\r
627                 }\r
628                 else if (GetSelectedCount() >= 2)\r
629                 {\r
630                         bool bAddSeparator = false;\r
631                         if (IsSelectionContinuous() || (GetSelectedCount() == 2))\r
632                         {\r
633                                 popup.AppendMenuIcon(ID_COMPARETWO, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);\r
634                         }\r
635                         if (GetSelectedCount() == 2)\r
636                         {\r
637                                 popup.AppendMenuIcon(ID_BLAMETWO, IDS_LOG_POPUP_BLAMEREVS, IDI_BLAME);\r
638                                 popup.AppendMenuIcon(ID_GNUDIFF2, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
639                                 bAddSeparator = true;\r
640                         }\r
641                         if (m_hasWC)\r
642                         {\r
643                                 popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREVS, IDI_REVERT);\r
644 //                              if (m_hasWC)\r
645 //                                      popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREVS, IDI_MERGE);\r
646                                 bAddSeparator = true;\r
647                         }\r
648                         if (bAddSeparator)\r
649                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
650                 }\r
651 #if 0\r
652 //              if ((selEntries.size() > 0)&&(bAllFromTheSameAuthor))\r
653 //              {\r
654 //                      popup.AppendMenuIcon(ID_EDITAUTHOR, IDS_LOG_POPUP_EDITAUTHOR);\r
655 //              }\r
656 //              if (GetSelectedCount() == 1)\r
657 //              {\r
658 //                      popup.AppendMenuIcon(ID_EDITLOG, IDS_LOG_POPUP_EDITLOG);\r
659 //                      popup.AppendMenuIcon(ID_REVPROPS, IDS_REPOBROWSE_SHOWREVPROP, IDI_PROPERTIES); // "Show Revision Properties"\r
660 //                      popup.AppendMenu(MF_SEPARATOR, NULL);\r
661 //              }\r
662 #endif\r
663                 if (GetSelectedCount() != 0)\r
664                 {\r
665                         popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD);\r
666                 }\r
667                 popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND);\r
668 \r
669                 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
670 //              DialogEnableWindow(IDOK, FALSE);\r
671 //              SetPromptApp(&theApp);\r
672                 theApp.DoWaitCursor(1);\r
673                 bool bOpenWith = false;\r
674 \r
675                 switch (cmd)\r
676                 {\r
677                         case ID_GNUDIFF1:\r
678                         {\r
679                                 CString tempfile=GetTempFile();\r
680                                 CString cmd;\r
681                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
682                                 cmd.Format(_T("git.cmd diff-tree -r -p --stat %s"),r1->m_CommitHash);\r
683                                 g_Git.RunLogFile(cmd,tempfile);\r
684                                 CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r1->m_Subject);\r
685                         }\r
686                         break;\r
687 \r
688                         case ID_GNUDIFF2:\r
689                         {\r
690                                 CString tempfile=GetTempFile();\r
691                                 CString cmd;\r
692                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
693                                 GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
694                                 cmd.Format(_T("git.cmd diff-tree -r -p --stat %s %s"),r1->m_CommitHash,r2->m_CommitHash);\r
695                                 g_Git.RunLogFile(cmd,tempfile);\r
696                                 CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r2->m_CommitHash.Left(6));\r
697 \r
698                         }\r
699                         break;\r
700 \r
701                 case ID_COMPARETWO:\r
702                         {\r
703                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
704                                 GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
705                                 CFileDiffDlg dlg;\r
706                                 dlg.SetDiff(NULL,*r1,*r2);\r
707                                 dlg.DoModal();\r
708                                 \r
709                         }\r
710                         break;\r
711 \r
712 #if 0\r
713                 case ID_GNUDIFF1:\r
714                         {\r
715                                 if (PromptShown())\r
716                                 {\r
717                                         GitDiff diff(this, this->m_hWnd, true);\r
718                                         diff.SetHEADPeg(m_LogRevision);\r
719                                         diff.ShowUnifiedDiff(m_path, revPrevious, m_path, revSelected);\r
720                                 }\r
721                                 else\r
722                                         CAppUtils::StartShowUnifiedDiff(m_hWnd, m_path, revPrevious, m_path, revSelected, GitRev(), m_LogRevision);\r
723                         }\r
724                         break;\r
725 \r
726                 case ID_GNUDIFF2:\r
727                         {\r
728                                 if (PromptShown())\r
729                                 {\r
730                                         GitDiff diff(this, this->m_hWnd, true);\r
731                                         diff.SetHEADPeg(m_LogRevision);\r
732                                         diff.ShowUnifiedDiff(m_path, revSelected2, m_path, revSelected);\r
733                                 }\r
734                                 else\r
735                                         CAppUtils::StartShowUnifiedDiff(m_hWnd, m_path, revSelected2, m_path, revSelected, GitRev(), m_LogRevision);\r
736                         }\r
737                         break;\r
738                 case ID_REVERTREV:\r
739                         {\r
740                                 // we need an URL to complete this command, so error out if we can't get an URL\r
741                                 if (pathURL.IsEmpty())\r
742                                 {\r
743                                         CString strMessage;\r
744                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
745                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
746                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
747                                         break;          //exit\r
748                                 }\r
749                                 CString msg;\r
750                                 msg.Format(IDS_LOG_REVERT_CONFIRM, m_path.GetWinPath());\r
751                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
752                                 {\r
753                                         CGitProgressDlg dlg;\r
754                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
755                                         dlg.SetPathList(CTGitPathList(m_path));\r
756                                         dlg.SetUrl(pathURL);\r
757                                         dlg.SetSecondUrl(pathURL);\r
758                                         revisionRanges.AdjustForMerge(true);\r
759                                         dlg.SetRevisionRanges(revisionRanges);\r
760                                         dlg.SetPegRevision(m_LogRevision);\r
761                                         dlg.DoModal();\r
762                                 }\r
763                         }\r
764                         break;\r
765                 case ID_MERGEREV:\r
766                         {\r
767                                 // we need an URL to complete this command, so error out if we can't get an URL\r
768                                 if (pathURL.IsEmpty())\r
769                                 {\r
770                                         CString strMessage;\r
771                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
772                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
773                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
774                                         break;          //exit\r
775                                 }\r
776 \r
777                                 CString path = m_path.GetWinPathString();\r
778                                 bool bGotSavePath = false;\r
779                                 if ((GetSelectedCount() == 1)&&(!m_path.IsDirectory()))\r
780                                 {\r
781                                         bGotSavePath = CAppUtils::FileOpenSave(path, NULL, IDS_LOG_MERGETO, IDS_COMMONFILEFILTER, true, GetSafeHwnd());\r
782                                 }\r
783                                 else\r
784                                 {\r
785                                         CBrowseFolder folderBrowser;\r
786                                         folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO)));\r
787                                         bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK);\r
788                                 }\r
789                                 if (bGotSavePath)\r
790                                 {\r
791                                         CGitProgressDlg dlg;\r
792                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
793                                         dlg.SetPathList(CTGitPathList(CTGitPath(path)));\r
794                                         dlg.SetUrl(pathURL);\r
795                                         dlg.SetSecondUrl(pathURL);\r
796                                         revisionRanges.AdjustForMerge(false);\r
797                                         dlg.SetRevisionRanges(revisionRanges);\r
798                                         dlg.SetPegRevision(m_LogRevision);\r
799                                         dlg.DoModal();\r
800                                 }\r
801                         }\r
802                         break;\r
803                 case ID_REVERTTOREV:\r
804                         {\r
805                                 // we need an URL to complete this command, so error out if we can't get an URL\r
806                                 if (pathURL.IsEmpty())\r
807                                 {\r
808                                         CString strMessage;\r
809                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
810                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
811                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
812                                         break;          //exit\r
813                                 }\r
814 \r
815                                 CString msg;\r
816                                 msg.Format(IDS_LOG_REVERTTOREV_CONFIRM, m_path.GetWinPath());\r
817                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
818                                 {\r
819                                         CGitProgressDlg dlg;\r
820                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
821                                         dlg.SetPathList(CTGitPathList(m_path));\r
822                                         dlg.SetUrl(pathURL);\r
823                                         dlg.SetSecondUrl(pathURL);\r
824                                         GitRevRangeArray revarray;\r
825                                         revarray.AddRevRange(GitRev::REV_HEAD, revSelected);\r
826                                         dlg.SetRevisionRanges(revarray);\r
827                                         dlg.SetPegRevision(m_LogRevision);\r
828                                         dlg.DoModal();\r
829                                 }\r
830                         }\r
831                         break;\r
832                 case ID_COPY:\r
833                         {\r
834                                 // we need an URL to complete this command, so error out if we can't get an URL\r
835                                 if (pathURL.IsEmpty())\r
836                                 {\r
837                                         CString strMessage;\r
838                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
839                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
840                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
841                                         break;          //exit\r
842                                 }\r
843 \r
844                                 CCopyDlg dlg;\r
845                                 dlg.m_URL = pathURL;\r
846                                 dlg.m_path = m_path;\r
847                                 dlg.m_CopyRev = revSelected;\r
848                                 if (dlg.DoModal() == IDOK)\r
849                                 {\r
850                                         // should we show a progress dialog here? Copies are done really fast\r
851                                         // and without much network traffic.\r
852                                         if (!Copy(CTGitPathList(CTGitPath(pathURL)), CTGitPath(dlg.m_URL), dlg.m_CopyRev, dlg.m_CopyRev, dlg.m_sLogMessage))\r
853                                                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
854                                         else\r
855                                                 CMessageBox::Show(this->m_hWnd, IDS_LOG_COPY_SUCCESS, IDS_APPNAME, MB_ICONINFORMATION);\r
856                                 }\r
857                         } \r
858                         break;\r
859                 case ID_COMPARE:\r
860                         {\r
861                                 //user clicked on the menu item "compare with working copy"\r
862                                 if (PromptShown())\r
863                                 {\r
864                                         GitDiff diff(this, m_hWnd, true);\r
865                                         diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
866                                         diff.SetHEADPeg(m_LogRevision);\r
867                                         diff.ShowCompare(m_path, GitRev::REV_WC, m_path, revSelected);\r
868                                 }\r
869                                 else\r
870                                         CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
871                         }\r
872                         break;\r
873                 case ID_COMPARETWO:\r
874                         {\r
875                                 GitRev r1 = revSelected;\r
876                                 GitRev r2 = revSelected2;\r
877                                 if (GetSelectedCount() > 2)\r
878                                 {\r
879                                         r1 = revHighest;\r
880                                         r2 = revLowest;\r
881                                 }\r
882                                 //user clicked on the menu item "compare revisions"\r
883                                 if (PromptShown())\r
884                                 {\r
885                                         GitDiff diff(this, m_hWnd, true);\r
886                                         diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
887                                         diff.SetHEADPeg(m_LogRevision);\r
888                                         diff.ShowCompare(CTGitPath(pathURL), r2, CTGitPath(pathURL), r1);\r
889                                 }\r
890                                 else\r
891                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), r2, CTGitPath(pathURL), r1, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
892                         }\r
893                         break;\r
894                 case ID_COMPAREWITHPREVIOUS:\r
895                         {\r
896                                 if (PromptShown())\r
897                                 {\r
898                                         GitDiff diff(this, m_hWnd, true);\r
899                                         diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
900                                         diff.SetHEADPeg(m_LogRevision);\r
901                                         diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected);\r
902                                 }\r
903                                 else\r
904                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
905                         }\r
906                         break;\r
907                 case ID_BLAMECOMPARE:\r
908                         {\r
909                                 //user clicked on the menu item "compare with working copy"\r
910                                 //now first get the revision which is selected\r
911                                 if (PromptShown())\r
912                                 {\r
913                                         GitDiff diff(this, this->m_hWnd, true);\r
914                                         diff.SetHEADPeg(m_LogRevision);\r
915                                         diff.ShowCompare(m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), false, true);\r
916                                 }\r
917                                 else\r
918                                         CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true);\r
919                         }\r
920                         break;\r
921                 case ID_BLAMETWO:\r
922                         {\r
923                                 //user clicked on the menu item "compare and blame revisions"\r
924                                 if (PromptShown())\r
925                                 {\r
926                                         GitDiff diff(this, this->m_hWnd, true);\r
927                                         diff.SetHEADPeg(m_LogRevision);\r
928                                         diff.ShowCompare(CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
929                                 }\r
930                                 else\r
931                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
932                         }\r
933                         break;\r
934                 case ID_BLAMEWITHPREVIOUS:\r
935                         {\r
936                                 //user clicked on the menu item "Compare and Blame with previous revision"\r
937                                 if (PromptShown())\r
938                                 {\r
939                                         GitDiff diff(this, this->m_hWnd, true);\r
940                                         diff.SetHEADPeg(m_LogRevision);\r
941                                         diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
942                                 }\r
943                                 else\r
944                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
945                         }\r
946                         break;\r
947                 case ID_SAVEAS:\r
948                         {\r
949                                 //now first get the revision which is selected\r
950                                 CString revFilename;\r
951                                 if (m_hasWC)\r
952                                 {\r
953                                         CString strWinPath = m_path.GetWinPathString();\r
954                                         int rfind = strWinPath.ReverseFind('.');\r
955                                         if (rfind > 0)\r
956                                                 revFilename.Format(_T("%s-%ld%s"), (LPCTSTR)strWinPath.Left(rfind), (LONG)revSelected, (LPCTSTR)strWinPath.Mid(rfind));\r
957                                         else\r
958                                                 revFilename.Format(_T("%s-%ld"), (LPCTSTR)strWinPath, revSelected);\r
959                                 }\r
960                                 if (CAppUtils::FileOpenSave(revFilename, NULL, IDS_LOG_POPUP_SAVE, IDS_COMMONFILEFILTER, false, m_hWnd))\r
961                                 {\r
962                                         CTGitPath tempfile;\r
963                                         tempfile.SetFromWin(revFilename);\r
964                                         CProgressDlg progDlg;\r
965                                         progDlg.SetTitle(IDS_APPNAME);\r
966                                         progDlg.SetAnimation(IDR_DOWNLOAD);\r
967                                         CString sInfoLine;\r
968                                         sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
969                                         progDlg.SetLine(1, sInfoLine, true);\r
970                                         SetAndClearProgressInfo(&progDlg);\r
971                                         progDlg.ShowModeless(m_hWnd);\r
972                                         if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
973                                         {\r
974                                                 // try again with another peg revision\r
975                                                 if (!Cat(m_path, revSelected, revSelected, tempfile))\r
976                                                 {\r
977                                                         progDlg.Stop();\r
978                                                         SetAndClearProgressInfo((HWND)NULL);\r
979                                                         CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
980                                                         EnableOKButton();\r
981                                                         break;\r
982                                                 }\r
983                                         }\r
984                                         progDlg.Stop();\r
985                                         SetAndClearProgressInfo((HWND)NULL);\r
986                                 }\r
987                         }\r
988                         break;\r
989                 case ID_OPENWITH:\r
990                         bOpenWith = true;\r
991                 case ID_OPEN:\r
992                         {\r
993                                 CProgressDlg progDlg;\r
994                                 progDlg.SetTitle(IDS_APPNAME);\r
995                                 progDlg.SetAnimation(IDR_DOWNLOAD);\r
996                                 CString sInfoLine;\r
997                                 sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
998                                 progDlg.SetLine(1, sInfoLine, true);\r
999                                 SetAndClearProgressInfo(&progDlg);\r
1000                                 progDlg.ShowModeless(m_hWnd);\r
1001                                 CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path, revSelected);\r
1002                                 bool bSuccess = true;\r
1003                                 if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
1004                                 {\r
1005                                         bSuccess = false;\r
1006                                         // try again, but with the selected revision as the peg revision\r
1007                                         if (!Cat(m_path, revSelected, revSelected, tempfile))\r
1008                                         {\r
1009                                                 progDlg.Stop();\r
1010                                                 SetAndClearProgressInfo((HWND)NULL);\r
1011                                                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
1012                                                 EnableOKButton();\r
1013                                                 break;\r
1014                                         }\r
1015                                         bSuccess = true;\r
1016                                 }\r
1017                                 if (bSuccess)\r
1018                                 {\r
1019                                         progDlg.Stop();\r
1020                                         SetAndClearProgressInfo((HWND)NULL);\r
1021                                         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
1022                                         int ret = 0;\r
1023                                         if (!bOpenWith)\r
1024                                                 ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
1025                                         if ((ret <= HINSTANCE_ERROR)||bOpenWith)\r
1026                                         {\r
1027                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
1028                                                 cmd += tempfile.GetWinPathString() + _T(" ");\r
1029                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
1030                                         }\r
1031                                 }\r
1032                         }\r
1033                         break;\r
1034                 case ID_BLAME:\r
1035                         {\r
1036                                 CBlameDlg dlg;\r
1037                                 dlg.EndRev = revSelected;\r
1038                                 if (dlg.DoModal() == IDOK)\r
1039                                 {\r
1040                                         CBlame blame;\r
1041                                         CString tempfile;\r
1042                                         CString logfile;\r
1043                                         tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE);\r
1044                                         if (!tempfile.IsEmpty())\r
1045                                         {\r
1046                                                 if (dlg.m_bTextView)\r
1047                                                 {\r
1048                                                         //open the default text editor for the result file\r
1049                                                         CAppUtils::StartTextViewer(tempfile);\r
1050                                                 }\r
1051                                                 else\r
1052                                                 {\r
1053                                                         CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" ");\r
1054                                                         if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams))\r
1055                                                         {\r
1056                                                                 break;\r
1057                                                         }\r
1058                                                 }\r
1059                                         }\r
1060                                         else\r
1061                                         {\r
1062                                                 CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
1063                                         }\r
1064                                 }\r
1065                         }\r
1066                         break;\r
1067                 case ID_UPDATE:\r
1068                         {\r
1069                                 CString sCmd;\r
1070                                 CString url = _T("tgit:")+pathURL;\r
1071                                 sCmd.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),\r
1072                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
1073                                         (LPCTSTR)m_path.GetWinPath(), (LONG)revSelected);\r
1074                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
1075                         }\r
1076                         break;\r
1077                 case ID_FINDENTRY:\r
1078                         {\r
1079                                 m_nSearchIndex = GetSelectionMark();\r
1080                                 if (m_nSearchIndex < 0)\r
1081                                         m_nSearchIndex = 0;\r
1082                                 if (m_pFindDialog)\r
1083                                 {\r
1084                                         break;\r
1085                                 }\r
1086                                 else\r
1087                                 {\r
1088                                         m_pFindDialog = new CFindReplaceDialog();\r
1089                                         m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this);                                                                        \r
1090                                 }\r
1091                         }\r
1092                         break;\r
1093                 case ID_REPOBROWSE:\r
1094                         {\r
1095                                 CString sCmd;\r
1096                                 sCmd.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),\r
1097                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
1098                                         (LPCTSTR)pathURL, (LPCTSTR)revSelected.ToString());\r
1099 \r
1100                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
1101                         }\r
1102                         break;\r
1103                 case ID_EDITLOG:\r
1104                         {\r
1105                                 EditLogMessage(selIndex);\r
1106                         }\r
1107                         break;\r
1108                 case ID_EDITAUTHOR:\r
1109                         {\r
1110                                 EditAuthor(selEntries);\r
1111                         }\r
1112                         break;\r
1113                 case ID_REVPROPS:\r
1114                         {\r
1115                                 CEditPropertiesDlg dlg;\r
1116                                 dlg.SetProjectProperties(&m_ProjectProperties);\r
1117                                 CTGitPathList escapedlist;\r
1118                                 dlg.SetPathList(CTGitPathList(CTGitPath(pathURL)));\r
1119                                 dlg.SetRevision(revSelected);\r
1120                                 dlg.RevProps(true);\r
1121                                 dlg.DoModal();\r
1122                         }\r
1123                         break;\r
1124                 case ID_COPYCLIPBOARD:\r
1125                         {\r
1126                                 CopySelectionToClipBoard();\r
1127                         }\r
1128                         break;\r
1129                 case ID_EXPORT:\r
1130                         {\r
1131                                 CString sCmd;\r
1132                                 sCmd.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),\r
1133                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
1134                                         (LPCTSTR)pathURL, (LONG)revSelected);\r
1135                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
1136                         }\r
1137                         break;\r
1138                 case ID_CHECKOUT:\r
1139                         {\r
1140                                 CString sCmd;\r
1141                                 CString url = _T("tgit:")+pathURL;\r
1142                                 sCmd.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),\r
1143                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
1144                                         (LPCTSTR)url, (LONG)revSelected);\r
1145                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
1146                         }\r
1147                         break;\r
1148                 case ID_VIEWREV:\r
1149                         {\r
1150                                 CString url = m_ProjectProperties.sWebViewerRev;\r
1151                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
1152                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
1153                                 if (!url.IsEmpty())\r
1154                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
1155                         }\r
1156                         break;\r
1157                 case ID_VIEWPATHREV:\r
1158                         {\r
1159                                 CString relurl = pathURL;\r
1160                                 CString sRoot = GetRepositoryRoot(CTGitPath(relurl));\r
1161                                 relurl = relurl.Mid(sRoot.GetLength());\r
1162                                 CString url = m_ProjectProperties.sWebViewerPathRev;\r
1163                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
1164                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
1165                                 url.Replace(_T("%PATH%"), relurl);\r
1166                                 if (!url.IsEmpty())\r
1167                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
1168                         }\r
1169                         break;\r
1170 #endif\r
1171                 default:\r
1172                         break;\r
1173                 } // switch (cmd)\r
1174                 theApp.DoWaitCursor(-1);\r
1175 //              EnableOKButton();\r
1176         } // if (popup.CreatePopupMenu())\r
1177 \r
1178 }\r
1179 \r
1180 bool CGitLogList::IsSelectionContinuous()\r
1181 {\r
1182         if ( GetSelectedCount()==1 )\r
1183         {\r
1184                 // if only one revision is selected, the selection is of course\r
1185                 // continuous\r
1186                 return true;\r
1187         }\r
1188 \r
1189         POSITION pos = GetFirstSelectedItemPosition();\r
1190         bool bContinuous = (m_arShownList.GetCount() == (INT_PTR)m_logEntries.size());\r
1191         if (bContinuous)\r
1192         {\r
1193                 int itemindex = GetNextSelectedItem(pos);\r
1194                 while (pos)\r
1195                 {\r
1196                         int nextindex = GetNextSelectedItem(pos);\r
1197                         if (nextindex - itemindex > 1)\r
1198                         {\r
1199                                 bContinuous = false;\r
1200                                 break;\r
1201                         }\r
1202                         itemindex = nextindex;\r
1203                 }\r
1204         }\r
1205         return bContinuous;\r
1206 }\r
1207 \r
1208 void CGitLogList::CopySelectionToClipBoard()\r
1209 {\r
1210 #if 0\r
1211         CString sClipdata;\r
1212         POSITION pos = GetFirstSelectedItemPosition();\r
1213         if (pos != NULL)\r
1214         {\r
1215                 CString sRev;\r
1216                 sRev.LoadString(IDS_LOG_REVISION);\r
1217                 CString sAuthor;\r
1218                 sAuthor.LoadString(IDS_LOG_AUTHOR);\r
1219                 CString sDate;\r
1220                 sDate.LoadString(IDS_LOG_DATE);\r
1221                 CString sMessage;\r
1222                 sMessage.LoadString(IDS_LOG_MESSAGE);\r
1223                 while (pos)\r
1224                 {\r
1225                         CString sLogCopyText;\r
1226                         CString sPaths;\r
1227                         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
1228                         LogChangedPathArray * cpatharray = pLogEntry->pArChangedPaths;\r
1229                         for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount(); ++cpPathIndex)\r
1230                         {\r
1231                                 LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
1232                                 sPaths += cpath->GetAction() + _T(" : ") + cpath->sPath;\r
1233                                 if (cpath->sCopyFromPath.IsEmpty())\r
1234                                         sPaths += _T("\r\n");\r
1235                                 else\r
1236                                 {\r
1237                                         CString sCopyFrom;\r
1238                                         sCopyFrom.Format(_T(" (%s: %s, %s, %ld)\r\n"), CString(MAKEINTRESOURCE(IDS_LOG_COPYFROM)), \r
1239                                                 (LPCTSTR)cpath->sCopyFromPath, \r
1240                                                 (LPCTSTR)CString(MAKEINTRESOURCE(IDS_LOG_REVISION)), \r
1241                                                 (LPCTSTR)cpath->lCopyFromRev);\r
1242                                         sPaths += sCopyFrom;\r
1243                                 }\r
1244                         }\r
1245                         sPaths.Trim();\r
1246                         sLogCopyText.Format(_T("%s: %d\r\n%s: %s\r\n%s: %s\r\n%s:\r\n%s\r\n----\r\n%s\r\n\r\n"),\r
1247                                 (LPCTSTR)sRev, pLogEntry->Rev,\r
1248                                 (LPCTSTR)sAuthor, (LPCTSTR)pLogEntry->sAuthor,\r
1249                                 (LPCTSTR)sDate, (LPCTSTR)pLogEntry->sDate,\r
1250                                 (LPCTSTR)sMessage, (LPCTSTR)pLogEntry->sMessage,\r
1251                                 (LPCTSTR)sPaths);\r
1252                         sClipdata +=  sLogCopyText;\r
1253                 }\r
1254                 CStringUtils::WriteAsciiStringToClipboard(sClipdata, GetSafeHwnd());\r
1255         }\r
1256 #endif\r
1257 }\r
1258 \r
1259 void CGitLogList::DiffSelectedRevWithPrevious()\r
1260 {\r
1261 #if 0\r
1262         if (m_bThreadRunning)\r
1263                 return;\r
1264         UpdateLogInfoLabel();\r
1265         int selIndex = m_LogList.GetSelectionMark();\r
1266         if (selIndex < 0)\r
1267                 return;\r
1268         int selCount = m_LogList.GetSelectedCount();\r
1269         if (selCount != 1)\r
1270                 return;\r
1271 \r
1272         // Find selected entry in the log list\r
1273         POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
1274         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
1275         long rev1 = pLogEntry->Rev;\r
1276         long rev2 = rev1-1;\r
1277         CTGitPath path = m_path;\r
1278 \r
1279         // See how many files under the relative root were changed in selected revision\r
1280         int nChanged = 0;\r
1281         LogChangedPath * changed = NULL;\r
1282         for (INT_PTR c = 0; c < pLogEntry->pArChangedPaths->GetCount(); ++c)\r
1283         {\r
1284                 LogChangedPath * cpath = pLogEntry->pArChangedPaths->GetAt(c);\r
1285                 if (cpath  &&  cpath -> sPath.Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)==0)\r
1286                 {\r
1287                         ++nChanged;\r
1288                         changed = cpath;\r
1289                 }\r
1290         }\r
1291 \r
1292         if (m_path.IsDirectory() && nChanged == 1) \r
1293         {\r
1294                 // We're looking at the log for a directory and only one file under dir was changed in the revision\r
1295                 // Do diff on that file instead of whole directory\r
1296                 path.AppendPathString(changed->sPath.Mid(m_sRelativeRoot.GetLength()));\r
1297         } \r
1298 \r
1299         m_bCancelled = FALSE;\r
1300         DialogEnableWindow(IDOK, FALSE);\r
1301         SetPromptApp(&theApp);\r
1302         theApp.DoWaitCursor(1);\r
1303 \r
1304         if (PromptShown())\r
1305         {\r
1306                 GitDiff diff(this, m_hWnd, true);\r
1307                 diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
1308                 diff.SetHEADPeg(m_LogRevision);\r
1309                 diff.ShowCompare(path, rev2, path, rev1);\r
1310         }\r
1311         else\r
1312         {\r
1313                 CAppUtils::StartShowCompare(m_hWnd, path, rev2, path, rev1, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
1314         }\r
1315 \r
1316         theApp.DoWaitCursor(-1);\r
1317         EnableOKButton();\r
1318 #endif\r
1319 }\r
1320 \r
1321 void CGitLogList::OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
1322 {\r
1323         LPNMLVFINDITEM pFindInfo = reinterpret_cast<LPNMLVFINDITEM>(pNMHDR);\r
1324         *pResult = -1;\r
1325         \r
1326         if (pFindInfo->lvfi.flags & LVFI_PARAM)\r
1327                 return; \r
1328         if ((pFindInfo->iStart < 0)||(pFindInfo->iStart >= m_arShownList.GetCount()))\r
1329                 return;\r
1330         if (pFindInfo->lvfi.psz == 0)\r
1331                 return;\r
1332 #if 0\r
1333         CString sCmp = pFindInfo->lvfi.psz;\r
1334         CString sRev;   \r
1335         for (int i=pFindInfo->iStart; i<m_arShownList.GetCount(); ++i)\r
1336         {\r
1337                 GitRev * pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(i));\r
1338                 sRev.Format(_T("%ld"), pLogEntry->Rev);\r
1339                 if (pFindInfo->lvfi.flags & LVFI_PARTIAL)\r
1340                 {\r
1341                         if (sCmp.Compare(sRev.Left(sCmp.GetLength()))==0)\r
1342                         {\r
1343                                 *pResult = i;\r
1344                                 return;\r
1345                         }\r
1346                 }\r
1347                 else\r
1348                 {\r
1349                         if (sCmp.Compare(sRev)==0)\r
1350                         {\r
1351                                 *pResult = i;\r
1352                                 return;\r
1353                         }\r
1354                 }\r
1355         }\r
1356         if (pFindInfo->lvfi.flags & LVFI_WRAP)\r
1357         {\r
1358                 for (int i=0; i<pFindInfo->iStart; ++i)\r
1359                 {\r
1360                         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(i));\r
1361                         sRev.Format(_T("%ld"), pLogEntry->Rev);\r
1362                         if (pFindInfo->lvfi.flags & LVFI_PARTIAL)\r
1363                         {\r
1364                                 if (sCmp.Compare(sRev.Left(sCmp.GetLength()))==0)\r
1365                                 {\r
1366                                         *pResult = i;\r
1367                                         return;\r
1368                                 }\r
1369                         }\r
1370                         else\r
1371                         {\r
1372                                 if (sCmp.Compare(sRev)==0)\r
1373                                 {\r
1374                                         *pResult = i;\r
1375                                         return;\r
1376                                 }\r
1377                         }\r
1378                 }\r
1379         }\r
1380 #endif\r
1381         *pResult = -1;\r
1382 }\r
1383 \r
1384 int CGitLogList::FillGitLog()\r
1385 {\r
1386         ClearText();\r
1387 \r
1388         this->m_logEntries.ClearAll();\r
1389         this->m_logEntries.ParserFromLog();\r
1390         SetItemCountEx(this->m_logEntries.size());\r
1391 \r
1392         this->m_arShownList.RemoveAll();\r
1393 \r
1394         for(int i=0;i<m_logEntries.size();i++)\r
1395                 this->m_arShownList.Add(&m_logEntries[i]);\r
1396 \r
1397         return 0;\r
1398 }\r
1399 \r
1400 BOOL CGitLogList::PreTranslateMessage(MSG* pMsg)\r
1401 {\r
1402         // Skip Ctrl-C when copying text out of the log message or search filter\r
1403         BOOL bSkipAccelerator = ( pMsg->message == WM_KEYDOWN && pMsg->wParam=='C' && (GetFocus()==GetDlgItem(IDC_MSGVIEW) || GetFocus()==GetDlgItem(IDC_SEARCHEDIT) ) && GetKeyState(VK_CONTROL)&0x8000 );\r
1404         if (pMsg->message == WM_KEYDOWN && pMsg->wParam=='\r')\r
1405         {\r
1406                 //if (GetFocus()==GetDlgItem(IDC_LOGLIST))\r
1407                 {\r
1408                         if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
1409                         {\r
1410                                 DiffSelectedRevWithPrevious();\r
1411                                 return TRUE;\r
1412                         }\r
1413                 }\r
1414 #if 0\r
1415                 if (GetFocus()==GetDlgItem(IDC_LOGMSG))\r
1416                 {\r
1417                         DiffSelectedFile();\r
1418                         return TRUE;\r
1419                 }\r
1420 #endif\r
1421         }\r
1422 \r
1423 #if 0\r
1424         if (m_hAccel && !bSkipAccelerator)\r
1425         {\r
1426                 int ret = TranslateAccelerator(m_hWnd, m_hAccel, pMsg);\r
1427                 if (ret)\r
1428                         return TRUE;\r
1429         }\r
1430         \r
1431 #endif\r
1432         //m_tooltips.RelayEvent(pMsg);\r
1433         return __super::PreTranslateMessage(pMsg);\r
1434 }\r
1435 \r
1436 void CGitLogList::OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult)\r
1437 {\r
1438         // a double click on an entry in the revision list has happened\r
1439         *pResult = 0;\r
1440 \r
1441   if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
1442           DiffSelectedRevWithPrevious();\r
1443 }