OSDN Git Service

Enable formatpatch at log dialog
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / GitLogListBase.cpp
index 89d732e..6dd415e 100644 (file)
@@ -57,6 +57,7 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl()
        , m_bStrictStopped(false)\r
        , m_pStoreSelection(NULL)\r
        , m_nSelectedFilter(LOGFILTER_ALL)\r
+       , m_bVista(false)\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
@@ -83,6 +84,7 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl()
 \r
        g_Git.GetMapHashToFriendName(m_HashMap);\r
        m_CurrentBranch=g_Git.GetCurrentBranch();\r
+       this->m_HeadHash=g_Git.GetHash(CString(_T("HEAD"))).Left(40);\r
 \r
        m_From=CTime(1970,1,2,0,0,0);\r
        m_To=CTime::GetCurrentTime();\r
@@ -90,6 +92,9 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl()
        m_LoadingThread = NULL;\r
 \r
        m_bExitThread=FALSE;\r
+       m_IsOldFirst = FALSE;\r
+       m_IsRebaseReplaceGraph = FALSE;\r
+\r
 \r
        for(int i=0;i<Lanes::COLORS_NUM;i++)\r
        {\r
@@ -108,6 +113,21 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl()
        // get relative time display setting from registry\r
        DWORD regRelativeTimes = CRegDWORD(_T("Software\\TortoiseGit\\RelativeTimes"), FALSE);\r
        m_bRelativeTimes = (regRelativeTimes != 0);\r
+       m_ContextMenuMask = 0xFFFFFFFFFFFFFFFF;\r
+\r
+       m_ContextMenuMask &= ~GetContextMenuBit(ID_REBASE_PICK);\r
+       m_ContextMenuMask &= ~GetContextMenuBit(ID_REBASE_SQUASH);\r
+       m_ContextMenuMask &= ~GetContextMenuBit(ID_REBASE_EDIT);\r
+       m_ContextMenuMask &= ~GetContextMenuBit(ID_REBASE_SKIP);\r
+\r
+       OSVERSIONINFOEX inf;\r
+       SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
+       inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
+       GetVersionEx((OSVERSIONINFO *)&inf);\r
+       WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
+       m_bVista = (fullver >= 0x0600);\r
+\r
+       m_ColumnRegKey=_T("log");\r
 }\r
 \r
 CGitLogListBase::~CGitLogListBase()\r
@@ -173,6 +193,14 @@ void CGitLogListBase::InsertGitColumn()
                DeleteColumn(c--);\r
        temp.LoadString(IDS_LOG_GRAPH);\r
 \r
+       if(m_IsRebaseReplaceGraph)\r
+       {\r
+               temp=_T("Rebase");\r
+       }\r
+       else\r
+       {\r
+               temp.LoadString(IDS_LOG_GRAPH);\r
+       }\r
        InsertColumn(this->LOGLIST_GRAPH, temp);\r
        \r
 #if 0  \r
@@ -236,7 +264,7 @@ void CGitLogListBase::ResizeAllListCtrlCols()
                {\r
                        // get width for this col last time from registry\r
                        CString regentry;\r
-                       regentry.Format( _T("Software\\TortoiseGit\\log\\ColWidth%d"), col);\r
+                       regentry.Format( _T("Software\\TortoiseGit\\%s\\ColWidth%d"),m_ColumnRegKey, col);\r
                        CRegDWORD regwidth(regentry, 0);\r
                        int cx = regwidth;\r
                        if ( cx == 0 )\r
@@ -288,6 +316,10 @@ void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect)
        rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
        GetItem(&rItem);\r
 \r
+       GitRev* pLogEntry = (GitRev*)m_arShownList.GetAt(Index);\r
+       HBRUSH brush;\r
+\r
+       \r
        if (m_Theme.IsAppThemed() && m_bVista)\r
        {\r
                m_Theme.Open(m_hWnd, L"Explorer");\r
@@ -301,34 +333,27 @@ void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect)
                }\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
