OSDN Git Service

build success
authorFrank Li <lznuaa@gmail.com>
Fri, 26 Dec 2008 02:23:10 +0000 (10:23 +0800)
committerFrank Li <lznuaa@gmail.com>
Fri, 26 Dec 2008 02:23:10 +0000 (10:23 +0800)
src/TortoiseProc/GitLogList.cpp [new file with mode: 0644]
src/TortoiseProc/GitLogList.h [new file with mode: 0644]
src/TortoiseProc/LogDlg.cpp
src/TortoiseProc/LogDlg.h

diff --git a/src/TortoiseProc/GitLogList.cpp b/src/TortoiseProc/GitLogList.cpp
new file mode 100644 (file)
index 0000000..4abd9b3
--- /dev/null
@@ -0,0 +1,1443 @@
+// GitLogList.cpp : implementation file\r
+//\r
+\r
+#include "stdafx.h"\r
+#include "TortoiseProc.h"\r
+#include "GitLogList.h"\r
+#include "GitRev.h"\r
+//#include "VssStyle.h"\r
+#include "IconMenu.h"\r
+// CGitLogList\r
+#include "cursor.h"\r
+#include "InputDlg.h"\r
+#include "PropDlg.h"\r
+#include "SVNProgressDlg.h"\r
+#include "ProgressDlg.h"\r
+//#include "RepositoryBrowser.h"\r
+//#include "CopyDlg.h"\r
+//#include "StatGraphDlg.h"\r
+#include "Logdlg.h"\r
+#include "MessageBox.h"\r
+#include "Registry.h"\r
+#include "AppUtils.h"\r
+#include "PathUtils.h"\r
+#include "StringUtils.h"\r
+#include "UnicodeUtils.h"\r
+#include "TempFile.h"\r
+//#include "GitInfo.h"\r
+//#include "GitDiff.h"\r
+#include "IconMenu.h"\r
+//#include "RevisionRangeDlg.h"\r
+//#include "BrowseFolder.h"\r
+//#include "BlameDlg.h"\r
+//#include "Blame.h"\r
+//#include "GitHelpers.h"\r
+#include "GitStatus.h"\r
+//#include "LogDlgHelper.h"\r
+//#include "CachedLogInfo.h"\r
+//#include "RepositoryInfo.h"\r
+//#include "EditPropertiesDlg.h"\r
+#include "FileDiffDlg.h"\r
+\r
+\r
+\r
+\r
+IMPLEMENT_DYNAMIC(CGitLogList, CHintListCtrl)\r
+\r
+CGitLogList::CGitLogList():CHintListCtrl()\r
+       ,m_regMaxBugIDColWidth(_T("Software\\TortoiseGit\\MaxBugIDColWidth"), 200)\r
+       ,m_nSearchIndex(0)\r
+{\r
+       // use the default GUI font, create a copy of it and\r
+       // change the copy to BOLD (leave the rest of the font\r
+       // the same)\r
+       HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);\r
+       LOGFONT lf = {0};\r
+       GetObject(hFont, sizeof(LOGFONT), &lf);\r
+       lf.lfWeight = FW_BOLD;\r
+       m_boldFont = CreateFontIndirect(&lf);\r
+\r
+}\r
+\r
+CGitLogList::~CGitLogList()\r
+{\r
+       DestroyIcon(m_hModifiedIcon);\r
+       DestroyIcon(m_hReplacedIcon);\r
+       DestroyIcon(m_hAddedIcon);\r
+       DestroyIcon(m_hDeletedIcon);\r
+       m_logEntries.ClearAll();\r
+\r
+       if (m_boldFont)\r
+               DeleteObject(m_boldFont);\r
+\r
+}\r
+\r
+\r
+BEGIN_MESSAGE_MAP(CGitLogList, CHintListCtrl)\r
+       ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdrawLoglist)\r
+       ON_NOTIFY(LVN_GETDISPINFO, 0, OnLvnGetdispinfoLoglist)\r
+       ON_WM_CONTEXTMENU()\r
+       ON_NOTIFY(NM_DBLCLK, 0, OnNMDblclkLoglist)\r
+       ON_NOTIFY(LVN_ODFINDITEM, IDC_LOGLIST, OnLvnOdfinditemLoglist)\r
+END_MESSAGE_MAP()\r
+\r
+int CGitLogList:: OnCreate(LPCREATESTRUCT lpCreateStruct)\r
+{\r
+       SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_SUBITEMIMAGES);\r
+       // load the icons for the action columns\r
+       m_hModifiedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONMODIFIED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
+       m_hReplacedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONREPLACED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
+       m_hAddedIcon    =  (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONADDED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
+       m_hDeletedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONDELETED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);\r
+\r
+       return CHintListCtrl::OnCreate(lpCreateStruct);\r
+}\r
+\r
+void CGitLogList::InsertGitColumn()\r
+{\r
+       CString temp;\r
+\r
+       int c = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
+       \r
+       while (c>=0)\r
+               DeleteColumn(c--);\r
+       temp.LoadString(IDS_LOG_GRAPH);\r
+\r
+       InsertColumn(this->LOGLIST_GRAPH, temp);\r
+       \r
+#if 0  \r
+       // make the revision column right aligned\r
+       LVCOLUMN Column;\r
+       Column.mask = LVCF_FMT;\r
+       Column.fmt = LVCFMT_RIGHT;\r
+       SetColumn(0, &Column); \r
+#endif \r
+//     CString log;\r
+//     g_Git.GetLog(log);\r
+\r
+       temp.LoadString(IDS_LOG_ACTIONS);\r
+       InsertColumn(this->LOGLIST_ACTION, temp);\r
+       \r
+       temp.LoadString(IDS_LOG_MESSAGE);\r
+       InsertColumn(this->LOGLIST_MESSAGE, temp);\r
+       \r
+       temp.LoadString(IDS_LOG_AUTHOR);\r
+       InsertColumn(this->LOGLIST_AUTHOR, temp);\r
+       \r
+       temp.LoadString(IDS_LOG_DATE);\r
+       InsertColumn(this->LOGLIST_DATE, temp);\r
+       \r
+\r
+       if (m_bShowBugtraqColumn)\r
+       {\r
+//             temp = m_ProjectProperties.sLabel;\r
+               if (temp.IsEmpty())\r
+                       temp.LoadString(IDS_LOG_BUGIDS);\r
+               InsertColumn(this->LOGLIST_BUG, temp);\r
+\r
+       }\r
+       \r
+       SetRedraw(false);\r
+       ResizeAllListCtrlCols();\r
+       SetRedraw(true);\r
+\r
+}\r
+\r
+void CGitLogList::ResizeAllListCtrlCols()\r
+{\r
+\r
+       const int nMinimumWidth = ICONITEMBORDER+16*4;\r
+       int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
+       int nItemCount = GetItemCount();\r
+       TCHAR textbuf[MAX_PATH];\r
+       CHeaderCtrl * pHdrCtrl = (CHeaderCtrl*)(GetDlgItem(0));\r
+       if (pHdrCtrl)\r
+       {\r
+               for (int col = 0; col <= maxcol; col++)\r
+               {\r
+                       HDITEM hdi = {0};\r
+                       hdi.mask = HDI_TEXT;\r
+                       hdi.pszText = textbuf;\r
+                       hdi.cchTextMax = sizeof(textbuf);\r
+                       pHdrCtrl->GetItem(col, &hdi);\r
+                       int cx = GetStringWidth(hdi.pszText)+20; // 20 pixels for col separator and margin\r
+                       for (int index = 0; index<nItemCount; ++index)\r
+                       {\r
+                               // get the width of the string and add 14 pixels for the column separator and margins\r
+                               int linewidth = GetStringWidth(GetItemText(index, col)) + 14;\r
+                               if (index < m_arShownList.GetCount())\r
+                               {\r
+                                       GitRev * pCurLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(index));\r
+                                       if ((pCurLogEntry)&&(pCurLogEntry->m_CommitHash == m_wcRev.m_CommitHash))\r
+                                       {\r
+                                               // set the bold font and ask for the string width again\r
+                                               SendMessage(WM_SETFONT, (WPARAM)m_boldFont, NULL);\r
+                                               linewidth = GetStringWidth(GetItemText(index, col)) + 14;\r
+                                               // restore the system font\r
+                                               SendMessage(WM_SETFONT, NULL, NULL);\r
+                                       }\r
+                               }\r
+                               if (index == 0)\r
+                               {\r
+                                       // add the image size\r
+                                       CImageList * pImgList = GetImageList(LVSIL_SMALL);\r
+                                       if ((pImgList)&&(pImgList->GetImageCount()))\r
+                                       {\r
+                                               IMAGEINFO imginfo;\r
+                                               pImgList->GetImageInfo(0, &imginfo);\r
+                                               linewidth += (imginfo.rcImage.right - imginfo.rcImage.left);\r
+                                               linewidth += 3; // 3 pixels between icon and text\r
+                                       }\r
+                               }\r
+                               if (cx < linewidth)\r
+                                       cx = linewidth;\r
+                       }\r
+                       // Adjust columns "Actions" containing icons\r
+                       if (col == this->LOGLIST_ACTION)\r
+                       {\r
+                               if (cx < nMinimumWidth)\r
+                               {\r
+                                       cx = nMinimumWidth;\r
+                               }\r
+                       }\r
+                       \r
+                       if (col == this->LOGLIST_MESSAGE)\r
+                       {\r
+                               if (cx > LOGLIST_MESSAGE_MAX)\r
+                               {\r
+                                       cx = LOGLIST_MESSAGE_MAX;\r
+                               }\r
+\r
+                       }\r
+                       // keep the bug id column small\r
+                       if ((col == 4)&&(m_bShowBugtraqColumn))\r
+                       {\r
+                               if (cx > (int)(DWORD)m_regMaxBugIDColWidth)\r
+                               {\r
+                                       cx = (int)(DWORD)m_regMaxBugIDColWidth;\r
+                               }\r
+                       }\r
+\r
+                       SetColumnWidth(col, cx);\r
+               }\r
+       }\r
+\r
+}\r
+\r
+\r
+void CGitLogList::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+\r
+       NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
+       // Take the default processing unless we set this to something else below.\r
+       *pResult = CDRF_DODEFAULT;\r
+\r
+       if (m_bNoDispUpdates)\r
+               return;\r
+\r
+       switch (pLVCD->nmcd.dwDrawStage)\r
+       {\r
+       case CDDS_PREPAINT:\r
+               {\r
+                       *pResult = CDRF_NOTIFYITEMDRAW;\r
+                       return;\r
+               }\r
+               break;\r
+       case CDDS_ITEMPREPAINT:\r
+               {\r
+                       // This is the prepaint stage for an item. Here's where we set the\r
+                       // item's text color. \r
+                       \r
+                       // Tell Windows to send draw notifications for each subitem.\r
+                       *pResult = CDRF_NOTIFYSUBITEMDRAW;\r
+\r
+                       COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
+\r
+                       if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
+                       {\r
+                               GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec);\r
+                               if (data)\r
+                               {\r
+#if 0\r
+                                       if (data->bCopiedSelf)\r
+                                       {\r
+                                               // only change the background color if the item is not 'hot' (on vista with m_Themes enabled)\r
+                                               if (!m_Theme.IsAppm_Themed() || !m_bVista || ((pLVCD->nmcd.uItemState & CDIS_HOT)==0))\r
+                                                       pLVCD->clrTextBk = GetSysColor(COLOR_MENU);\r
+                                       }\r
+\r
+                                       if (data->bCopies)\r
+                                               crText = m_Colors.GetColor(CColors::Modified);\r
+#endif\r
+//                                     if ((data->childStackDepth)||(m_mergedRevs.find(data->Rev) != m_mergedRevs.end()))\r
+//                                             crText = GetSysColor(COLOR_GRAYTEXT);\r
+//                                     if (data->Rev == m_wcRev)\r
+//                                     {\r
+//                                             SelectObject(pLVCD->nmcd.hdc, m_boldFont);\r
+                                               // We changed the font, so we're returning CDRF_NEWFONT. This\r
+                                               // tells the control to recalculate the extent of the text.\r
+//                                             *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;\r
+//                                     }\r
+                               }\r
+                       }\r
+                       if (m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
+                       {\r
+                               if (m_bStrictStopped)\r
+                                       crText = GetSysColor(COLOR_GRAYTEXT);\r
+                       }\r
+                       // Store the color back in the NMLVCUSTOMDRAW struct.\r
+                       pLVCD->clrText = crText;\r
+                       return;\r
+               }\r
+               break;\r
+       case CDDS_ITEMPREPAINT|CDDS_ITEM|CDDS_SUBITEM:\r
+               {\r
+                       if ((m_bStrictStopped)&&(m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec))\r
+                       {\r
+                               pLVCD->nmcd.uItemState &= ~(CDIS_SELECTED|CDIS_FOCUS);\r
+                       }\r
+                       if (pLVCD->iSubItem == 1)\r
+                       {\r
+                               *pResult = CDRF_DODEFAULT;\r
+\r
+                               if (m_arShownList.GetCount() <= (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
+                                       return;\r
+\r
+                               int             nIcons = 0;\r
+                               int             iconwidth = ::GetSystemMetrics(SM_CXSMICON);\r
+                               int             iconheight = ::GetSystemMetrics(SM_CYSMICON);\r
+\r
+                               GitRev* pLogEntry = reinterpret_cast<GitRev *>(m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec));\r
+\r
+                               // Get the selected state of the\r
+                               // item being drawn.\r
+                               LVITEM   rItem;\r
+                               SecureZeroMemory(&rItem, sizeof(LVITEM));\r
+                               rItem.mask  = LVIF_STATE;\r
+                               rItem.iItem = pLVCD->nmcd.dwItemSpec;\r
+                               rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
+                               GetItem(&rItem);\r
+\r
+                               CRect rect;\r
+                               GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
+\r
+                               // Fill the background\r
+                               if (m_Theme.IsAppThemed() && m_bVista)\r
+                               {\r
+                                       m_Theme.Open(m_hWnd, L"Explorer");\r
+                                       int state = LISS_NORMAL;\r
+                                       if (rItem.state & LVIS_SELECTED)\r
+                                       {\r
+                                               if (::GetFocus() == m_hWnd)\r
+                                                       state |= LISS_SELECTED;\r
+                                               else\r
+                                                       state |= LISS_SELECTEDNOTFOCUS;\r
+                                       }\r
+                                       else\r
+                                       {\r
+#if 0\r
+                                               if (pLogEntry->bCopiedSelf)\r
+                                               {\r
+                                                       // unfortunately, the pLVCD->nmcd.uItemState does not contain valid\r
+                                                       // information at this drawing stage. But we can check the whether the\r
+                                                       // previous stage changed the background color of the item\r
+                                                       if (pLVCD->clrTextBk == GetSysColor(COLOR_MENU))\r
+                                                       {\r
+                                                               HBRUSH brush;\r
+                                                               brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
+                                                               if (brush)\r
+                                                               {\r
+                                                                       ::FillRect(pLVCD->nmcd.hdc, &rect, brush);\r
+                                                                       ::DeleteObject(brush);\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+#endif\r
+                                       }\r
+\r
+                                       if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTDETAIL, state))\r
+                                               m_Theme.DrawParentBackground(m_hWnd, pLVCD->nmcd.hdc, &rect);\r
+\r
+                                       m_Theme.DrawBackground(pLVCD->nmcd.hdc, LVP_LISTDETAIL, state, &rect, NULL);\r
+                               }\r
+                               else\r
+                               {\r
+                                       HBRUSH brush;\r
+                                       if (rItem.state & LVIS_SELECTED)\r
+                                       {\r
+                                               if (::GetFocus() == m_hWnd)\r
+                                                       brush = ::CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT));\r
+                                               else\r
+                                                       brush = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               //if (pLogEntry->bCopiedSelf)\r
+                                               //      brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
+                                               //else\r
+                                                       brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));\r
+                                       }\r
+                                       if (brush == NULL)\r
+                                               return;\r
+\r
+                                       ::FillRect(pLVCD->nmcd.hdc, &rect, brush);\r
+                                       ::DeleteObject(brush);\r
+                               }\r
+\r
+                               // Draw the icon(s) into the compatible DC\r
+                               if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_MODIFIED)\r
+                                       ::DrawIconEx(pLVCD->nmcd.hdc, rect.left + ICONITEMBORDER, rect.top, m_hModifiedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
+                               nIcons++;\r
+\r
+                               if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_ADDED)\r
+                                       ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hAddedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
+                               nIcons++;\r
+\r
+                               if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_DELETED)\r
+                                       ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hDeletedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
+                               nIcons++;\r
+\r
+                               if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
+                                       ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hReplacedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
+                               nIcons++;\r
+                               *pResult = CDRF_SKIPDEFAULT;\r
+                               return;\r
+                       }\r
+               }\r
+               break;\r
+       }\r
+       *pResult = CDRF_DODEFAULT;\r
+\r
+}\r
+\r
+// CGitLogList message handlers\r
+\r
+void CGitLogList::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);\r
+\r
+       // Create a pointer to the item\r
+       LV_ITEM* pItem = &(pDispInfo)->item;\r
+\r
+       // Do the list need text information?\r
+       if (!(pItem->mask & LVIF_TEXT))\r
+               return;\r
+\r
+       // By default, clear text buffer.\r
+       lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
+\r
+       bool bOutOfRange = pItem->iItem >= ShownCountWithStopped();\r
+       \r
+       *pResult = 0;\r
+       if (m_bNoDispUpdates || m_bThreadRunning || bOutOfRange)\r
+               return;\r
+\r
+       // Which item number?\r
+       int itemid = pItem->iItem;\r
+       GitRev * pLogEntry = NULL;\r
+       if (itemid < m_arShownList.GetCount())\r
+               pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(pItem->iItem));\r
+    \r
+       // Which column?\r
+       switch (pItem->iSubItem)\r
+       {\r
+       case this->LOGLIST_GRAPH:       //Graphic\r
+               if (pLogEntry)\r
+               {\r
+               }\r
+               break;\r
+       case this->LOGLIST_ACTION: //action -- no text in the column\r
+               break;\r
+       case this->LOGLIST_MESSAGE: //Message\r
+               if (pLogEntry)\r
+                       lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_Subject, pItem->cchTextMax);\r
+               break;\r
+       case this->LOGLIST_AUTHOR: //Author\r
+               if (pLogEntry)\r
+                       lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorName, pItem->cchTextMax);\r
+               break;\r
+       case this->LOGLIST_DATE: //Date\r
+               if (pLogEntry)\r
+                       lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorDate.Format(_T("%Y-%m-%d %H:%M")), pItem->cchTextMax);\r
+               break;\r
+               \r
+       case 5:\r
+\r
+               break;\r
+       default:\r
+               ASSERT(false);\r
+       }\r
+}\r
+\r
+void CGitLogList::OnContextMenu(CWnd* pWnd, CPoint point)\r
+{\r
+\r
+       int selIndex = GetSelectionMark();\r
+       if (selIndex < 0)\r
+               return; // nothing selected, nothing to do with a context menu\r
+\r
+       // if the user selected the info text telling about not all revisions shown due to\r
+       // the "stop on copy/rename" option, we also don't show the context menu\r
+       if ((m_bStrictStopped)&&(selIndex == m_arShownList.GetCount()))\r
+               return;\r
+\r
+       // if the context menu is invoked through the keyboard, we have to use\r
+       // a calculated position on where to anchor the menu on\r
+       if ((point.x == -1) && (point.y == -1))\r
+       {\r
+               CRect rect;\r
+               GetItemRect(selIndex, &rect, LVIR_LABEL);\r
+               ClientToScreen(&rect);\r
+               point = rect.CenterPoint();\r
+       }\r
+       m_nSearchIndex = selIndex;\r
+       m_bCancelled = FALSE;\r
+\r
+       // calculate some information the context menu commands can use\r
+//     CString pathURL = GetURLFromPath(m_path);\r
+\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       int indexNext = GetNextSelectedItem(pos);\r
+       if (indexNext < 0)\r
+               return;\r
+\r
+       GitRev* pSelLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(indexNext));\r
+#if 0\r
+       GitRev revSelected = pSelLogEntry->Rev;\r
+       GitRev revPrevious = git_revnum_t(revSelected)-1;\r
+       if ((pSelLogEntry->pArChangedPaths)&&(pSelLogEntry->pArChangedPaths->GetCount() <= 2))\r
+       {\r
+               for (int i=0; i<pSelLogEntry->pArChangedPaths->GetCount(); ++i)\r
+               {\r
+                       LogChangedPath * changedpath = (LogChangedPath *)pSelLogEntry->pArChangedPaths->GetAt(i);\r
+                       if (changedpath->lCopyFromRev)\r
+                               revPrevious = changedpath->lCopyFromRev;\r
+               }\r
+       }\r
+       GitRev revSelected2;\r
+       if (pos)\r
+       {\r
+               PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
+               revSelected2 = pLogEntry->Rev;\r
+       }\r
+       bool bAllFromTheSameAuthor = true;\r
+       CString firstAuthor;\r
+       CLogDataVector selEntries;\r
+       GitRev revLowest, revHighest;\r
+       GitRevRangeArray revisionRanges;\r
+       {\r
+               POSITION pos = GetFirstSelectedItemPosition();\r
+               PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
+               revisionRanges.AddRevision(pLogEntry->Rev);\r
+               selEntries.push_back(pLogEntry);\r
+               firstAuthor = pLogEntry->sAuthor;\r
+               revLowest = pLogEntry->Rev;\r
+               revHighest = pLogEntry->Rev;\r
+               while (pos)\r
+               {\r
+                       pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
+                       revisionRanges.AddRevision(pLogEntry->Rev);\r
+                       selEntries.push_back(pLogEntry);\r
+                       if (firstAuthor.Compare(pLogEntry->sAuthor))\r
+                               bAllFromTheSameAuthor = false;\r
+                       revLowest = (git_revnum_t(pLogEntry->Rev) > git_revnum_t(revLowest) ? revLowest : pLogEntry->Rev);\r
+                       revHighest = (git_revnum_t(pLogEntry->Rev) < git_revnum_t(revHighest) ? revHighest : pLogEntry->Rev);\r
+               }\r
+       }\r
+\r
+#endif\r
+\r
+       int FirstSelect=-1, LastSelect=-1;\r
+       pos = GetFirstSelectedItemPosition();\r
+       FirstSelect = GetNextSelectedItem(pos);\r
+       while(pos)\r
+       {\r
+               LastSelect = GetNextSelectedItem(pos);\r
+       }\r
+       //entry is selected, now show the popup menu\r
+       CIconMenu popup;\r
+       if (popup.CreatePopupMenu())\r
+       {\r
+               if (GetSelectedCount() == 1)\r
+               {\r
+#if 0\r
+                       if (!m_path.IsDirectory())\r
+                       {\r
+                               if (m_hasWC)\r
+                               {\r
+                                       popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
+                                       popup.AppendMenuIcon(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME);\r
+                               }\r
+                               popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
+                               popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
+                               popup.AppendMenu(MF_SEPARATOR, NULL);\r
+                               popup.AppendMenuIcon(ID_SAVEAS, IDS_LOG_POPUP_SAVE, IDI_SAVEAS);\r
+                               popup.AppendMenuIcon(ID_OPEN, IDS_LOG_POPUP_OPEN, IDI_OPEN);\r
+                               popup.AppendMenuIcon(ID_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
+                               popup.AppendMenuIcon(ID_BLAME, IDS_LOG_POPUP_BLAME, IDI_BLAME);\r
+                               popup.AppendMenu(MF_SEPARATOR, NULL);\r
+                       }\r
+                       else\r
+#endif \r
+                       {\r
+                               if (m_hasWC)\r
+                               {\r
+                                       popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
+                                       // TODO:\r
+                                       // TortoiseMerge could be improved to take a /blame switch\r
+                                       // and then not 'cat' the files from a unified diff but\r
+                                       // blame then.\r
+                                       // But until that's implemented, the context menu entry for\r
+                                       // this feature is commented out.\r
+                                       //popup.AppendMenu(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME);\r
+                               }\r
+                               popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
+                               popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
+                               popup.AppendMenuIcon(ID_BLAMEWITHPREVIOUS, IDS_LOG_POPUP_BLAMEWITHPREVIOUS, IDI_BLAME);\r
+                               popup.AppendMenu(MF_SEPARATOR, NULL);\r
+                       }\r
+\r
+//                     if (!m_ProjectProperties.sWebViewerRev.IsEmpty())\r
+//                     {\r
+//                             popup.AppendMenuIcon(ID_VIEWREV, IDS_LOG_POPUP_VIEWREV);\r
+//                     }\r
+//                     if (!m_ProjectProperties.sWebViewerPathRev.IsEmpty())\r
+//                     {\r
+//                             popup.AppendMenuIcon(ID_VIEWPATHREV, IDS_LOG_POPUP_VIEWPATHREV);\r
+//                     }\r
+//                     if ((!m_ProjectProperties.sWebViewerPathRev.IsEmpty())||\r
+//                             (!m_ProjectProperties.sWebViewerRev.IsEmpty()))\r
+//                     {\r
+//                             popup.AppendMenu(MF_SEPARATOR, NULL);\r
+//                     }\r
+\r
+//                     popup.AppendMenuIcon(ID_REPOBROWSE, IDS_LOG_BROWSEREPO, IDI_REPOBROWSE);\r
+//                     popup.AppendMenuIcon(ID_COPY, IDS_LOG_POPUP_COPY);\r
+//                     if (m_hasWC)\r
+//                             popup.AppendMenuIcon(ID_UPDATE, IDS_LOG_POPUP_UPDATE, IDI_UPDATE);\r
+                       if (m_hasWC)\r
+                               popup.AppendMenuIcon(ID_REVERTTOREV, IDS_LOG_POPUP_REVERTTOREV, IDI_REVERT);\r
+                       if (m_hasWC)\r
+                               popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREV, IDI_REVERT);\r
+//                     if (m_hasWC)\r
+//                             popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREV, IDI_MERGE);\r
+                       popup.AppendMenuIcon(ID_CHECKOUT, IDS_MENUCHECKOUT, IDI_CHECKOUT);\r
+                       popup.AppendMenuIcon(ID_EXPORT, IDS_MENUEXPORT, IDI_EXPORT);\r
+                       popup.AppendMenu(MF_SEPARATOR, NULL);\r
+               }\r
+               else if (GetSelectedCount() >= 2)\r
+               {\r
+                       bool bAddSeparator = false;\r
+                       if (IsSelectionContinuous() || (GetSelectedCount() == 2))\r
+                       {\r
+                               popup.AppendMenuIcon(ID_COMPARETWO, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);\r
+                       }\r
+                       if (GetSelectedCount() == 2)\r
+                       {\r
+                               popup.AppendMenuIcon(ID_BLAMETWO, IDS_LOG_POPUP_BLAMEREVS, IDI_BLAME);\r
+                               popup.AppendMenuIcon(ID_GNUDIFF2, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
+                               bAddSeparator = true;\r
+                       }\r
+                       if (m_hasWC)\r
+                       {\r
+                               popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREVS, IDI_REVERT);\r
+//                             if (m_hasWC)\r
+//                                     popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREVS, IDI_MERGE);\r
+                               bAddSeparator = true;\r
+                       }\r
+                       if (bAddSeparator)\r
+                               popup.AppendMenu(MF_SEPARATOR, NULL);\r
+               }\r
+#if 0\r
+//             if ((selEntries.size() > 0)&&(bAllFromTheSameAuthor))\r
+//             {\r
+//                     popup.AppendMenuIcon(ID_EDITAUTHOR, IDS_LOG_POPUP_EDITAUTHOR);\r
+//             }\r
+//             if (GetSelectedCount() == 1)\r
+//             {\r
+//                     popup.AppendMenuIcon(ID_EDITLOG, IDS_LOG_POPUP_EDITLOG);\r
+//                     popup.AppendMenuIcon(ID_REVPROPS, IDS_REPOBROWSE_SHOWREVPROP, IDI_PROPERTIES); // "Show Revision Properties"\r
+//                     popup.AppendMenu(MF_SEPARATOR, NULL);\r
+//             }\r
+#endif\r
+               if (GetSelectedCount() != 0)\r
+               {\r
+                       popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD);\r
+               }\r
+               popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND);\r
+\r
+               int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
+//             DialogEnableWindow(IDOK, FALSE);\r
+//             SetPromptApp(&theApp);\r
+               theApp.DoWaitCursor(1);\r
+               bool bOpenWith = false;\r
+\r
+               switch (cmd)\r
+               {\r
+                       case ID_GNUDIFF1:\r
+                       {\r
+                               CString tempfile=GetTempFile();\r
+                               CString cmd;\r
+                               GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
+                               cmd.Format(_T("git.cmd diff-tree -r -p --stat %s"),r1->m_CommitHash);\r
+                               g_Git.RunLogFile(cmd,tempfile);\r
+                               CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r1->m_Subject);\r
+                       }\r
+                       break;\r
+\r
+                       case ID_GNUDIFF2:\r
+                       {\r
+                               CString tempfile=GetTempFile();\r
+                               CString cmd;\r
+                               GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
+                               GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
+                               cmd.Format(_T("git.cmd diff-tree -r -p --stat %s %s"),r1->m_CommitHash,r2->m_CommitHash);\r
+                               g_Git.RunLogFile(cmd,tempfile);\r
+                               CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r2->m_CommitHash.Left(6));\r
+\r
+                       }\r
+                       break;\r
+\r
+               case ID_COMPARETWO:\r
+                       {\r
+                               GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
+                               GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
+                               CFileDiffDlg dlg;\r
+                               dlg.SetDiff(NULL,*r1,*r2);\r
+                               dlg.DoModal();\r
+                               \r
+                       }\r
+                       break;\r
+\r
+#if 0\r
+               case ID_GNUDIFF1:\r
+                       {\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, this->m_hWnd, true);\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowUnifiedDiff(m_path, revPrevious, m_path, revSelected);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowUnifiedDiff(m_hWnd, m_path, revPrevious, m_path, revSelected, GitRev(), m_LogRevision);\r
+                       }\r
+                       break;\r
+\r
+               case ID_GNUDIFF2:\r
+                       {\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, this->m_hWnd, true);\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowUnifiedDiff(m_path, revSelected2, m_path, revSelected);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowUnifiedDiff(m_hWnd, m_path, revSelected2, m_path, revSelected, GitRev(), m_LogRevision);\r
+                       }\r
+                       break;\r
+               case ID_REVERTREV:\r
+                       {\r
+                               // we need an URL to complete this command, so error out if we can't get an URL\r
+                               if (pathURL.IsEmpty())\r
+                               {\r
+                                       CString strMessage;\r
+                                       strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
+                                       CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
+                                       TRACE(_T("could not retrieve the URL of the folder!\n"));\r
+                                       break;          //exit\r
+                               }\r
+                               CString msg;\r
+                               msg.Format(IDS_LOG_REVERT_CONFIRM, m_path.GetWinPath());\r
+                               if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
+                               {\r
+                                       CGitProgressDlg dlg;\r
+                                       dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
+                                       dlg.SetPathList(CTGitPathList(m_path));\r
+                                       dlg.SetUrl(pathURL);\r
+                                       dlg.SetSecondUrl(pathURL);\r
+                                       revisionRanges.AdjustForMerge(true);\r
+                                       dlg.SetRevisionRanges(revisionRanges);\r
+                                       dlg.SetPegRevision(m_LogRevision);\r
+                                       dlg.DoModal();\r
+                               }\r
+                       }\r
+                       break;\r
+               case ID_MERGEREV:\r
+                       {\r
+                               // we need an URL to complete this command, so error out if we can't get an URL\r
+                               if (pathURL.IsEmpty())\r
+                               {\r
+                                       CString strMessage;\r
+                                       strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
+                                       CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
+                                       TRACE(_T("could not retrieve the URL of the folder!\n"));\r
+                                       break;          //exit\r
+                               }\r
+\r
+                               CString path = m_path.GetWinPathString();\r
+                               bool bGotSavePath = false;\r
+                               if ((GetSelectedCount() == 1)&&(!m_path.IsDirectory()))\r
+                               {\r
+                                       bGotSavePath = CAppUtils::FileOpenSave(path, NULL, IDS_LOG_MERGETO, IDS_COMMONFILEFILTER, true, GetSafeHwnd());\r
+                               }\r
+                               else\r
+                               {\r
+                                       CBrowseFolder folderBrowser;\r
+                                       folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO)));\r
+                                       bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK);\r
+                               }\r
+                               if (bGotSavePath)\r
+                               {\r
+                                       CGitProgressDlg dlg;\r
+                                       dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
+                                       dlg.SetPathList(CTGitPathList(CTGitPath(path)));\r
+                                       dlg.SetUrl(pathURL);\r
+                                       dlg.SetSecondUrl(pathURL);\r
+                                       revisionRanges.AdjustForMerge(false);\r
+                                       dlg.SetRevisionRanges(revisionRanges);\r
+                                       dlg.SetPegRevision(m_LogRevision);\r
+                                       dlg.DoModal();\r
+                               }\r
+                       }\r
+                       break;\r
+               case ID_REVERTTOREV:\r
+                       {\r
+                               // we need an URL to complete this command, so error out if we can't get an URL\r
+                               if (pathURL.IsEmpty())\r
+                               {\r
+                                       CString strMessage;\r
+                                       strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
+                                       CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
+                                       TRACE(_T("could not retrieve the URL of the folder!\n"));\r
+                                       break;          //exit\r
+                               }\r
+\r
+                               CString msg;\r
+                               msg.Format(IDS_LOG_REVERTTOREV_CONFIRM, m_path.GetWinPath());\r
+                               if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
+                               {\r
+                                       CGitProgressDlg dlg;\r
+                                       dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
+                                       dlg.SetPathList(CTGitPathList(m_path));\r
+                                       dlg.SetUrl(pathURL);\r
+                                       dlg.SetSecondUrl(pathURL);\r
+                                       GitRevRangeArray revarray;\r
+                                       revarray.AddRevRange(GitRev::REV_HEAD, revSelected);\r
+                                       dlg.SetRevisionRanges(revarray);\r
+                                       dlg.SetPegRevision(m_LogRevision);\r
+                                       dlg.DoModal();\r
+                               }\r
+                       }\r
+                       break;\r
+               case ID_COPY:\r
+                       {\r
+                               // we need an URL to complete this command, so error out if we can't get an URL\r
+                               if (pathURL.IsEmpty())\r
+                               {\r
+                                       CString strMessage;\r
+                                       strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
+                                       CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
+                                       TRACE(_T("could not retrieve the URL of the folder!\n"));\r
+                                       break;          //exit\r
+                               }\r
+\r
+                               CCopyDlg dlg;\r
+                               dlg.m_URL = pathURL;\r
+                               dlg.m_path = m_path;\r
+                               dlg.m_CopyRev = revSelected;\r
+                               if (dlg.DoModal() == IDOK)\r
+                               {\r
+                                       // should we show a progress dialog here? Copies are done really fast\r
+                                       // and without much network traffic.\r
+                                       if (!Copy(CTGitPathList(CTGitPath(pathURL)), CTGitPath(dlg.m_URL), dlg.m_CopyRev, dlg.m_CopyRev, dlg.m_sLogMessage))\r
+                                               CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
+                                       else\r
+                                               CMessageBox::Show(this->m_hWnd, IDS_LOG_COPY_SUCCESS, IDS_APPNAME, MB_ICONINFORMATION);\r
+                               }\r
+                       } \r
+                       break;\r
+               case ID_COMPARE:\r
+                       {\r
+                               //user clicked on the menu item "compare with working copy"\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, m_hWnd, true);\r
+                                       diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowCompare(m_path, GitRev::REV_WC, m_path, revSelected);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+                       }\r
+                       break;\r
+               case ID_COMPARETWO:\r
+                       {\r
+                               GitRev r1 = revSelected;\r
+                               GitRev r2 = revSelected2;\r
+                               if (GetSelectedCount() > 2)\r
+                               {\r
+                                       r1 = revHighest;\r
+                                       r2 = revLowest;\r
+                               }\r
+                               //user clicked on the menu item "compare revisions"\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, m_hWnd, true);\r
+                                       diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowCompare(CTGitPath(pathURL), r2, CTGitPath(pathURL), r1);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), r2, CTGitPath(pathURL), r1, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+                       }\r
+                       break;\r
+               case ID_COMPAREWITHPREVIOUS:\r
+                       {\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, m_hWnd, true);\r
+                                       diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+                       }\r
+                       break;\r
+               case ID_BLAMECOMPARE:\r
+                       {\r
+                               //user clicked on the menu item "compare with working copy"\r
+                               //now first get the revision which is selected\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, this->m_hWnd, true);\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowCompare(m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), false, true);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true);\r
+                       }\r
+                       break;\r
+               case ID_BLAMETWO:\r
+                       {\r
+                               //user clicked on the menu item "compare and blame revisions"\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, this->m_hWnd, true);\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowCompare(CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
+                       }\r
+                       break;\r
+               case ID_BLAMEWITHPREVIOUS:\r
+                       {\r
+                               //user clicked on the menu item "Compare and Blame with previous revision"\r
+                               if (PromptShown())\r
+                               {\r
+                                       GitDiff diff(this, this->m_hWnd, true);\r
+                                       diff.SetHEADPeg(m_LogRevision);\r
+                                       diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
+                               }\r
+                               else\r
+                                       CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
+                       }\r
+                       break;\r
+               case ID_SAVEAS:\r
+                       {\r
+                               //now first get the revision which is selected\r
+                               CString revFilename;\r
+                               if (m_hasWC)\r
+                               {\r
+                                       CString strWinPath = m_path.GetWinPathString();\r
+                                       int rfind = strWinPath.ReverseFind('.');\r
+                                       if (rfind > 0)\r
+                                               revFilename.Format(_T("%s-%ld%s"), (LPCTSTR)strWinPath.Left(rfind), (LONG)revSelected, (LPCTSTR)strWinPath.Mid(rfind));\r
+                                       else\r
+                                               revFilename.Format(_T("%s-%ld"), (LPCTSTR)strWinPath, revSelected);\r
+                               }\r
+                               if (CAppUtils::FileOpenSave(revFilename, NULL, IDS_LOG_POPUP_SAVE, IDS_COMMONFILEFILTER, false, m_hWnd))\r
+                               {\r
+                                       CTGitPath tempfile;\r
+                                       tempfile.SetFromWin(revFilename);\r
+                                       CProgressDlg progDlg;\r
+                                       progDlg.SetTitle(IDS_APPNAME);\r
+                                       progDlg.SetAnimation(IDR_DOWNLOAD);\r
+                                       CString sInfoLine;\r
+                                       sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
+                                       progDlg.SetLine(1, sInfoLine, true);\r
+                                       SetAndClearProgressInfo(&progDlg);\r
+                                       progDlg.ShowModeless(m_hWnd);\r
+                                       if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
+                                       {\r
+                                               // try again with another peg revision\r
+                                               if (!Cat(m_path, revSelected, revSelected, tempfile))\r
+                                               {\r
+                                                       progDlg.Stop();\r
+                                                       SetAndClearProgressInfo((HWND)NULL);\r
+                                                       CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
+                                                       EnableOKButton();\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                                       progDlg.Stop();\r
+                                       SetAndClearProgressInfo((HWND)NULL);\r
+                               }\r
+                       }\r
+                       break;\r
+               case ID_OPENWITH:\r
+                       bOpenWith = true;\r
+               case ID_OPEN:\r
+                       {\r
+                               CProgressDlg progDlg;\r
+                               progDlg.SetTitle(IDS_APPNAME);\r
+                               progDlg.SetAnimation(IDR_DOWNLOAD);\r
+                               CString sInfoLine;\r
+                               sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
+                               progDlg.SetLine(1, sInfoLine, true);\r
+                               SetAndClearProgressInfo(&progDlg);\r
+                               progDlg.ShowModeless(m_hWnd);\r
+                               CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path, revSelected);\r
+                               bool bSuccess = true;\r
+                               if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
+                               {\r
+                                       bSuccess = false;\r
+                                       // try again, but with the selected revision as the peg revision\r
+                                       if (!Cat(m_path, revSelected, revSelected, tempfile))\r
+                                       {\r
+                                               progDlg.Stop();\r
+                                               SetAndClearProgressInfo((HWND)NULL);\r
+                                               CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
+                                               EnableOKButton();\r
+                                               break;\r
+                                       }\r
+                                       bSuccess = true;\r
+                               }\r
+                               if (bSuccess)\r
+                               {\r
+                                       progDlg.Stop();\r
+                                       SetAndClearProgressInfo((HWND)NULL);\r
+                                       SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
+                                       int ret = 0;\r
+                                       if (!bOpenWith)\r
+                                               ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
+                                       if ((ret <= HINSTANCE_ERROR)||bOpenWith)\r
+                                       {\r
+                                               CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
+                                               cmd += tempfile.GetWinPathString() + _T(" ");\r
+                                               CAppUtils::LaunchApplication(cmd, NULL, false);\r
+                                       }\r
+                               }\r
+                       }\r
+                       break;\r
+               case ID_BLAME:\r
+                       {\r
+                               CBlameDlg dlg;\r
+                               dlg.EndRev = revSelected;\r
+                               if (dlg.DoModal() == IDOK)\r
+                               {\r
+                                       CBlame blame;\r
+                                       CString tempfile;\r
+                                       CString logfile;\r
+                                       tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE);\r
+                                       if (!tempfile.IsEmpty())\r
+                                       {\r
+                                               if (dlg.m_bTextView)\r
+                                               {\r
+                                                       //open the default text editor for the result file\r
+                                                       CAppUtils::StartTextViewer(tempfile);\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" ");\r
+                                                       if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams))\r
+                                                       {\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
+                                       }\r
+                               }\r
+                       }\r
+                       break;\r
+               case ID_UPDATE:\r
+                       {\r
+                               CString sCmd;\r
+                               CString url = _T("tgit:")+pathURL;\r
+                               sCmd.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),\r
+                                       (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
+                                       (LPCTSTR)m_path.GetWinPath(), (LONG)revSelected);\r
+                               CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+                       }\r
+                       break;\r
+               case ID_FINDENTRY:\r
+                       {\r
+                               m_nSearchIndex = GetSelectionMark();\r
+                               if (m_nSearchIndex < 0)\r
+                                       m_nSearchIndex = 0;\r
+                               if (m_pFindDialog)\r
+                               {\r
+                                       break;\r
+                               }\r
+                               else\r
+                               {\r
+                                       m_pFindDialog = new CFindReplaceDialog();\r
+                                       m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this);                                                                        \r
+                               }\r
+                       }\r
+                       break;\r
+               case ID_REPOBROWSE:\r
+                       {\r
+                               CString sCmd;\r
+                               sCmd.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),\r
+                                       (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
+                                       (LPCTSTR)pathURL, (LPCTSTR)revSelected.ToString());\r
+\r
+                               CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+                       }\r
+                       break;\r
+               case ID_EDITLOG:\r
+                       {\r
+                               EditLogMessage(selIndex);\r
+                       }\r
+                       break;\r
+               case ID_EDITAUTHOR:\r
+                       {\r
+                               EditAuthor(selEntries);\r
+                       }\r
+                       break;\r
+               case ID_REVPROPS:\r
+                       {\r
+                               CEditPropertiesDlg dlg;\r
+                               dlg.SetProjectProperties(&m_ProjectProperties);\r
+                               CTGitPathList escapedlist;\r
+                               dlg.SetPathList(CTGitPathList(CTGitPath(pathURL)));\r
+                               dlg.SetRevision(revSelected);\r
+                               dlg.RevProps(true);\r
+                               dlg.DoModal();\r
+                       }\r
+                       break;\r
+               case ID_COPYCLIPBOARD:\r
+                       {\r
+                               CopySelectionToClipBoard();\r
+                       }\r
+                       break;\r
+               case ID_EXPORT:\r
+                       {\r
+                               CString sCmd;\r
+                               sCmd.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),\r
+                                       (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
+                                       (LPCTSTR)pathURL, (LONG)revSelected);\r
+                               CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+                       }\r
+                       break;\r
+               case ID_CHECKOUT:\r
+                       {\r
+                               CString sCmd;\r
+                               CString url = _T("tgit:")+pathURL;\r
+                               sCmd.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),\r
+                                       (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
+                                       (LPCTSTR)url, (LONG)revSelected);\r
+                               CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+                       }\r
+                       break;\r
+               case ID_VIEWREV:\r
+                       {\r
+                               CString url = m_ProjectProperties.sWebViewerRev;\r
+                               url = GetAbsoluteUrlFromRelativeUrl(url);\r
+                               url.Replace(_T("%REVISION%"), revSelected.ToString());\r
+                               if (!url.IsEmpty())\r
+                                       ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
+                       }\r
+                       break;\r
+               case ID_VIEWPATHREV:\r
+                       {\r
+                               CString relurl = pathURL;\r
+                               CString sRoot = GetRepositoryRoot(CTGitPath(relurl));\r
+                               relurl = relurl.Mid(sRoot.GetLength());\r
+                               CString url = m_ProjectProperties.sWebViewerPathRev;\r
+                               url = GetAbsoluteUrlFromRelativeUrl(url);\r
+                               url.Replace(_T("%REVISION%"), revSelected.ToString());\r
+                               url.Replace(_T("%PATH%"), relurl);\r
+                               if (!url.IsEmpty())\r
+                                       ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
+                       }\r
+                       break;\r
+#endif\r
+               default:\r
+                       break;\r
+               } // switch (cmd)\r
+               theApp.DoWaitCursor(-1);\r
+//             EnableOKButton();\r
+       } // if (popup.CreatePopupMenu())\r
+\r
+}\r
+\r
+bool CGitLogList::IsSelectionContinuous()\r
+{\r
+       if ( GetSelectedCount()==1 )\r
+       {\r
+               // if only one revision is selected, the selection is of course\r
+               // continuous\r
+               return true;\r
+       }\r
+\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       bool bContinuous = (m_arShownList.GetCount() == (INT_PTR)m_logEntries.size());\r
+       if (bContinuous)\r
+       {\r
+               int itemindex = GetNextSelectedItem(pos);\r
+               while (pos)\r
+               {\r
+                       int nextindex = GetNextSelectedItem(pos);\r
+                       if (nextindex - itemindex > 1)\r
+                       {\r
+                               bContinuous = false;\r
+                               break;\r
+                       }\r
+                       itemindex = nextindex;\r
+               }\r
+       }\r
+       return bContinuous;\r
+}\r
+\r
+void CGitLogList::CopySelectionToClipBoard()\r
+{\r
+#if 0\r
+       CString sClipdata;\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       if (pos != NULL)\r
+       {\r
+               CString sRev;\r
+               sRev.LoadString(IDS_LOG_REVISION);\r
+               CString sAuthor;\r
+               sAuthor.LoadString(IDS_LOG_AUTHOR);\r
+               CString sDate;\r
+               sDate.LoadString(IDS_LOG_DATE);\r
+               CString sMessage;\r
+               sMessage.LoadString(IDS_LOG_MESSAGE);\r
+               while (pos)\r
+               {\r
+                       CString sLogCopyText;\r
+                       CString sPaths;\r
+                       PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(GetNextSelectedItem(pos)));\r
+                       LogChangedPathArray * cpatharray = pLogEntry->pArChangedPaths;\r
+                       for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount(); ++cpPathIndex)\r
+                       {\r
+                               LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
+                               sPaths += cpath->GetAction() + _T(" : ") + cpath->sPath;\r
+                               if (cpath->sCopyFromPath.IsEmpty())\r
+                                       sPaths += _T("\r\n");\r
+                               else\r
+                               {\r
+                                       CString sCopyFrom;\r
+                                       sCopyFrom.Format(_T(" (%s: %s, %s, %ld)\r\n"), CString(MAKEINTRESOURCE(IDS_LOG_COPYFROM)), \r
+                                               (LPCTSTR)cpath->sCopyFromPath, \r
+                                               (LPCTSTR)CString(MAKEINTRESOURCE(IDS_LOG_REVISION)), \r
+                                               (LPCTSTR)cpath->lCopyFromRev);\r
+                                       sPaths += sCopyFrom;\r
+                               }\r
+                       }\r
+                       sPaths.Trim();\r
+                       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
+                               (LPCTSTR)sRev, pLogEntry->Rev,\r
+                               (LPCTSTR)sAuthor, (LPCTSTR)pLogEntry->sAuthor,\r
+                               (LPCTSTR)sDate, (LPCTSTR)pLogEntry->sDate,\r
+                               (LPCTSTR)sMessage, (LPCTSTR)pLogEntry->sMessage,\r
+                               (LPCTSTR)sPaths);\r
+                       sClipdata +=  sLogCopyText;\r
+               }\r
+               CStringUtils::WriteAsciiStringToClipboard(sClipdata, GetSafeHwnd());\r
+       }\r
+#endif\r
+}\r
+\r
+void CGitLogList::DiffSelectedRevWithPrevious()\r
+{\r
+#if 0\r
+       if (m_bThreadRunning)\r
+               return;\r
+       UpdateLogInfoLabel();\r
+       int selIndex = m_LogList.GetSelectionMark();\r
+       if (selIndex < 0)\r
+               return;\r
+       int selCount = m_LogList.GetSelectedCount();\r
+       if (selCount != 1)\r
+               return;\r
+\r
+       // Find selected entry in the log list\r
+       POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
+       PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
+       long rev1 = pLogEntry->Rev;\r
+       long rev2 = rev1-1;\r
+       CTGitPath path = m_path;\r
+\r
+       // See how many files under the relative root were changed in selected revision\r
+       int nChanged = 0;\r
+       LogChangedPath * changed = NULL;\r
+       for (INT_PTR c = 0; c < pLogEntry->pArChangedPaths->GetCount(); ++c)\r
+       {\r
+               LogChangedPath * cpath = pLogEntry->pArChangedPaths->GetAt(c);\r
+               if (cpath  &&  cpath -> sPath.Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)==0)\r
+               {\r
+                       ++nChanged;\r
+                       changed = cpath;\r
+               }\r
+       }\r
+\r
+       if (m_path.IsDirectory() && nChanged == 1) \r
+       {\r
+               // We're looking at the log for a directory and only one file under dir was changed in the revision\r
+               // Do diff on that file instead of whole directory\r
+               path.AppendPathString(changed->sPath.Mid(m_sRelativeRoot.GetLength()));\r
+       } \r
+\r
+       m_bCancelled = FALSE;\r
+       DialogEnableWindow(IDOK, FALSE);\r
+       SetPromptApp(&theApp);\r
+       theApp.DoWaitCursor(1);\r
+\r
+       if (PromptShown())\r
+       {\r
+               GitDiff diff(this, m_hWnd, true);\r
+               diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+               diff.SetHEADPeg(m_LogRevision);\r
+               diff.ShowCompare(path, rev2, path, rev1);\r
+       }\r
+       else\r
+       {\r
+               CAppUtils::StartShowCompare(m_hWnd, path, rev2, path, rev1, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+       }\r
+\r
+       theApp.DoWaitCursor(-1);\r
+       EnableOKButton();\r
+#endif\r
+}\r
+\r
+void CGitLogList::OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMLVFINDITEM pFindInfo = reinterpret_cast<LPNMLVFINDITEM>(pNMHDR);\r
+       *pResult = -1;\r
+       \r
+       if (pFindInfo->lvfi.flags & LVFI_PARAM)\r
+               return; \r
+       if ((pFindInfo->iStart < 0)||(pFindInfo->iStart >= m_arShownList.GetCount()))\r
+               return;\r
+       if (pFindInfo->lvfi.psz == 0)\r
+               return;\r
+#if 0\r
+       CString sCmp = pFindInfo->lvfi.psz;\r
+       CString sRev;   \r
+       for (int i=pFindInfo->iStart; i<m_arShownList.GetCount(); ++i)\r
+       {\r
+               GitRev * pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(i));\r
+               sRev.Format(_T("%ld"), pLogEntry->Rev);\r
+               if (pFindInfo->lvfi.flags & LVFI_PARTIAL)\r
+               {\r
+                       if (sCmp.Compare(sRev.Left(sCmp.GetLength()))==0)\r
+                       {\r
+                               *pResult = i;\r
+                               return;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (sCmp.Compare(sRev)==0)\r
+                       {\r
+                               *pResult = i;\r
+                               return;\r
+                       }\r
+               }\r
+       }\r
+       if (pFindInfo->lvfi.flags & LVFI_WRAP)\r
+       {\r
+               for (int i=0; i<pFindInfo->iStart; ++i)\r
+               {\r
+                       PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(i));\r
+                       sRev.Format(_T("%ld"), pLogEntry->Rev);\r
+                       if (pFindInfo->lvfi.flags & LVFI_PARTIAL)\r
+                       {\r
+                               if (sCmp.Compare(sRev.Left(sCmp.GetLength()))==0)\r
+                               {\r
+                                       *pResult = i;\r
+                                       return;\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               if (sCmp.Compare(sRev)==0)\r
+                               {\r
+                                       *pResult = i;\r
+                                       return;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+#endif\r
+       *pResult = -1;\r
+}\r
+\r
+int CGitLogList::FillGitLog()\r
+{\r
+       ClearText();\r
+\r
+       this->m_logEntries.ClearAll();\r
+       this->m_logEntries.ParserFromLog();\r
+       SetItemCountEx(this->m_logEntries.size());\r
+\r
+       this->m_arShownList.RemoveAll();\r
+\r
+       for(int i=0;i<m_logEntries.size();i++)\r
+               this->m_arShownList.Add(&m_logEntries[i]);\r
+\r
+       return 0;\r
+}\r
+\r
+BOOL CGitLogList::PreTranslateMessage(MSG* pMsg)\r
+{\r
+       // Skip Ctrl-C when copying text out of the log message or search filter\r
+       BOOL bSkipAccelerator = ( pMsg->message == WM_KEYDOWN && pMsg->wParam=='C' && (GetFocus()==GetDlgItem(IDC_MSGVIEW) || GetFocus()==GetDlgItem(IDC_SEARCHEDIT) ) && GetKeyState(VK_CONTROL)&0x8000 );\r
+       if (pMsg->message == WM_KEYDOWN && pMsg->wParam=='\r')\r
+       {\r
+               //if (GetFocus()==GetDlgItem(IDC_LOGLIST))\r
+               {\r
+                       if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
+                       {\r
+                               DiffSelectedRevWithPrevious();\r
+                               return TRUE;\r
+                       }\r
+               }\r
+#if 0\r
+               if (GetFocus()==GetDlgItem(IDC_LOGMSG))\r
+               {\r
+                       DiffSelectedFile();\r
+                       return TRUE;\r
+               }\r
+#endif\r
+       }\r
+\r
+#if 0\r
+       if (m_hAccel && !bSkipAccelerator)\r
+       {\r
+               int ret = TranslateAccelerator(m_hWnd, m_hAccel, pMsg);\r
+               if (ret)\r
+                       return TRUE;\r
+       }\r
+       \r
+#endif\r
+       //m_tooltips.RelayEvent(pMsg);\r
+       return __super::PreTranslateMessage(pMsg);\r
+}\r
+\r
+void CGitLogList::OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult)\r
+{\r
+       // a double click on an entry in the revision list has happened\r
+       *pResult = 0;\r
+\r
+  if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
+         DiffSelectedRevWithPrevious();\r
+}
\ No newline at end of file
diff --git a/src/TortoiseProc/GitLogList.h b/src/TortoiseProc/GitLogList.h
new file mode 100644 (file)
index 0000000..b8c97fc
--- /dev/null
@@ -0,0 +1,144 @@
+#pragma once\r
+\r
+#include "HintListCtrl.h"\r
+#include "XPTheme.h"\r
+#include "resource.h"\r
+#include "Git.h"\r
+#include "ProjectProperties.h"\r
+#include "StandAloneDlg.h"\r
+#include "TGitPath.h"\r
+#include "registry.h"\r
+#include "SplitterControl.h"\r
+#include "Colors.h"\r
+#include "MenuButton.h"\r
+#include "LogDlgHelper.h"\r
+#include "FilterEdit.h"\r
+#include "GitRev.h"\r
+#include "Tooltip.h"\r
+#include "HintListCtrl.h"\r
+#include "GitLogList.h"\r
+\r
+#include <regex>\r
+// CGitLogList\r
+#if (NTDDI_VERSION < NTDDI_LONGHORN)\r
+\r
+enum LISTITEMSTATES_MINE {\r
+       LISS_NORMAL = 1,\r
+       LISS_HOT = 2,\r
+       LISS_SELECTED = 3,\r
+       LISS_DISABLED = 4,\r
+       LISS_SELECTEDNOTFOCUS = 5,\r
+       LISS_HOTSELECTED = 6,\r
+};\r
+\r
+#define MCS_NOTRAILINGDATES  0x0040\r
+#define MCS_SHORTDAYSOFWEEK  0x0080\r
+#define MCS_NOSELCHANGEONNAV 0x0100\r
+\r
+#define DTM_SETMCSTYLE    (DTM_FIRST + 11)\r
+\r
+#endif\r
+\r
+#define ICONITEMBORDER 5\r
+\r
+class CGitLogList : public CHintListCtrl\r
+{\r
+       DECLARE_DYNAMIC(CGitLogList)\r
+\r
+public:\r
+       CGitLogList();\r
+       virtual ~CGitLogList();\r
+       BOOL m_bNoDispUpdates;\r
+       BOOL m_bStrictStopped;\r
+       BOOL m_bShowBugtraqColumn;\r
+       BOOL m_bSearchIndex;\r
+       BOOL m_bCancelled;\r
+       bool                            m_hasWC;\r
+       GitRev                          m_wcRev;\r
+\r
+       enum\r
+       {\r
+               LOGLIST_GRAPH,\r
+               LOGLIST_ACTION,\r
+               LOGLIST_MESSAGE,\r
+               LOGLIST_AUTHOR,\r
+               LOGLIST_DATE,\r
+               LOGLIST_BUG,\r
+               LOGLIST_MESSAGE_MAX=250\r
+       };\r
+\r
+       enum \r
+       {\r
+       // needs to start with 1, since 0 is the return value if *nothing* is clicked on in the context menu\r
+       ID_COMPARE = 1,\r
+       ID_SAVEAS,\r
+       ID_COMPARETWO,\r
+       ID_UPDATE,\r
+       ID_COPY,\r
+       ID_REVERTREV,\r
+       ID_MERGEREV,\r
+       ID_GNUDIFF1,\r
+       ID_GNUDIFF2,\r
+       ID_FINDENTRY,\r
+       ID_OPEN,\r
+       ID_BLAME,\r
+       ID_REPOBROWSE,\r
+       ID_LOG,\r
+       ID_POPPROPS,\r
+       ID_EDITAUTHOR,\r
+       ID_EDITLOG,\r
+       ID_DIFF,\r
+       ID_OPENWITH,\r
+       ID_COPYCLIPBOARD,\r
+       ID_CHECKOUT,\r
+       ID_REVERTTOREV,\r
+       ID_BLAMECOMPARE,\r
+       ID_BLAMETWO,\r
+       ID_BLAMEDIFF,\r
+       ID_VIEWREV,\r
+       ID_VIEWPATHREV,\r
+       ID_EXPORT,\r
+       ID_COMPAREWITHPREVIOUS,\r
+       ID_BLAMEWITHPREVIOUS,\r
+       ID_GETMERGELOGS,\r
+       ID_REVPROPS\r
+       };\r
+       void InsertGitColumn();\r
+       void ResizeAllListCtrlCols();\r
+       void CopySelectionToClipBoard();\r
+       void DiffSelectedRevWithPrevious();\r
+       bool IsSelectionContinuous();\r
+       int  FillGitLog();\r
+       inline int ShownCountWithStopped() const { return (int)m_arShownList.GetCount() + (m_bStrictStopped ? 1 : 0); }\r
+\r
+protected:\r
+       DECLARE_MESSAGE_MAP()\r
+       afx_msg void OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);\r
+       afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);\r
+       void OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult);\r
+       afx_msg void OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult);\r
+       virtual BOOL PreTranslateMessage(MSG* pMsg);\r
+\r
+       CPtrArray                       m_arShownList;\r
+       CXPTheme                        m_Theme;\r
+       BOOL                            m_bVista;\r
+       BOOL                            m_bThreadRunning;\r
+       \r
+       HICON                           m_hModifiedIcon;\r
+       HICON                           m_hReplacedIcon;\r
+       HICON                           m_hAddedIcon;\r
+       HICON                           m_hDeletedIcon;\r
+\r
+       HFONT                           m_boldFont;\r
+\r
+       CRegDWORD                       m_regMaxBugIDColWidth;\r
+\r
+\r
+       int                                     m_nSearchIndex;\r
+       CLogDataVector          m_logEntries;\r
+\r
+};\r
+\r
+\r
index 9cf6a02..9552a37 100644 (file)
@@ -68,7 +68,7 @@ CLogDlg::CLogDlg(CWnd* pParent /*=NULL*/)
        , m_bShowedAll(false)\r
        , m_bSelect(false)\r
        , m_regLastStrict(_T("Software\\TortoiseGit\\LastLogStrict"), FALSE)\r