+                       if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
+                               brush = ::CreateSolidBrush(RGB(156,156,156));\r
+                       else if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_EDIT)\r
+                               brush = ::CreateSolidBrush(RGB(200,200,128));\r
+\r
+                       if (brush == NULL)\r
+                               return;\r
+\r
+                       ::FillRect(hdc, &rect, brush);\r
+                       ::DeleteObject(brush);\r
+\r
                }\r
 \r
                if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTDETAIL, state))\r
                        m_Theme.DrawParentBackground(m_hWnd, hdc, &rect);\r
-\r
+               else\r
                        m_Theme.DrawBackground(hdc, LVP_LISTDETAIL, state, &rect, NULL);\r
        }\r
        else\r
        {\r
-               HBRUSH brush;\r
+               \r
                if (rItem.state & LVIS_SELECTED)\r
                {\r
                        if (::GetFocus() == m_hWnd)\r
@@ -341,6 +366,11 @@ void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect)
                        //if (pLogEntry->bCopiedSelf)\r
                        //      brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
                        //else\r
+                       if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
+                               brush = ::CreateSolidBrush(RGB(156,156,156));\r
+                       else if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_EDIT)\r
+                               brush = ::CreateSolidBrush(RGB(200,200,128));\r
+                       else \r
                                brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));\r
                }\r
                if (brush == NULL)\r
@@ -386,6 +416,12 @@ void CGitLogListBase::DrawTagBranch(HDC hdc,CRect &rect,INT_PTR index)
                {\r
                        brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::Tag));\r
                }\r
+               else if(GetShortName(str,shortname,_T("refs/stash")))\r
+               {\r
+                       brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::Stash));\r
+                       shortname=_T("stash");\r
+               }\r
+               \r
 \r
                if(!shortname.IsEmpty())\r
                {\r
@@ -592,6 +628,9 @@ void CGitLogListBase::DrawGraph(HDC hdc,CRect &rect,INT_PTR index)
        //todo unfinished\r
 //     return;\r
        GitRev* data = (GitRev*)m_arShownList.GetAt(index);\r
+       if(data->m_CommitHash.IsEmpty())\r
+               return;\r
+\r
        CRect rt=rect;\r
        LVITEM   rItem;\r
        SecureZeroMemory(&rItem, sizeof(LVITEM));\r
@@ -688,6 +727,28 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)
                                        if (data->bCopies)\r
                                                crText = m_Colors.GetColor(CColors::Modified);\r
 #endif\r
+                                       if (data->m_Action& (CTGitPath::LOGACTIONS_REBASE_DONE| CTGitPath::LOGACTIONS_REBASE_SKIP) ) \r
+                                               crText = RGB(128,128,128);\r
+\r
+                                       if(data->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
+                                               pLVCD->clrTextBk = RGB(156,156,156);\r
+                                       else if(data->m_Action&CTGitPath::LOGACTIONS_REBASE_EDIT)\r
+                                               pLVCD->clrTextBk  = RGB(200,200,128);\r
+                                       else \r
+                                               pLVCD->clrTextBk  = ::GetSysColor(COLOR_WINDOW);\r
+\r
+                                       if(data->m_Action&CTGitPath::LOGACTIONS_REBASE_CURRENT)\r
+                                       {\r
+                                               SelectObject(pLVCD->nmcd.hdc, m_boldFont);\r
+                                               *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;\r
+                                       }\r
+\r
+                                       if(data->m_CommitHash == m_HeadHash)\r
+                                       {\r
+                                               SelectObject(pLVCD->nmcd.hdc, m_boldFont);\r
+                                               *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;\r
+                                       }\r
+\r
 //                                     if ((data->childStackDepth)||(m_mergedRevs.find(data->Rev) != m_mergedRevs.end()))\r
 //                                             crText = GetSysColor(COLOR_GRAYTEXT);\r
 //                                     if (data->Rev == m_wcRev)\r
@@ -718,7 +779,7 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)
 \r
                        if (pLVCD->iSubItem == LOGLIST_GRAPH)\r
                        {\r
-                               if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
+                               if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec && (!this->m_IsRebaseReplaceGraph) )\r
                                {\r
                                        CRect rect;\r
                                        GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
@@ -790,7 +851,7 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)
                                        ::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
+                               if (pLogEntry->m_Action & (CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_COPY) )\r
                                        ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hAddedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
                                nIcons++;\r
 \r
@@ -840,7 +901,14 @@ void CGitLogListBase::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult)
                pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(pItem->iItem));\r
 \r
        CString temp;\r
-       temp.Format(_T("%d"),m_arShownList.GetCount()-pItem->iItem);\r
+       if(m_IsOldFirst)\r
+       {\r
+               temp.Format(_T("%d"),pItem->iItem+1);\r
+\r
+       }else\r
+       {\r
+               temp.Format(_T("%d"),m_arShownList.GetCount()-pItem->iItem);\r
+       }\r
            \r
        // Which column?\r
        switch (pItem->iSubItem)\r
@@ -848,6 +916,13 @@ void CGitLogListBase::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult)
        case this->LOGLIST_GRAPH:       //Graphic\r
                if (pLogEntry)\r
                {\r
+                       if(this->m_IsRebaseReplaceGraph)\r
+                       {\r
+                               CTGitPath path;\r
+                               path.m_Action=pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_MODE_MASK;\r
+\r
+                               lstrcpyn(pItem->pszText,path.GetActionName(), pItem->cchTextMax);\r
+                       }\r
                }\r
                break;\r
        case this->LOGLIST_ACTION: //action -- no text in the column\r
@@ -966,31 +1041,30 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
        CIconMenu popup;\r
        if (popup.CreatePopupMenu())\r
        {\r
+\r
+               if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_PICK))\r
+                       popup.AppendMenuIcon(ID_REBASE_PICK,  IDS_REBASE_SKIP,   IDI_PICK);\r
+\r
+               if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_SQUASH))\r
+                       popup.AppendMenuIcon(ID_REBASE_SQUASH,IDS_REBASE_SQUASH, IDI_SQUASH);\r
+\r
+               if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_EDIT))\r
+                       popup.AppendMenuIcon(ID_REBASE_EDIT,  IDS_REBASE_EDIT,   IDI_EDIT);\r
+\r
+               if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_SKIP))\r
+                       popup.AppendMenuIcon(ID_REBASE_SKIP,  IDS_REBASE_SKIP,   IDI_SKIP);\r
+               \r
+               if(m_ContextMenuMask&(GetContextMenuBit(ID_REBASE_SKIP)|GetContextMenuBit(ID_REBASE_EDIT)|\r
+                             GetContextMenuBit(ID_REBASE_SQUASH)|GetContextMenuBit(ID_REBASE_PICK)))\r
+                       popup.AppendMenu(MF_SEPARATOR, NULL);\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
+                                       if(m_ContextMenuMask&GetContextMenuBit(ID_COMPARE))\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
@@ -999,8 +1073,11 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
                                        // 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
+                               if(m_ContextMenuMask&GetContextMenuBit(ID_GNUDIFF1))\r
+                                       popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
+\r
+                               if(m_ContextMenuMask&GetContextMenuBit(ID_COMPAREWITHPREVIOUS))\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
@@ -1026,31 +1103,61 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
                        //if (m_hasWC)\r
                        //      popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREV, IDI_MERGE);\r
                        \r