-       , m_regMaxBugIDColWidth(_T("Software\\TortoiseGit\\MaxBugIDColWidth"), 200)\r
+       \r
        , m_bSelectionMustBeContinuous(false)\r
        , m_bShowBugtraqColumn(false)\r
        , m_lowestRev(_T(""))\r
@@ -88,29 +88,21 @@ CLogDlg::CLogDlg(CWnd* pParent /*=NULL*/)
        , m_bVista(false)\r
 {\r
        m_bFilterWithRegex = !!CRegDWORD(_T("Software\\TortoiseGit\\UseRegexFilter"), TRUE);\r
-       // use the default GUI font, create a copy of it and\r
-       // change the copy to BOLD (leave the rest of the font\r
-       // the same)\r
-       HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);\r
-       LOGFONT lf = {0};\r
-       GetObject(hFont, sizeof(LOGFONT), &lf);\r
-       lf.lfWeight = FW_BOLD;\r
-       m_boldFont = CreateFontIndirect(&lf);\r
+       \r
 }\r
 \r
 CLogDlg::~CLogDlg()\r
 {\r
        InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
     m_CurrentFilteredChangedArray.RemoveAll();\r
-       m_logEntries.ClearAll();\r
+       \r
 \r
        if ( m_pStoreSelection )\r
        {\r
                delete m_pStoreSelection;\r
                m_pStoreSelection = NULL;\r
        }\r
-       if (m_boldFont)\r
-               DeleteObject(m_boldFont);\r
+       \r
 }\r
 \r
 void CLogDlg::DoDataExchange(CDataExchange* pDX)\r