-                       CString str;\r
-                       str.Format(_T("Reset %s to this"),g_Git.GetCurrentBranch());\r
-                       popup.AppendMenuIcon(ID_RESET,str,IDI_REVERT);\r
-                       popup.AppendMenuIcon(ID_SWITCHTOREV, _T("Switch/Checkout to this") , IDI_SWITCH);\r
-                       popup.AppendMenuIcon(ID_CREATE_BRANCH, _T("Create Branch at this version") , IDI_COPY);\r
-                       popup.AppendMenuIcon(ID_CREATE_TAG, _T("Create Tag at this version"), IDI_COPY);\r
-                       popup.AppendMenuIcon(ID_CHERRY_PICK, _T("Cherry Pick this version"), IDI_EXPORT);\r
-                       popup.AppendMenuIcon(ID_EXPORT, _T("Export this version"), IDI_EXPORT);\r
+                       CString str,format;\r
+                       format.LoadString(IDS_RESET_TO_THIS_FORMAT);\r
+                       str.Format(format,g_Git.GetCurrentBranch());\r
+\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_RESET))\r
+                               popup.AppendMenuIcon(ID_RESET,str,IDI_REVERT);\r
+\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_SWITCHTOREV))\r
+                               popup.AppendMenuIcon(ID_SWITCHTOREV, IDS_SWITCH_TO_THIS , IDI_SWITCH);\r
+\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_BRANCH))\r
+                               popup.AppendMenuIcon(ID_CREATE_BRANCH, IDS_CREATE_BRANCH_AT_THIS , IDI_COPY);\r
+\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_TAG))\r
+                               popup.AppendMenuIcon(ID_CREATE_TAG,IDS_CREATE_TAG_AT_THIS , IDI_COPY);\r
+                       \r
+                       format.LoadString(IDS_REBASE_THIS_FORMAT);\r
+                       str.Format(format,g_Git.GetCurrentBranch());\r
+\r
+                       if(pSelLogEntry->m_CommitHash != m_HeadHash)\r
+                               if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_TO_VERSION))\r
+                                       popup.AppendMenuIcon(ID_REBASE_TO_VERSION, str , IDI_REBASE);                   \r
+\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_EXPORT))\r
+                               popup.AppendMenuIcon(ID_EXPORT,IDS_EXPORT_TO_THIS, IDI_EXPORT); \r
                        \r
 \r
                        popup.AppendMenu(MF_SEPARATOR, NULL);\r
+\r
                }\r
-               else if (GetSelectedCount() >= 2)\r
+\r
+               if(!pSelLogEntry->m_Ref.IsEmpty() && GetSelectedCount() == 1)\r
+               {\r
+                       popup.AppendMenuIcon(ID_REFLOG_DEL, IDS_REFLOG_DEL,     IDI_DELETE);    \r
+                       popup.AppendMenuIcon(ID_STASH_APPLY,IDS_MENUSTASHAPPLY, IDI_RELOCATE);  \r
+                       popup.AppendMenu(MF_SEPARATOR, NULL);\r
+               }\r
+       \r
+               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
+                               if(m_ContextMenuMask&GetContextMenuBit(ID_COMPARETWO))\r
+                                       popup.AppendMenuIcon(ID_COMPARETWO, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);\r
                        }\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
+                               if(m_ContextMenuMask&GetContextMenuBit(ID_GNUDIFF2))\r
+                                       popup.AppendMenuIcon(ID_GNUDIFF2, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
                                bAddSeparator = true;\r
                        }\r
+\r
                        if (m_hasWC)\r
                        {\r
                                //popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREVS, IDI_REVERT);\r
@@ -1061,6 +1168,39 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
                        if (bAddSeparator)\r
                                popup.AppendMenu(MF_SEPARATOR, NULL);\r
                }\r
+\r
+               if ( GetSelectedCount() >0 )\r
+               {\r
+                       if ( IsSelectionContinuous() && GetSelectedCount() >= 2 )\r
+                       {\r
+                               if(m_ContextMenuMask&GetContextMenuBit(ID_COMBINE_COMMIT))\r
+                               {\r
+                                       CString head;\r
+                                       int headindex;\r
+                                       headindex = this->GetHeadIndex();\r
+                                       if(headindex>=0)\r
+                                       {\r
+                                               head.Format(_T("HEAD~%d"),LastSelect-headindex);\r
+                                               CString hash=g_Git.GetHash(head);\r
+                                               hash=hash.Left(40);\r
+                                               GitRev* pLastEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
+                                               if(pLastEntry->m_CommitHash == hash)\r
+                                                       popup.AppendMenuIcon(ID_COMBINE_COMMIT,IDS_COMBINE_TO_ONE,IDI_COMBINE);\r
+                                       }\r
+                               }\r
+                       }\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_CHERRY_PICK))\r
+                               popup.AppendMenuIcon(ID_CHERRY_PICK, IDS_CHERRY_PICK_VERSION, IDI_EXPORT);\r
+\r
+                       if(GetSelectedCount()<=2)\r
+                               if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_PATCH))\r
+                                       popup.AppendMenuIcon(ID_CREATE_PATCH, IDS_CREATE_PATCH, IDI_PATCH);\r
+                       \r
+                       popup.AppendMenu(MF_SEPARATOR, NULL);\r
+       \r
+               }\r
+\r
+               \r
 #if 0\r
 //             if ((selEntries.size() > 0)&&(bAllFromTheSameAuthor))\r
 //             {\r
@@ -1077,13 +1217,17 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
                \r
                if (GetSelectedCount() == 1)\r
                {\r
-                       popup.AppendMenuIcon(ID_COPYHASH, _T("Copy Commit Hash"));\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_COPYHASH))\r
+                               popup.AppendMenuIcon(ID_COPYHASH, IDS_COPY_COMMIT_HASH);\r
                }\r
                if (GetSelectedCount() != 0)\r
                {\r
-                       popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD);\r
+                       if(m_ContextMenuMask&GetContextMenuBit(ID_COPYCLIPBOARD))\r
+                               popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD);\r
                }\r
-               popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND);\r
+\r
+               if(m_ContextMenuMask&GetContextMenuBit(ID_FINDENTRY))\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
@@ -1178,9 +1322,20 @@ void CGitLogListBase::CopySelectionToClipBoard(bool HashOnly)
 \r
 void CGitLogListBase::DiffSelectedRevWithPrevious()\r
 {\r
-#if 0\r
        if (m_bThreadRunning)\r
                return;\r
+\r
+       int FirstSelect=-1, LastSelect=-1;\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       FirstSelect = GetNextSelectedItem(pos);\r
+       while(pos)\r
+       {\r
+               LastSelect = GetNextSelectedItem(pos);\r
+       }\r
+\r
+       ContextMenuAction(ID_COMPAREWITHPREVIOUS,FirstSelect,LastSelect);\r
+\r
+#if 0\r
        UpdateLogInfoLabel();\r
        int selIndex = m_LogList.GetSelectionMark();\r
        if (selIndex < 0)\r
@@ -1301,12 +1456,12 @@ void CGitLogListBase::OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult)
        *pResult = -1;\r
 }\r
 \r