@@ -236,54 +228,10 @@ BOOL CLogDlg::OnInitDialog()
 \r
        // set up the columns\r
        m_LogList.DeleteAllItems();\r
-#if 0\r
-       int c = ((CHeaderCtrl*)(m_LogList.GetDlgItem(0)))->GetItemCount()-1;\r
-       \r
-       while (c>=0)\r
-               m_LogList.DeleteColumn(c--);\r
-       temp.LoadString(IDS_LOG_GRAPH);\r
-\r
-       m_LogList.InsertColumn(this->LOGLIST_GRAPH, temp);\r
-       \r
-#if 0  \r
-       // make the revision column right aligned\r
-       LVCOLUMN Column;\r
-       Column.mask = LVCF_FMT;\r
-       Column.fmt = LVCFMT_RIGHT;\r
-       m_LogList.SetColumn(0, &Column); \r
-#endif \r
-//     CString log;\r
-//     g_Git.GetLog(log);\r
-\r
-       temp.LoadString(IDS_LOG_ACTIONS);\r
-       m_LogList.InsertColumn(this->LOGLIST_ACTION, temp);\r
-       \r
-       temp.LoadString(IDS_LOG_MESSAGE);\r
-       m_LogList.InsertColumn(this->LOGLIST_MESSAGE, temp);\r
-       \r
-       temp.LoadString(IDS_LOG_AUTHOR);\r
-       m_LogList.InsertColumn(this->LOGLIST_AUTHOR, temp);\r
-       \r
-       temp.LoadString(IDS_LOG_DATE);\r
-       m_LogList.InsertColumn(this->LOGLIST_DATE, temp);\r
-       \r
-\r
-       if (m_bShowBugtraqColumn)\r
-       {\r
-               temp = m_ProjectProperties.sLabel;\r
-               if (temp.IsEmpty())\r
-                       temp.LoadString(IDS_LOG_BUGIDS);\r
-               m_LogList.InsertColumn(this->LOGLIST_BUG, temp);\r
 \r
-       }\r
-       \r
-       m_LogList.SetRedraw(false);\r
-       ResizeAllListCtrlCols();\r
-       m_LogList.SetRedraw(true);\r
-#endif\r
        m_ChangedFileListCtrl.SetExtendedStyle ( LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER );\r
        m_ChangedFileListCtrl.DeleteAllItems();\r