-int CGitLogListBase::FillGitLog(CTGitPath *path,int info)\r
+int CGitLogListBase::FillGitLog(CTGitPath *path,int info,CString *from,CString *to)\r
 {\r
        ClearText();\r
 \r
        this->m_logEntries.ClearAll();\r
-       this->m_logEntries.ParserFromLog(path,-1,info);\r
+       this->m_logEntries.ParserFromLog(path,-1,info,from,to);\r
 \r
        //this->m_logEntries.ParserFromLog();\r
        SetItemCountEx(this->m_logEntries.size());\r
@@ -1315,8 +1470,16 @@ int CGitLogListBase::FillGitLog(CTGitPath *path,int info)
 \r
        for(unsigned int i=0;i<m_logEntries.size();i++)\r
        {\r
-               m_logEntries[i].m_IsFull=TRUE;\r
-               this->m_arShownList.Add(&m_logEntries[i]);\r
+               if(m_IsOldFirst)\r
+               {\r
+                       m_logEntries[m_logEntries.size()-i-1].m_IsFull=TRUE;\r
+                       this->m_arShownList.Add(&m_logEntries[m_logEntries.size()-i-1]);\r
+               \r
+               }else\r
+               {\r
+                       m_logEntries[i].m_IsFull=TRUE;\r
+                       this->m_arShownList.Add(&m_logEntries[i]);\r
+               }\r
        }\r
 \r
     if(path)\r
@@ -1345,9 +1508,8 @@ int CGitLogListBase::FillGitShortLog()
 //     if(this->m_bAllBranch)\r
        mask |= m_ShowMask;\r
 \r
-       this->m_logEntries.ParserShortLog(path,hash,-1,mask);\r
+       this->m_logEntries.FetchShortLog(path,m_StartRef,-1,mask);\r
        \r
-\r
        //this->m_logEntries.ParserFromLog();\r
        if(IsInWorkingThread())\r
                PostMessage(LVM_SETITEMCOUNT, (WPARAM) this->m_logEntries.size(),(LPARAM) LVSICF_NOINVALIDATEALL);\r
@@ -1357,8 +1519,17 @@ int CGitLogListBase::FillGitShortLog()
        this->m_arShownList.RemoveAll();\r
 \r
        for(unsigned int i=0;i<m_logEntries.size();i++)\r
-               this->m_arShownList.Add(&m_logEntries[i]);\r
+       {\r
+               m_logEntries[i].m_Subject=_T("parser...");\r
+               if(this->m_IsOldFirst)\r
+               {\r
+                       this->m_arShownList.Add(&m_logEntries[m_logEntries.size()-1-i]);\r
 \r
+               }else\r
+               {\r
+                       this->m_arShownList.Add(&m_logEntries[i]);\r
+               }\r
+       }\r
        return 0;\r
 }\r
 \r
@@ -1403,8 +1574,8 @@ void CGitLogListBase::OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult)
        // 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
+       if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
+               DiffSelectedRevWithPrevious();\r
 }\r
 \r
 int CGitLogListBase::FetchLogAsync(void * data)\r
@@ -1498,9 +1669,21 @@ public:
                GitRev* revInVector=&m_ploglist->m_logEntries[rev];\r
 \r
 \r
+               if(revInVector->m_IsFull)\r
+                       return;\r
+\r
+               if(!m_ploglist->m_LogCache.GetCacheData(m_ploglist->m_logEntries[rev]))\r
+               {\r
+                       ++m_CollectedCount;\r
+                       InterlockedExchange(&m_ploglist->m_logEntries[rev].m_IsUpdateing,FALSE);\r
+                       InterlockedExchange(&m_ploglist->m_logEntries[rev].m_IsFull,TRUE);\r
+                       ::PostMessage(m_ploglist->m_hWnd,MSG_LOADED,(WPARAM)rev,0);\r
+                       return;\r
+               }\r
+\r
 //             fullRev.m_IsUpdateing=TRUE;\r
 //             fullRev.m_IsFull=TRUE;\r
-\r
+       \r
 \r
                if(InterlockedExchange(&revInVector->m_IsUpdateing,TRUE))\r
                        return;//Cannot update this row now. Ignore.\r
@@ -1516,6 +1699,9 @@ public:
                                                               //So we need keep old bound mark.\r
                revInVector->m_ParentHash=oldlist;\r
 \r
+               //update cache\r
+               m_ploglist->m_LogCache.AddCacheEntry(*revInVector);\r
+\r
                //Reset updating\r
                InterlockedExchange(&revInVector->m_IsFull,TRUE);\r
                InterlockedExchange(&revInVector->m_IsUpdateing,FALSE);\r
@@ -1525,7 +1711,7 @@ public:
 \r
                ::PostMessage(m_ploglist->m_hWnd,MSG_LOADED,(WPARAM)rev,0);\r
 \r
-               DWORD percent=m_CollectedCount*98/m_ploglist->m_logEntries.size() + GITLOG_START+1;\r
+               DWORD percent=m_CollectedCount*68/m_ploglist->m_logEntries.size() + GITLOG_START+1+30;\r
                if(percent == GITLOG_END)\r
                        percent = GITLOG_END -1;\r
                \r
@@ -1538,7 +1724,7 @@ public:
 \r
 };\r
 \r
-void CGitLogListBase::FetchFullLogInfo()\r
+void CGitLogListBase::FetchFullLogInfo(CString &from, CString &to)\r
 {\r
        CGitCall_FetchFullLogInfo fetcher(this);\r
        int mask=\r
@@ -1546,18 +1732,27 @@ void CGitLogListBase::FetchFullLogInfo()
                CGit::LOG_INFO_FILESTATE|\r
                CGit::LOG_INFO_DETECT_COPYRENAME|\r
                m_ShowMask;\r
-       g_Git.GetLog(&fetcher,CString(),NULL,-1,mask);\r
+\r
+       CTGitPath *path;\r
+    if(this->m_Path.IsEmpty())\r
+        path=NULL;\r
+    else\r
+        path=&this->m_Path;\r
+\r
+       g_Git.GetLog(&fetcher,CString(),path,-1,mask,&from,&to);\r
 }\r
 \r
-void CGitLogListBase::FetchFullLogInfoOrig()\r
+void CGitLogListBase::FetchLastLogInfo()\r
 {\r
        unsigned int updated=0;\r
        int percent=0;\r
        CRect rect;\r
-       while(1)\r
        {\r
                for(unsigned int i=0;i<m_logEntries.size();i++)\r
                {\r
+                       if(m_logEntries[i].m_IsFull)\r
+                               continue;\r
+\r
                        if(m_LogCache.GetCacheData(m_logEntries[i]))\r
                        {\r
                                if(!m_logEntries.FetchFullInfo(i))\r
@@ -1580,18 +1775,8 @@ void CGitLogListBase::FetchFullLogInfoOrig()
                                InterlockedExchange(&m_bThreadRunning, FALSE);\r
                                InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
                                return;\r
-                       }\r
-\r
-                       percent=updated*98/m_logEntries.size() + GITLOG_START+1;\r
-                       if(percent == GITLOG_END)\r
-                               percent = GITLOG_END -1;\r
-                       \r
-                       ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent,0);\r
-\r
-                       \r
+                       }                       \r
                }\r
-               if(updated==m_logEntries.size())\r
-                       break;\r
        }\r
 }\r
 \r
@@ -1620,6 +1805,50 @@ UINT CGitLogListBase::LogThread()
                InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
                return 0;\r
        }\r
+       InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
+       ::PostMessage(GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_START_ALL, 0);\r
+\r
+       int start=0; CString firstcommit,lastcommit;\r
+       int update=0;\r
+       for(int i=0;i<m_logEntries.size();i++)\r
+       {\r
+               start=this->m_logEntries[i].ParserFromLog(m_logEntries.m_RawlogData,start);\r
+               m_logEntries.m_HashMap[m_logEntries[i].m_CommitHash]=i;\r
+\r
+               if(m_LogCache.GetCacheData(m_logEntries[i]))\r
+               {\r
+                       if(firstcommit.IsEmpty())\r
+                               firstcommit=m_logEntries[i].m_CommitHash;\r
+                       lastcommit=m_logEntries[i].m_CommitHash;\r
+\r
+               }else\r
+               {\r
+                       InterlockedExchange(&m_logEntries[i].m_IsUpdateing,FALSE);\r
+                       InterlockedExchange(&m_logEntries[i].m_IsFull,TRUE);\r
+                       update++;\r
+               }\r
+               if(start<0)\r
+                       break;\r
+               if(start>=m_logEntries.m_RawlogData.size())\r
+                       break;\r
+\r
+               int percent=i*30/m_logEntries.size() + GITLOG_START+1;\r
+\r
+               ::PostMessage(GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent, 0);\r
+               ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM) i, 0);\r
+\r
+               if(this->m_bExitThread)\r
+               {       \r
+                       InterlockedExchange(&m_bThreadRunning, FALSE);\r
+                       InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
+                       return 0;\r
+               }\r
+       }\r
+       if(!lastcommit.IsEmpty())\r
+               FetchFullLogInfo(lastcommit,firstcommit);\r
+       \r
+       this->FetchLastLogInfo();\r
+       \r
 #if 0\r
        RedrawItems(0, m_arShownList.GetCount());\r
 //     SetRedraw(false);\r