-       c = ((CHeaderCtrl*)(m_ChangedFileListCtrl.GetDlgItem(0)))->GetItemCount()-1;\r
+       int c = ((CHeaderCtrl*)(m_ChangedFileListCtrl.GetDlgItem(0)))->GetItemCount()-1;\r
        while (c>=0)\r
                m_ChangedFileListCtrl.DeleteColumn(c--);\r
        temp.LoadString(IDS_PROGRS_ACTION);\r
@@ -404,7 +352,7 @@ BOOL CLogDlg::OnInitDialog()
        {\r
                // the dialog is used to select revisions\r
                if (m_bSelectionMustBeContinuous)\r
-                       DialogEnableWindow(IDOK, (m_LogList.GetSelectedCount()!=0)&&(IsSelectionContinuous()));\r
+                       DialogEnableWindow(IDOK, (m_LogList.GetSelectedCount()!=0)&&(m_LogList.IsSelectionContinuous()));\r
                else\r
                        DialogEnableWindow(IDOK, m_LogList.GetSelectedCount()!=0);\r
        }\r
@@ -486,7 +434,7 @@ void CLogDlg::EnableOKButton()
        {\r
                // the dialog is used to select revisions\r
                if (m_bSelectionMustBeContinuous)\r
-                       DialogEnableWindow(IDOK, (m_LogList.GetSelectedCount()!=0)&&(IsSelectionContinuous()));\r
+                       DialogEnableWindow(IDOK, (m_LogList.GetSelectedCount()!=0)&&(m_LogList.IsSelectionContinuous()));\r
                else\r
                        DialogEnableWindow(IDOK, m_LogList.GetSelectedCount()!=0);\r
        }\r
@@ -1176,16 +1124,7 @@ UINT CLogDlg::LogThread()
        m_DateTo.SetTime(&m_timTo);\r
 #endif\r
        DialogEnableWindow(IDC_GETALL, TRUE);\r
-       m_LogList.ClearText();\r
-\r
-       this->m_logEntries.ClearAll();\r
-       this->m_logEntries.ParserFromLog();\r
-       m_LogList.SetItemCountEx(this->m_logEntries.size());\r
-\r
-       this->m_arShownList.RemoveAll();\r
-\r
-       for(int i=0;i<m_logEntries.size();i++)\r
-               this->m_arShownList.Add(&m_logEntries[i]);\r
+       m_LogList.FillGitLog();\r
        \r
 #if 0  \r
        if (!m_bShowedAll)\r
@@ -1206,7 +1145,7 @@ UINT CLogDlg::LogThread()
        InterlockedExchange(&m_bThreadRunning, FALSE);\r
        m_LogList.RedrawItems(0, m_arShownList.GetCount());\r
        m_LogList.SetRedraw(false);\r
-       ResizeAllListCtrlCols();\r
+       m_LogList.ResizeAllListCtrlCols();\r
        m_LogList.SetRedraw(true);\r
        if ( m_pStoreSelection )\r
        {\r
@@ -1327,7 +1266,7 @@ void CLogDlg::OnContextMenu(CWnd* pWnd, CPoint point)
        int selCount = m_LogList.GetSelectedCount();\r
        if (pWnd == &m_LogList)\r
        {\r
-               ShowContextMenuForRevisions(pWnd, point);\r
+               //ShowContextMenuForRevisions(pWnd, point);\r
        }\r
        else if (pWnd == &m_ChangedFileListCtrl)\r
        {\r
@@ -1360,7 +1299,7 @@ void CLogDlg::OnContextMenu(CWnd* pWnd, CPoint point)
                        {\r
                                popup.AppendMenu(MF_SEPARATOR);\r
                                sMenuItemText.LoadString(IDS_LOG_POPUP_EDITLOG);\r
-                               popup.AppendMenu(MF_STRING | MF_ENABLED, ID_EDITAUTHOR, sMenuItemText);\r
+                               popup.AppendMenu(MF_STRING | MF_ENABLED, CGitLogList::ID_EDITAUTHOR, sMenuItemText);\r
                        }\r
 \r
                        int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
@@ -1372,7 +1311,7 @@ void CLogDlg::OnContextMenu(CWnd* pWnd, CPoint point)
                        case WM_COPY:\r
                                ::SendMessage(GetDlgItem(IDC_MSGVIEW)->GetSafeHwnd(), cmd, 0, -1);\r
                                break;\r
-                       case ID_EDITAUTHOR:\r
+                       case CGitLogList::ID_EDITAUTHOR:\r
                                EditLogMessage(selIndex);\r
                                break;\r
                        }\r
@@ -2086,7 +2025,7 @@ void CLogDlg::EditLogMessage(int index)
        EnableOKButton();\r
 #endif\r
 }\r