@@ -1644,10 +1873,10 @@ UINT CGitLogListBase::LogThread()
                }\r
        }\r
 #endif\r
-       InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
 \r
 \r
-       FetchFullLogInfo();\r
+\r
+       //FetchFullLogInfo();\r
        //FetchFullLogInfoOrig();\r
        //RefreshCursor();\r
        // make sure the filter is applied (if any) now, after we refreshed/fetched\r
@@ -1663,9 +1892,12 @@ UINT CGitLogListBase::LogThread()
 void CGitLogListBase::Refresh()\r
 {      \r
        m_bExitThread=TRUE;\r
-       DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000);\r
-       if(ret == WAIT_TIMEOUT)\r
-               TerminateThread();\r
+       if(m_LoadingThread!=NULL)\r
+       {\r
+               DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000);\r
+               if(ret == WAIT_TIMEOUT)\r
+                       TerminateThread();\r
+       }\r
 \r
        this->Clear();\r
 \r
@@ -1937,7 +2169,13 @@ void CGitLogListBase::RemoveFilter()
 \r
        for (DWORD i=0; i<m_logEntries.size(); ++i)\r
        {\r
-               m_arShownList.Add(&m_logEntries[i]);\r
+               if(this->m_IsOldFirst)\r
+               {\r
+                       m_arShownList.Add(&m_logEntries[m_logEntries.size()-i-1]);\r
+               }else\r
+               {\r
+                       m_arShownList.Add(&m_logEntries[i]);\r
+               }\r
        }\r
 //     InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
        DeleteAllItems();\r
@@ -1953,13 +2191,9 @@ void CGitLogListBase::RemoveFilter()
 void CGitLogListBase::Clear()\r
 {\r
        m_arShownList.RemoveAll();\r
-       m_logEntries.clear();\r
-       m_logEntries.m_HashMap.clear();\r
        DeleteAllItems();\r
-       m_logEntries.m_Lns.clear();\r
 \r
-       m_logEntries.m_FirstFreeLane=0;\r
-       m_logEntries.m_Lns.clear();\r
+       m_logEntries.ClearAll();\r
 \r
 }\r
 \r
@@ -2006,10 +2240,26 @@ void CGitLogListBase::SaveColumnWidths()
                {\r
                        int width = GetColumnWidth( col );\r
                        CString regentry;\r
-                       regentry.Format( _T("Software\\TortoiseGit\\log\\ColWidth%d"), col);\r
+                       regentry.Format( _T("Software\\TortoiseGit\\%s\\ColWidth%d"),m_ColumnRegKey, col);\r
                        CRegDWORD regwidth(regentry, 0);\r
                        regwidth = width;       // this writes it to reg\r
                }\r
        }\r
 }\r
 \r
+int CGitLogListBase::GetHeadIndex()\r
+{\r
+       if(m_HeadHash.IsEmpty())\r
+               return -1;\r
+\r
+       for(int i=0;i<m_arShownList.GetCount();i++)\r
+       {\r
+               GitRev *pRev = (GitRev*)m_arShownList[i];\r
+               if(pRev)\r
+               {\r
+                       if(pRev->m_CommitHash == m_HeadHash )\r
+                               return i;\r
+               }\r
+       }\r
+       return -1;\r
+}
\ No newline at end of file