-\r
+#if 0\r
 BOOL CLogDlg::PreTranslateMessage(MSG* pMsg)\r
 {\r
        // Skip Ctrl-C when copying text out of the log message or search filter\r
@@ -2117,6 +2056,7 @@ BOOL CLogDlg::PreTranslateMessage(MSG* pMsg)
        m_tooltips.RelayEvent(pMsg);\r
        return __super::PreTranslateMessage(pMsg);\r
 }\r
+#endif\r
 \r
 BOOL CLogDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)\r
 {\r
@@ -3115,10 +3055,10 @@ void CLogDlg::OnTimer(UINT_PTR nIDEvent)
 \r
 \r
                m_LogList.DeleteAllItems();\r
-               m_LogList.SetItemCountEx(ShownCountWithStopped());\r
-               m_LogList.RedrawItems(0, ShownCountWithStopped());\r
+               m_LogList.SetItemCountEx(m_LogList.ShownCountWithStopped());\r
+               m_LogList.RedrawItems(0, m_LogList.ShownCountWithStopped());\r
                m_LogList.SetRedraw(false);\r
-               ResizeAllListCtrlCols();\r
+               m_LogList.ResizeAllListCtrlCols();\r
                m_LogList.SetRedraw(true);\r
                m_LogList.Invalidate();\r
                if ( m_LogList.GetItemCount()==1 )\r
@@ -3664,40 +3604,40 @@ void CLogDlg::ShowContextMenuForChangedpaths(CWnd* /*pWnd*/, CPoint point)
                {\r
 //                     if ((!bOneRev)||(IsDiffPossible(changedlogpaths[0], rev1)))\r
                        {\r
-                               popup.AppendMenuIcon(ID_DIFF, IDS_LOG_POPUP_DIFF, IDI_DIFF);\r
-                               popup.AppendMenuIcon(ID_BLAMEDIFF, IDS_LOG_POPUP_BLAMEDIFF, IDI_BLAME);\r
-                               popup.SetDefaultItem(ID_DIFF, FALSE);\r
-                               popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
+                               popup.AppendMenuIcon(CGitLogList::ID_DIFF, IDS_LOG_POPUP_DIFF, IDI_DIFF);\r
+                               popup.AppendMenuIcon(CGitLogList::ID_BLAMEDIFF, IDS_LOG_POPUP_BLAMEDIFF, IDI_BLAME);\r
+                               popup.SetDefaultItem(CGitLogList::ID_DIFF, FALSE);\r
+                               popup.AppendMenuIcon(CGitLogList::ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
                                bEntryAdded = true;\r
                        }\r
 //                     if (rev2 == rev1-1)\r
                        {\r
                                if (bEntryAdded)\r
                                        popup.AppendMenu(MF_SEPARATOR, NULL);\r
-                               popup.AppendMenuIcon(ID_OPEN, IDS_LOG_POPUP_OPEN, IDI_OPEN);\r
-                               popup.AppendMenuIcon(ID_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
-                               popup.AppendMenuIcon(ID_BLAME, IDS_LOG_POPUP_BLAME, IDI_BLAME);\r
+                               popup.AppendMenuIcon(CGitLogList::ID_OPEN, IDS_LOG_POPUP_OPEN, IDI_OPEN);\r
+                               popup.AppendMenuIcon(CGitLogList::ID_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
+                               popup.AppendMenuIcon(CGitLogList::ID_BLAME, IDS_LOG_POPUP_BLAME, IDI_BLAME);\r
                                popup.AppendMenu(MF_SEPARATOR, NULL);\r
                                if (m_hasWC)\r
-                                       popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREV, IDI_REVERT);\r
-                               popup.AppendMenuIcon(ID_POPPROPS, IDS_REPOBROWSE_SHOWPROP, IDI_PROPERTIES);                     // "Show Properties"\r
-                               popup.AppendMenuIcon(ID_LOG, IDS_MENULOG, IDI_LOG);                                             // "Show Log"                           \r
-                               popup.AppendMenuIcon(ID_GETMERGELOGS, IDS_LOG_POPUP_GETMERGELOGS, IDI_LOG);             // "Show merge log"\r
-                               popup.AppendMenuIcon(ID_SAVEAS, IDS_LOG_POPUP_SAVE, IDI_SAVEAS);\r
+                                       popup.AppendMenuIcon(CGitLogList::ID_REVERTREV, IDS_LOG_POPUP_REVERTREV, IDI_REVERT);\r
+                               popup.AppendMenuIcon(CGitLogList::ID_POPPROPS, IDS_REPOBROWSE_SHOWPROP, IDI_PROPERTIES);                        // "Show Properties"\r
+                               popup.AppendMenuIcon(CGitLogList::ID_LOG, IDS_MENULOG, IDI_LOG);                                                // "Show Log"                           \r
+                               popup.AppendMenuIcon(CGitLogList::ID_GETMERGELOGS, IDS_LOG_POPUP_GETMERGELOGS, IDI_LOG);                // "Show merge log"\r
+                               popup.AppendMenuIcon(CGitLogList::ID_SAVEAS, IDS_LOG_POPUP_SAVE, IDI_SAVEAS);\r
                                bEntryAdded = true;\r
                                if (!m_ProjectProperties.sWebViewerPathRev.IsEmpty())\r
                                {\r
                                        popup.AppendMenu(MF_SEPARATOR, NULL);\r
-                                       popup.AppendMenuIcon(ID_VIEWPATHREV, IDS_LOG_POPUP_VIEWPATHREV);\r
+                                       popup.AppendMenuIcon(CGitLogList::ID_VIEWPATHREV, IDS_LOG_POPUP_VIEWPATHREV);\r
                                }\r
                                if (popup.GetDefaultItem(0,FALSE)==-1)\r
-                                       popup.SetDefaultItem(ID_OPEN, FALSE);\r
+                                       popup.SetDefaultItem(CGitLogList::ID_OPEN, FALSE);\r
                        }\r
                }\r
                else if (changedlogpaths.size())\r
                {\r
                        // more than one entry is selected\r
-                       popup.AppendMenuIcon(ID_SAVEAS, IDS_LOG_POPUP_SAVE);\r
+                       popup.AppendMenuIcon(CGitLogList::ID_SAVEAS, IDS_LOG_POPUP_SAVE);\r
                        bEntryAdded = true;\r
                }\r
 \r
@@ -3710,7 +3650,7 @@ void CLogDlg::ShowContextMenuForChangedpaths(CWnd* /*pWnd*/, CPoint point)
                \r
                switch (cmd)\r
                {\r
-               case ID_DIFF:\r
+               case CGitLogList::ID_DIFF:\r
                        {\r
                                DoDiffFromLog(selIndex, rev1, rev2, false, false);\r
                        }\r
@@ -4138,7 +4078,7 @@ void CLogDlg::OnEditCopy()
        if (GetFocus() == &m_ChangedFileListCtrl)\r
                CopyChangedSelectionToClipBoard();\r
        else\r
-               CopySelectionToClipBoard();\r
+               m_LogList.CopySelectionToClipBoard();\r
 }\r
 \r
 CString CLogDlg::GetAbsoluteUrlFromRelativeUrl(const CString& url)\r
index 0055ab1..c61bc4e 100644 (file)
@@ -32,9 +32,9 @@
 #include "GitRev.h"\r
 #include "Tooltip.h"\r
 #include "HintListCtrl.h"\r
+#include <regex>\r
 #include "GitLogList.h"\r
 \r
-#include <regex>\r
 using namespace std;\r
 \r
 \r
@@ -151,7 +151,7 @@ protected:
        virtual void OnCancel();\r
        virtual void OnOK();\r
        virtual BOOL OnInitDialog();\r
-       virtual BOOL PreTranslateMessage(MSG* pMsg);\r
+       //virtual BOOL PreTranslateMessage(MSG* pMsg);\r
 \r
        void    FillLogMessageCtrl(bool bShow = true);\r
        void    DoDiffFromLog(INT_PTR selIndex, GitRev *rev1, GitRev *rev2, bool blame, bool unified);\r