OSDN Git Service

Update first commit can't show when launch log dialog
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / GitLogListBase.cpp
index 3a2f1fa..f4e2314 100644 (file)
@@ -47,7 +47,6 @@
 #include "..\\TortoiseShell\\Resource.h"\r
 \r
 \r
-\r
 IMPLEMENT_DYNAMIC(CGitLogListBase, CHintListCtrl)\r
 \r
 CGitLogListBase::CGitLogListBase():CHintListCtrl()\r
@@ -58,6 +57,8 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl()
        , m_bStrictStopped(false)\r
        , m_pStoreSelection(NULL)\r
        , m_nSelectedFilter(LOGFILTER_ALL)\r
+       , m_bVista(false)\r
+       , m_bShowWC(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
@@ -73,7 +74,11 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl()
        m_IsIDReplaceAction=FALSE;\r
 \r
        m_wcRev.m_CommitHash=GIT_REV_ZERO;\r
-       m_wcRev.m_Subject=_T("Working Copy");\r
+       m_wcRev.m_Subject=_T("Working dir changes");\r
+       m_wcRev.m_ParentHash.clear();\r
+       m_wcRev.m_Mark=_T('-');\r
+       m_wcRev.m_IsUpdateing=FALSE;\r
+       m_wcRev.m_IsFull = TRUE;\r
 \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
@@ -84,18 +89,50 @@ 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
-    m_bAllBranch = FALSE;\r
+    m_ShowMask = 0;\r
        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
                m_LineColors[i] = m_Colors.GetColor((CColors::Colors)(CColors::BranchLine1+i));\r
        }\r
+       // get short/long datetime setting from registry\r
+       DWORD RegUseShortDateFormat = CRegDWORD(_T("Software\\TortoiseGit\\LogDateFormat"), TRUE);\r
+       if ( RegUseShortDateFormat )\r
+       {\r
+               m_DateFormat = DATE_SHORTDATE;\r
+       }\r
+       else\r
+       {\r
+               m_DateFormat = DATE_LONGDATE;\r
+       }\r
+       // 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
@@ -116,6 +153,13 @@ CGitLogListBase::~CGitLogListBase()
                delete m_pStoreSelection;\r
                m_pStoreSelection = NULL;\r
        }\r
+\r
+       if(this->m_bThreadRunning)\r
+       {\r
+               m_bExitThread=true;\r
+               WaitForSingleObject(m_LoadingThread->m_hThread,1000);\r
+               TerminateThread();\r
+       }\r
 }\r
 \r
 \r
@@ -126,8 +170,27 @@ BEGIN_MESSAGE_MAP(CGitLogListBase, CHintListCtrl)
        ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclkLoglist)\r
        ON_NOTIFY_REFLECT(LVN_ODFINDITEM,OnLvnOdfinditemLoglist)\r
        ON_WM_CREATE()\r
+       ON_WM_DESTROY()\r
+       ON_MESSAGE(MSG_LOADED,OnLoad)\r
+       ON_WM_MEASUREITEM()\r
+       ON_WM_MEASUREITEM_REFLECT()\r
 END_MESSAGE_MAP()\r
 \r
+void CGitLogListBase::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)\r
+{\r
+       // TODO: ÔÚ´ËÌí¼ÓÏûÏ¢´¦Àí³ÌÐò´úÂëºÍ/»òµ÷ÓÃĬÈÏÖµ\r
+\r
+       CListCtrl::OnMeasureItem(nIDCtl, lpMeasureItemStruct);\r
+}\r
+\r
+void CGitLogListBase::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)\r
+{\r
+       //if (m_nRowHeight>0)\r
+       {\r
+               lpMeasureItemStruct->itemHeight = 50;\r
+       }\r
+}\r
+\r
 int CGitLogListBase:: OnCreate(LPCREATESTRUCT lpCreateStruct)\r
 {\r
        PreSubclassWindow();\r
@@ -138,7 +201,9 @@ void CGitLogListBase::PreSubclassWindow()
 {\r
        SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES);\r
        // load the icons for the action columns\r
-       m_Theme.SetWindowTheme(GetSafeHwnd(), L"Explorer", NULL);\r
+//     m_Theme.Open(m_hWnd, L"ListView");\r
+       m_Theme.Open(m_hWnd, L"Explorer::ListView;ListView");\r
+       m_Theme.SetWindowTheme(m_hWnd, L"Explorer", NULL);\r
        CHintListCtrl::PreSubclassWindow();\r
 }\r
 \r
@@ -146,12 +211,20 @@ void CGitLogListBase::InsertGitColumn()
 {\r
        CString temp;\r
 \r
-       int c = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
+       int c = GetHeaderCtrl()->GetItemCount()-1;\r
        \r
        while (c>=0)\r
                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
@@ -199,83 +272,43 @@ void CGitLogListBase::InsertGitColumn()
 \r
 }\r
 \r
+/**\r
+ * Resizes all columns in a list control to values in registry.\r
+ */\r
 void CGitLogListBase::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
+       // column max and min widths to allow\r
+       static const int nMinimumWidth = 10;\r
+       static const int nMaximumWidth = 1000;\r
+       CHeaderCtrl* pHdrCtrl = (CHeaderCtrl*)(GetDlgItem(0));\r
        if (pHdrCtrl)\r
        {\r
-               for (int col = 0; col <= maxcol; col++)\r
+               int numcols = pHdrCtrl->GetItemCount();\r
+               for (int col = 0; col < numcols; 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
+                       // get width for this col last time from registry\r
+                       CString regentry;\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
                        {\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
+                               // no saved value, setup sensible defaults\r
+                               if (col == this->LOGLIST_MESSAGE)\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
+                                       cx = LOGLIST_MESSAGE_MIN;\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
+                               else\r
                                {\r
-                                       cx = nMinimumWidth;\r
+                                       cx = ICONITEMBORDER+16*4;\r
                                }\r
                        }\r
-                       \r
-                       if (col == this->LOGLIST_MESSAGE)\r
+                       if (cx < nMinimumWidth)\r
                        {\r
-                               if (cx > LOGLIST_MESSAGE_MAX)\r
-                               {\r
-                                       cx = LOGLIST_MESSAGE_MAX;\r
-                               }\r
-                               if (cx < LOGLIST_MESSAGE_MIN)\r
-                               {\r
-                                       cx = LOGLIST_MESSAGE_MIN;\r
-                               }\r
-\r
-                       }\r
-                       // keep the bug id column small\r
-                       if ((col == 4)&&(m_bShowBugtraqColumn))\r
+                               cx = nMinimumWidth;\r
+                       } else if (cx > nMaximumWidth)\r
                        {\r
-                               if (cx > (int)(DWORD)m_regMaxBugIDColWidth)\r
-                               {\r
-                                       cx = (int)(DWORD)m_regMaxBugIDColWidth;\r
-                               }\r
+                               cx = nMaximumWidth;\r
                        }\r
 \r
                        SetColumnWidth(col, cx);\r
@@ -297,6 +330,7 @@ BOOL CGitLogListBase::GetShortName(CString ref, CString &shortname,CString prefi
        }\r
        return FALSE;\r
 }\r
+\r
 void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect)\r
 {      \r
 //     HBRUSH brush;\r
@@ -307,9 +341,12 @@ 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 = NULL;\r
+\r
+       \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
@@ -320,34 +357,34 @@ 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
+\r
+               if (brush != NULL)\r
+               {\r
+                       ::FillRect(hdc, &rect, brush);\r
+                       ::DeleteObject(brush);\r
                }\r
+               else\r
+               {\r
+                       if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTITEM, state))\r
+                               m_Theme.DrawParentBackground(m_hWnd, hdc, &rect);\r
 \r
-               if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTDETAIL, state))\r
-                       m_Theme.DrawParentBackground(m_hWnd, hdc, &rect);\r
+                       CRect rectDraw = rect;\r
+                       if(rItem.state & LVIS_SELECTED)\r
+                               rectDraw.InflateRect(1,0);\r
+                       else\r
+                               rectDraw.InflateRect(1,1);\r
 \r
-                       m_Theme.DrawBackground(hdc, LVP_LISTDETAIL, state, &rect, NULL);\r
+                       m_Theme.DrawBackground(hdc, LVP_LISTITEM, state, rectDraw, &rect);\r
+               }\r
        }\r
        else\r
        {\r
-               HBRUSH brush;\r
+               \r
                if (rItem.state & LVIS_SELECTED)\r
                {\r
                        if (::GetFocus() == m_hWnd)\r
@@ -360,6 +397,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
@@ -382,29 +424,45 @@ void CGitLogListBase::DrawTagBranch(HDC hdc,CRect &rect,INT_PTR index)
        rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
        GetItem(&rItem);\r
 \r
-       for(int i=0;i<m_HashMap[data->m_CommitHash].size();i++)\r
+       for(unsigned int i=0;i<m_HashMap[data->m_CommitHash].size();i++)\r
        {\r
                CString str;\r
                str=m_HashMap[data->m_CommitHash][i];\r
                \r
                CString shortname;\r
-               HBRUSH brush=0;\r
-               shortname=_T("");\r
+               HBRUSH brush = 0;\r
+               shortname = _T("");\r
+               COLORREF colRef = 0;\r
+\r
+               //Determine label color\r
                if(GetShortName(str,shortname,_T("refs/heads/")))\r
                {\r
                        if( shortname == m_CurrentBranch )\r
-                               brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::CurrentBranch));\r
+                               colRef = m_Colors.GetColor(CColors::CurrentBranch);\r
                        else\r
-                               brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::LocalBranch));\r
+                               colRef = m_Colors.GetColor(CColors::LocalBranch);\r
 \r
                }else if(GetShortName(str,shortname,_T("refs/remotes/")))\r
                {\r
-                       brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::RemoteBranch));\r
+                       colRef = m_Colors.GetColor(CColors::RemoteBranch);\r
                }\r
                else if(GetShortName(str,shortname,_T("refs/tags/")))\r
                {\r
-                       brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::Tag));\r
+                       colRef = m_Colors.GetColor(CColors::Tag);\r
                }\r
+               else if(GetShortName(str,shortname,_T("refs/stash")))\r
+               {\r
+                       colRef = m_Colors.GetColor(CColors::Stash);\r
+                       shortname=_T("stash");\r
+               }\r
+\r
+               //When row selected, ajust label color\r
+               if (!(m_Theme.IsAppThemed() && m_bVista))\r
+                       if (rItem.state & LVIS_SELECTED)\r
+                               colRef = CColors::MixColors(colRef, ::GetSysColor(COLOR_HIGHLIGHT), 150);\r
+\r
+               brush = ::CreateSolidBrush(colRef);\r
+               \r
 \r
                if(!shortname.IsEmpty())\r
                {\r
@@ -413,46 +471,97 @@ void CGitLogListBase::DrawTagBranch(HDC hdc,CRect &rect,INT_PTR index)
                        GetTextExtentPoint32(hdc, shortname,shortname.GetLength(),&size);\r
                \r
                        rt.SetRect(rt.left,rt.top,rt.left+size.cx,rt.bottom);\r
-                       rt.right+=4;\r
+                       rt.right+=8;\r
+\r
+                       //Fill interior of ref label\r
                        ::FillRect(hdc, &rt, brush);\r
-                       if (rItem.state & LVIS_SELECTED)\r
+\r
+                       //Draw edge of label\r
+                       CDC W_Dc;\r
+                       W_Dc.Attach(hdc);\r
+\r
+                       CRect rectEdge = rt;\r
+\r
+                       W_Dc.Draw3dRect(rectEdge, m_Colors.Lighten(colRef,100), m_Colors.Darken(colRef,100));\r
+                       rectEdge.DeflateRect(1,1);\r
+                       W_Dc.Draw3dRect(rectEdge, m_Colors.Lighten(colRef,50), m_Colors.Darken(colRef,50));\r
+\r
+                       W_Dc.Detach();\r
+\r
+                       //Draw text inside label\r
+                       if (m_Theme.IsAppThemed() && m_bVista)\r
                        {\r
-                               COLORREF   clrOld   = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT));   \r
-                               ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER);\r
-                               ::SetTextColor(hdc,clrOld);   \r
-                       }else\r
+                               int txtState = LISS_NORMAL;\r
+                               if (rItem.state & LVIS_SELECTED)\r
+                                       txtState = LISS_SELECTED;\r
+\r
+                               m_Theme.DrawText(hdc, LVP_LISTITEM, txtState, shortname, -1, DT_CENTER | DT_SINGLELINE | DT_VCENTER, 0, &rt);\r
+                       }\r
+                       else\r
                        {\r
-                               ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER);\r
+                               if (rItem.state & LVIS_SELECTED)\r
+                               {\r
+                                       COLORREF clrNew = ::GetSysColor(COLOR_HIGHLIGHTTEXT);\r
+                                       COLORREF   clrOld   = ::SetTextColor(hdc,clrNew);   \r
+                                       ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER | DT_SINGLELINE | DT_VCENTER);\r
+                                       ::SetTextColor(hdc,clrOld);\r
+                               }else\r
+                               {\r
+                                       ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER | DT_SINGLELINE | DT_VCENTER);\r
+                               }\r
                        }\r
 \r
                        \r
-                       ::MoveToEx(hdc,rt.left,rt.top,NULL);\r
-                       ::LineTo(hdc,rt.right,rt.top);\r
-                       ::LineTo(hdc,rt.right,rt.bottom);\r
-                       ::LineTo(hdc,rt.left,rt.bottom);\r
-                       ::LineTo(hdc,rt.left,rt.top);\r
+                       //::MoveToEx(hdc,rt.left,rt.top,NULL);\r
+                       //::LineTo(hdc,rt.right,rt.top);\r
+                       //::LineTo(hdc,rt.right,rt.bottom);\r
+                       //::LineTo(hdc,rt.left,rt.bottom);\r
+                       //::LineTo(hdc,rt.left,rt.top);\r
+\r
                                \r
-                       rt.left=rt.right+3;\r
+                       rt.left=rt.right+1;\r
                }\r
                if(brush)\r
                        ::DeleteObject(brush);\r
        }               \r
        rt.right=rect.right;\r
 \r
-       if (rItem.state & LVIS_SELECTED)\r
+       if (m_Theme.IsAppThemed() && m_bVista)\r
        {\r
-               COLORREF   clrOld   = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT));   \r
-               ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT);\r
-               ::SetTextColor(hdc,clrOld);   \r
-       }else\r
+               int txtState = LISS_NORMAL;\r
+               if (rItem.state & LVIS_SELECTED)\r
+                       txtState = LISS_SELECTED;\r
+\r
+               m_Theme.DrawText(hdc, LVP_LISTITEM, txtState, data->m_Subject, -1, DT_LEFT | DT_SINGLELINE | DT_VCENTER, 0, &rt);\r
+       }\r
+       else\r
        {\r
-               ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT);\r
+               if (rItem.state & LVIS_SELECTED)\r
+               {\r
+                       COLORREF   clrOld   = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT));   \r
+                       ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT | DT_SINGLELINE | DT_VCENTER);\r
+                       ::SetTextColor(hdc,clrOld);   \r
+               }else\r
+               {\r
+                       ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT | DT_SINGLELINE | DT_VCENTER);\r
+               }\r
        }\r
-       \r
 }\r
 \r
+static COLORREF blend(const COLORREF& col1, const COLORREF& col2, int amount = 128) {\r
+\r
+       // Returns ((256 - amount)*col1 + amount*col2) / 256;\r
+       return RGB(((256 - amount)*GetRValue(col1)   + amount*GetRValue(col2)  ) / 256,\r
+                     ((256 - amount)*GetGValue(col1) + amount*GetGValue(col2) ) / 256,\r
+                     ((256 - amount)*GetBValue(col1)  + amount*GetBValue(col2) ) / 256);\r
+}\r
+\r
+Gdiplus::Color GetGdiColor(COLORREF col)\r
+{\r
+       return Gdiplus::Color(GetRValue(col),GetGValue(col),GetBValue(col));\r
+}\r
 void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, int x2,\r
-                                      const COLORREF& col,int top\r
+                                      const COLORREF& col,const COLORREF& activeColor, int top\r
                                                                          )  \r
 {\r
        int h = laneHeight / 2;\r
@@ -467,12 +576,97 @@ void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, i
        #define P_270    m , 2 * h+top\r
        #define R_CENTER m - r, h - r+top, m - r+d, h - r+top+d\r
 \r
+\r
+       #define DELTA_UR_B 2*(x1 - m), 2*h +top \r
+       #define DELTA_UR_E 0*16, 90*16 +top  // -,\r
+\r
+       #define DELTA_DR_B 2*(x1 - m), 2*-h +top\r
+       #define DELTA_DR_E 270*16, 90*16 +top  // -'\r
+\r
+       #define DELTA_UL_B 2*(x2 - m), 2*h +top\r
+       #define DELTA_UL_E 90*16, 90*16 +top //  ,-\r
+\r
+       #define DELTA_DL_B 2*(x2 - m),2*-h +top \r
+       #define DELTA_DL_E 180*16, 90*16  //  '-\r
+\r
+       #define CENTER_UR x1, 2*h, 225\r
+       #define CENTER_DR x1, 0  , 135\r
+       #define CENTER_UL x2, 2*h, 315\r
+       #define CENTER_DL x2, 0  ,  45\r
+\r
+\r
+       Gdiplus::Graphics graphics( hdc );\r
+\r
+       // arc\r
+       switch (type) {\r
+       case Lanes::JOIN:\r
+       case Lanes::JOIN_R:\r
+       case Lanes::HEAD:\r
+       case Lanes::HEAD_R: \r
+       {\r
+               Gdiplus::LinearGradientBrush gradient(\r
+                                                               Gdiplus::Point(x1-2, h+top-2),\r
+                                                               Gdiplus::Point(P_270),\r
+                                                               GetGdiColor(activeColor),GetGdiColor(col));\r
+\r
+               \r
+               Gdiplus::Pen mypen(&gradient,2);\r
+               //Gdiplus::Pen mypen(Gdiplus::Color(0,0,0),2);\r
+               \r
+               //graphics.DrawRectangle(&mypen,x1-(x2-x1)/2,top+h, x2-x1,laneHeight);\r
+               graphics.DrawArc(&mypen,x1-(x2-x1)/2-1,top+h-1, x2-x1+1,laneHeight+1,270,90);\r
+               //graphics.DrawLine(&mypen,x1-1,h+top,P_270);\r
+\r
+               break;\r
+       }\r
+       case Lanes::JOIN_L: \r
+       {\r
+       \r
+               Gdiplus::Pen mypen(Gdiplus::Color(0,0,0),2);\r
+\r
+               \r
+               graphics.DrawArc(&mypen,x1,top+h, x2-x1,laneHeight,270,90);\r
+\r
+               break;\r
+       }\r
+       case Lanes::TAIL:\r
+       case Lanes::TAIL_R: \r
+       {\r
+               \r
+               Gdiplus::LinearGradientBrush gradient(\r
+                                                               Gdiplus::Point(x1-2, h+top-2),\r
+                                                               Gdiplus::Point(P_90),\r
+                                                               GetGdiColor(activeColor),GetGdiColor(col));\r
+\r
+               \r
+               Gdiplus::Pen mypen(&gradient,2);\r
+\r
+               graphics.DrawArc(&mypen,x1-(x2-x1)/2-1,top-h-1, x2-x1+1,laneHeight+1,0,90);\r
+\r
+\r
+#if 0\r
+               QConicalGradient gradient(CENTER_DR);\r
+               gradient.setColorAt(0.375, activeCol);\r
+               gradient.setColorAt(0.625, col);\r
+               myPen.setBrush(gradient);\r
+               p->setPen(myPen);\r
+               p->drawArc(P_CENTER, DELTA_DR);\r
+#endif\r
+               break;\r
+       }\r
+       default:\r
+               break;\r
+       }\r
+\r
+\r
        //static QPen myPen(Qt::black, 2); // fast path here\r
        CPen pen;\r
        pen.CreatePen(PS_SOLID,2,col);\r
        //myPen.setColor(col);\r
        HPEN oldpen=(HPEN)::SelectObject(hdc,(HPEN)pen);\r
 \r
+       Gdiplus::Pen myPen(GetGdiColor(col),2);\r
+\r
        //p->setPen(myPen);\r
 \r
        // vertical line\r
@@ -485,31 +679,33 @@ void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, i
        case Lanes::JOIN:\r
        case Lanes::JOIN_R:\r
        case Lanes::JOIN_L:\r
-               DrawLine(hdc,P_90,P_270);\r
+       case Lanes::CROSS:\r
+               //DrawLine(hdc,P_90,P_270);\r
+               graphics.DrawLine(&myPen,P_90,P_270);\r
                //p->drawLine(P_90, P_270);\r
                break;\r
-       case Lanes::HEAD:\r
-       case Lanes::HEAD_R:\r
        case Lanes::HEAD_L:\r
        case Lanes::BRANCH:\r
-               DrawLine(hdc,P_CENTER,P_270);\r
+               //DrawLine(hdc,P_CENTER,P_270);\r
+               graphics.DrawLine(&myPen,P_CENTER,P_270);\r
                //p->drawLine(P_CENTER, P_270);\r
                break;\r
-       case Lanes::TAIL:\r
-       case Lanes::TAIL_R:\r
        case Lanes::TAIL_L:\r
        case Lanes::INITIAL:\r
        case Lanes::BOUNDARY:\r
        case Lanes::BOUNDARY_C:\r
        case Lanes::BOUNDARY_R:\r
        case Lanes::BOUNDARY_L:\r
-               DrawLine(hdc,P_90, P_CENTER);\r
+               //DrawLine(hdc,P_90, P_CENTER);\r
+               graphics.DrawLine(&myPen,P_90,P_CENTER);\r
                //p->drawLine(P_90, P_CENTER);\r
                break;\r
        default:\r
                break;\r
        }\r
 \r
+       myPen.SetColor(GetGdiColor(activeColor));\r
+\r
        // horizontal line\r
        switch (type) {\r
        case Lanes::MERGE_FORK:\r
@@ -519,23 +715,22 @@ void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, i
        case Lanes::CROSS:\r
        case Lanes::CROSS_EMPTY:\r
        case Lanes::BOUNDARY_C:\r
-               DrawLine(hdc,P_180,P_0);\r
+               //DrawLine(hdc,P_180,P_0);\r
+               graphics.DrawLine(&myPen,P_180,P_0);\r
                //p->drawLine(P_180, P_0);\r
                break;\r
        case Lanes::MERGE_FORK_R:\r
-       case Lanes::JOIN_R:\r
-       case Lanes::HEAD_R:\r
-       case Lanes::TAIL_R:\r
        case Lanes::BOUNDARY_R:\r
-               DrawLine(hdc,P_180,P_CENTER);\r
+               //DrawLine(hdc,P_180,P_CENTER);\r
+               graphics.DrawLine(&myPen,P_180,P_CENTER);\r
                //p->drawLine(P_180, P_CENTER);\r
                break;\r
        case Lanes::MERGE_FORK_L:\r
-       case Lanes::JOIN_L:\r
        case Lanes::HEAD_L:\r
        case Lanes::TAIL_L:\r
        case Lanes::BOUNDARY_L:\r
-               DrawLine(hdc,P_CENTER,P_0);\r
+               //DrawLine(hdc,P_CENTER,P_0);\r
+               graphics.DrawLine(&myPen,P_CENTER,P_0);\r
                //p->drawLine(P_CENTER, P_0);\r
                break;\r
        default:\r
@@ -611,6 +806,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
@@ -629,16 +827,37 @@ void CGitLogListBase::DrawGraph(HDC hdc,CRect &rect,INT_PTR index)
 \r
        std::vector<int>& lanes=data->m_Lanes;\r
        UINT laneNum = lanes.size();\r
-       UINT mergeLane = 0;\r
+       UINT activeLane = 0;\r
        for (UINT i = 0; i < laneNum; i++)\r
                if (Lanes::isMerge(lanes[i])) {\r
-                       mergeLane = i;\r
+                       activeLane = i;\r
                        break;\r
                }\r
 \r
        int x1 = 0, x2 = 0;\r
        int maxWidth = rect.Width();\r
        int lw = 3 * rect.Height() / 4; //laneWidth() \r
+\r
+       COLORREF activeColor = m_LineColors[activeLane % Lanes::COLORS_NUM];\r
+       //if (opt.state & QStyle::State_Selected)\r
+       //      activeColor = blend(activeColor, opt.palette.highlightedText().color(), 208);\r
+       \r
+\r
+       for (unsigned int i = 0; i < laneNum && x2 < maxWidth; i++) \r
+       {\r
+\r
+               x1 = x2;\r
+               x2 += lw;\r
+\r
+               int ln = lanes[i];\r
+               if (ln == Lanes::EMPTY)\r
+                       continue;\r
+\r
+               COLORREF color = i == activeLane ? activeColor : m_LineColors[i % Lanes::COLORS_NUM];\r
+               paintGraphLane(hdc, rect.Height(),ln, x1+rect.left, x2+rect.left, color,activeColor, rect.top);\r
+       }\r
+\r
+#if 0\r
        for (UINT i = 0; i < laneNum && x2 < maxWidth; i++) {\r
 \r
                x1 = x2;\r
@@ -649,16 +868,16 @@ void CGitLogListBase::DrawGraph(HDC hdc,CRect &rect,INT_PTR index)
                        continue;\r
 \r
                UINT col = (  Lanes:: isHead(ln) ||Lanes:: isTail(ln) || Lanes::isJoin(ln)\r
-                           || ln ==Lanes:: CROSS_EMPTY) ? mergeLane : i;\r
+                           || ln ==Lanes:: CROSS_EMPTY) ? activeLane : i;\r
 \r
                if (ln == Lanes::CROSS) {\r
                        paintGraphLane(hdc, rect.Height(),Lanes::NOT_ACTIVE, x1, x2, m_LineColors[col % Lanes::COLORS_NUM],rect.top);\r
-                       paintGraphLane(hdc, rect.Height(),Lanes::CROSS, x1, x2, m_LineColors[mergeLane % Lanes::COLORS_NUM],rect.top);\r
+                       paintGraphLane(hdc, rect.Height(),Lanes::CROSS, x1, x2, m_LineColors[activeLane % Lanes::COLORS_NUM],rect.top);\r
                } else\r
                        paintGraphLane(hdc, rect.Height(),ln, x1, x2, m_LineColors[col % Lanes::COLORS_NUM],rect.top);\r
        }\r
+#endif\r
 \r
-       TRACE(_T("index %d %d\r\n"),index,data->m_Lanes.size());\r
 }\r
 \r
 void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
@@ -707,15 +926,39 @@ 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
-//                                     {\r
-//                                             SelectObject(pLVCD->nmcd.hdc, m_boldFont);\r
+//                                     \r
+                                       if (data->m_CommitHash == GIT_REV_ZERO)\r
+                                       {\r
+                                               //crText = GetSysColor(RGB(200,200,0));\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
+                                               *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;\r
+                                       }\r
                                }\r
                        }\r
                        if (m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
@@ -737,13 +980,23 @@ 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
+                                       if(pLVCD->iSubItem == 0)\r
+                                       {\r
+                                               CRect second;\r
+                                               GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem+1, LVIR_BOUNDS, second);\r
+                                               rect.right=second.left;\r
+                                       }\r
                                        \r
+                                       TRACE(_T("A Graphic left %d right %d\r\n"),rect.left,rect.right);\r
                                        FillBackGround(pLVCD->nmcd.hdc, (INT_PTR)pLVCD->nmcd.dwItemSpec,rect);\r
-                                       DrawGraph(pLVCD->nmcd.hdc,rect,pLVCD->nmcd.dwItemSpec);\r
+                                       \r
+                                       GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec);\r
+                                       if( data ->m_CommitHash != GIT_REV_ZERO)\r
+                                               DrawGraph(pLVCD->nmcd.hdc,rect,pLVCD->nmcd.dwItemSpec);\r
 \r
                                        *pResult = CDRF_SKIPDEFAULT;\r
                                        return;\r
@@ -756,12 +1009,12 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)
                                if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
                                {\r
                                        GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec);\r
-                                       if(!data->m_IsFull)\r
-                                       {\r
-                                               if(data->SafeFetchFullInfo(&g_Git))\r
-                                                       this->Invalidate();\r
-                                               TRACE(_T("Update ... %d\r\n"),pLVCD->nmcd.dwItemSpec);\r
-                                       }\r
+                                       //if(!data->m_IsFull)\r
+                                       //{\r
+                                               //if(data->SafeFetchFullInfo(&g_Git))\r
+                                               //      this->Invalidate();\r
+                                               //TRACE(_T("Update ... %d\r\n"),pLVCD->nmcd.dwItemSpec);\r
+                                       //}\r
 \r
                                        if(m_HashMap[data->m_CommitHash].size()!=0)\r
                                        {\r
@@ -776,7 +1029,8 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)
                                                return;\r
 \r
                                        }\r
-                               }\r
+\r
+                               }       \r
                        }\r
                        \r
                        if (pLVCD->iSubItem == 1)\r
@@ -798,6 +1052,7 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)
                                GitRev* pLogEntry = reinterpret_cast<GitRev *>(m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec));\r
                                CRect rect;\r
                                GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
+                               TRACE(_T("Action left %d right %d\r\n"),rect.left,rect.right);\r
                                // Get the selected state of the\r
                                // item being drawn.                                                    \r
 \r
@@ -809,7 +1064,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
@@ -859,7 +1114,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
@@ -867,6 +1129,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
@@ -882,8 +1151,10 @@ void CGitLogListBase::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult)
                        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
+               if (pLogEntry && pLogEntry->m_CommitHash != GIT_REV_ZERO)\r
+                       lstrcpyn(pItem->pszText,\r
+                               CAppUtils::FormatDateAndTime( pLogEntry->m_AuthorDate, m_DateFormat, true, m_bRelativeTimes ), \r
+                               pItem->cchTextMax);\r
                break;\r
                \r
        case 5:\r
@@ -981,33 +1252,34 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
        }\r
        //entry is selected, now show the popup menu\r
        CIconMenu popup;\r
+       CIconMenu submenu;\r
        if (popup.CreatePopupMenu())\r
        {\r
+\r
+               if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_PICK))\r
+                       popup.AppendMenuIcon(ID_REBASE_PICK,  IDS_REBASE_PICK,   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
                        {\r
-                               if (m_hasWC)\r
+                               if(pSelLogEntry->m_CommitHash != GIT_REV_ZERO)\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
@@ -1015,9 +1287,16 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
                                        // 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
+                               }else\r
+                               {\r
+                                       if(m_ContextMenuMask&GetContextMenuBit(ID_COMMIT))\r
+                                               popup.AppendMenuIcon(ID_COMMIT, IDS_LOG_POPUP_COMMIT, IDI_COMMIT);\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
@@ -1043,31 +1322,64 @@ 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(pSelLogEntry->m_CommitHash != GIT_REV_ZERO)\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
+               }\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
-               else if (GetSelectedCount() >= 2)\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
@@ -1078,6 +1390,39 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point)
                        if (bAddSeparator)\r
                                popup.AppendMenu(MF_SEPARATOR, NULL);\r
                }\r
+\r
+               if ( GetSelectedCount() >0 && pSelLogEntry->m_CommitHash != GIT_REV_ZERO)\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 || (IsSelectionContinuous() && GetSelectedCount() > 0))\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
@@ -1094,13 +1439,49 @@ 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
+\r
+               if(m_ContextMenuMask&GetContextMenuBit(ID_FINDENTRY))\r
+                       popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND);\r
+\r
+\r
+               if (GetSelectedCount() == 1)\r
+               {\r
+                       if(m_ContextMenuMask &GetContextMenuBit(ID_DELETE))\r
+                       {\r
+                               if( this->m_HashMap.find(pSelLogEntry->m_CommitHash) != m_HashMap.end() )\r
+                               {\r
+                                       CString str;\r
+                                       str.LoadString(IDS_DELETE_BRANCHTAG);\r
+                                       if( m_HashMap[pSelLogEntry->m_CommitHash].size() == 1 )\r
+                                       {\r
+                                               str+=_T(" ");\r
+                                               str+=m_HashMap[pSelLogEntry->m_CommitHash].at(0);\r
+                                               popup.AppendMenuIcon(ID_DELETE,str+_T("..."),IDI_DELETE);\r
+                                       }\r
+                                       else if( m_HashMap[pSelLogEntry->m_CommitHash].size() > 1 )\r
+                                       {\r
+                                               \r
+                                               submenu.CreatePopupMenu();\r
+                                               for(int i=0;i<m_HashMap[pSelLogEntry->m_CommitHash].size();i++)\r
+                                               {\r
+                                                       submenu.AppendMenuIcon(ID_DELETE+(i<<16),m_HashMap[pSelLogEntry->m_CommitHash][i]+_T("..."));\r
+                                               }\r
+\r
+                                               popup.AppendMenu(MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT) submenu.m_hMenu,str); \r
+\r
+                                       }\r
+                                       \r
+                               }\r
+                       }\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
@@ -1176,7 +1557,8 @@ void CGitLogListBase::CopySelectionToClipBoard(bool HashOnly)
                                sLogCopyText.Format(_T("%s: %s\r\n%s: %s\r\n%s: %s\r\n%s:\r\n%s\r\n----\r\n%s\r\n\r\n"),\r
                                        (LPCTSTR)sRev, pLogEntry->m_CommitHash,\r
                                        (LPCTSTR)sAuthor, (LPCTSTR)pLogEntry->m_AuthorName,\r
-                                       (LPCTSTR)sDate, (LPCTSTR)pLogEntry->m_AuthorDate.Format(_T("%Y-%m-%d %H:%M")),\r
+                                       (LPCTSTR)sDate, \r
+                                       (LPCTSTR)CAppUtils::FormatDateAndTime( pLogEntry->m_AuthorDate, m_DateFormat, true, m_bRelativeTimes ),\r
                                        (LPCTSTR)sMessage, pLogEntry->m_Subject+_T("\r\n")+pLogEntry->m_Body,\r
                                        (LPCTSTR)sPaths);\r
                                sClipdata +=  sLogCopyText;\r
@@ -1194,9 +1576,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
@@ -1317,22 +1710,30 @@ 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
 \r
        this->m_arShownList.RemoveAll();\r
 \r
-       for(int i=0;i<m_logEntries.size();i++)\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
@@ -1346,6 +1747,9 @@ int CGitLogListBase::FillGitShortLog()
        ClearText();\r
 \r
        this->m_logEntries.ClearAll();\r
+\r
+       m_LogCache.FetchCacheIndex(g_Git.m_CurrentDir);\r
+\r
     CTGitPath *path;\r
     if(this->m_Path.IsEmpty())\r
         path=NULL;\r
@@ -1355,20 +1759,40 @@ int CGitLogListBase::FillGitShortLog()
        CString hash;\r
        int mask;\r
        mask = CGit::LOG_INFO_ONLY_HASH | CGit::LOG_INFO_BOUNDARY;\r
-       if(this->m_bAllBranch)\r
-               mask |= CGit::LOG_INFO_ALL_BRANCH;\r
-\r
-       this->m_logEntries.ParserShortLog(path,hash,-1,mask);\r
+//     if(this->m_bAllBranch)\r
+       mask |= m_ShowMask;\r
        \r
+       if(m_bShowWC)\r
+               this->m_logEntries.insert(m_logEntries.begin(),this->m_wcRev);\r
+\r
+       this->m_logEntries.FetchShortLog(path,m_StartRef,-1,mask,m_bShowWC?1:0);\r
 \r
        //this->m_logEntries.ParserFromLog();\r
-       SetItemCountEx(this->m_logEntries.size());\r
+       if(IsInWorkingThread())\r
+       {\r
+               PostMessage(LVM_SETITEMCOUNT, (WPARAM) this->m_logEntries.size(),(LPARAM) LVSICF_NOINVALIDATEALL);\r
+       }\r
+       else\r
+       {\r
+               SetItemCountEx(this->m_logEntries.size());\r
+       }\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
+       for(unsigned int i=0;i<m_logEntries.size();i++)\r
+       {\r
+               if(i>0 || m_logEntries[i].m_CommitHash != GIT_REV_ZERO)\r
+                       m_logEntries[i].m_Subject=_T("parser...");\r
+\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
@@ -1413,13 +1837,12 @@ 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(CALLBACK_PROCESS *proc,void * data)\r
+int CGitLogListBase::FetchLogAsync(void * data)\r
 {\r
-       m_ProcCallBack=proc;\r
        m_ProcData=data;\r
        m_bExitThread=FALSE;\r
        InterlockedExchange(&m_bThreadRunning, TRUE);\r
@@ -1446,7 +1869,7 @@ void CGitLogListBase::GetTimeRange(CTime &oldest, CTime &latest)
        //CTime time;\r
        oldest=CTime::GetCurrentTime();\r
        latest=CTime(1971,1,2,0,0,0);\r
-       for(int i=0;i<m_logEntries.size();i++)\r
+       for(unsigned int i=0;i<m_logEntries.size();i++)\r
        {\r
                if(m_logEntries[i].m_AuthorDate.GetTime() < oldest.GetTime())\r
                        oldest = m_logEntries[i].m_AuthorDate.GetTime();\r
@@ -1457,11 +1880,177 @@ void CGitLogListBase::GetTimeRange(CTime &oldest, CTime &latest)
        }\r
 }\r
 \r
+//Helper class for FetchFullLogInfo()\r
+class CGitCall_FetchFullLogInfo : public CGitCall\r
+{\r
+public:\r
+       CGitCall_FetchFullLogInfo(CGitLogListBase* ploglist):m_ploglist(ploglist),m_CollectedCount(0){}\r
+       virtual bool OnOutputData(const BYTE* data, size_t size)\r
+       {\r
+               if(size==0)\r
+                       return m_ploglist->m_bExitThread;\r
+               //Add received data to byte collector\r
+               m_ByteCollector.append(data,size);\r
+\r
+               //Find loginfo endmarker\r
+               static const BYTE dataToFind[]={0,0,'#','<'};\r
+               int found=m_ByteCollector.findData(dataToFind,4);\r
+               if(found<0)\r
+                       return m_ploglist->m_bExitThread;//Not found\r
+               found+=2;//Position after loginfo end-marker\r
+\r
+               //Prepare data for OnLogInfo and call it\r
+               BYTE_VECTOR logInfo;\r
+               logInfo.append(&*m_ByteCollector.begin(),found);\r
+               OnLogInfo(logInfo);\r
+\r
+               //Remove loginfo from bytecollector\r
+               m_ByteCollector.erase(m_ByteCollector.begin(),m_ByteCollector.begin()+found);\r
+\r
+               return m_ploglist->m_bExitThread;\r
+       }\r
+       virtual void OnEnd()\r
+       {\r
+               //Rest should be a complete log line.\r
+               if(!m_ByteCollector.empty())\r
+                       OnLogInfo(m_ByteCollector);\r
+       }\r
+\r
+\r
+       void OnLogInfo(BYTE_VECTOR& logInfo)\r
+       {\r
+               GitRev fullRev;\r
+               fullRev.ParserFromLog(logInfo);\r
+               MAP_HASH_REV::iterator itRev=m_ploglist->m_logEntries.m_HashMap.find(fullRev.m_CommitHash);\r
+               if(itRev==m_ploglist->m_logEntries.m_HashMap.end())\r
+               {\r
+                       //Should not occur, only when Git-tree updated in the mean time. (Race condition)\r
+                       return;//Ignore\r
+               }\r
+               //Set updating\r
+               int rev=itRev->second;\r
+               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
+               if(InterlockedExchange(&revInVector->m_IsUpdateing,TRUE))\r
+                       return;//Cannot update this row now. Ignore.\r
+               TCHAR oldmark=revInVector->m_Mark;\r
+               GIT_REV_LIST oldlist=revInVector->m_ParentHash;\r
+//             CString oldhash=m_CommitHash;\r
+\r
+               //Parse new rev info\r
+               revInVector->ParserFromLog(logInfo);\r
+\r
+               if(oldmark!=0)\r
+                       revInVector->m_Mark=oldmark;  //parser full log will cause old mark overwrited. \r
+                                                              //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
+\r
+               //Notify listcontrol and update progress bar\r
+               ++m_CollectedCount;\r
+\r
+               ::PostMessage(m_ploglist->m_hWnd,MSG_LOADED,(WPARAM)rev,0);\r
+\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
+               ::PostMessage(m_ploglist->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent,0);\r
+       }\r
+\r
+       CGitLogListBase*        m_ploglist;\r
+       BYTE_VECTOR                     m_ByteCollector;\r
+       int                                     m_CollectedCount;\r
+\r
+};\r
+\r
+void CGitLogListBase::FetchFullLogInfo(CString &from, CString &to)\r
+{\r
+       CGitCall_FetchFullLogInfo fetcher(this);\r
+       int mask=\r
+               CGit::LOG_INFO_FULL_DIFF|\r
+               CGit::LOG_INFO_STAT|\r
+               CGit::LOG_INFO_FILESTATE|\r
+               CGit::LOG_INFO_DETECT_COPYRENAME|\r
+               CGit::LOG_INFO_SHOW_MERGEDFILE |\r
+               m_ShowMask;\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::FetchLastLogInfo()\r
+{\r
+       unsigned int updated=0;\r
+       int percent=0;\r
+       CRect rect;\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
+                               {\r
+                                       updated++;\r
+                               }\r
+                               m_LogCache.AddCacheEntry(m_logEntries[i]);\r
+\r
+                       }else\r
+                       {\r
+                               updated++;\r
+                               InterlockedExchange(&m_logEntries[i].m_IsUpdateing,FALSE);\r
+                               InterlockedExchange(&m_logEntries[i].m_IsFull,TRUE);\r
+                       }\r
+                       \r
+                       ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM)i,0);\r
+\r
+                       if(m_bExitThread)\r
+                       {\r
+                               InterlockedExchange(&m_bThreadRunning, FALSE);\r
+                               InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
+                               return;\r
+                       }                       \r
+               }\r
+       }\r
+}\r
+\r
 UINT CGitLogListBase::LogThread()\r
 {\r
 \r
-       if(m_ProcCallBack)\r
-               m_ProcCallBack(m_ProcData,GITLOG_START);\r
+//     if(m_ProcCallBack)\r
+//             m_ProcCallBack(m_ProcData,GITLOG_START);\r
+       ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_START,0);\r
 \r
        InterlockedExchange(&m_bThreadRunning, TRUE);\r
        InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
@@ -1473,18 +2062,79 @@ UINT CGitLogListBase::LogThread()
        //disable the "Get All" button while we're receiving\r
        //log messages.\r
 \r
-       CString temp;\r
-       temp.LoadString(IDS_PROGRESSWAIT);\r
-       ShowText(temp, true);\r
-\r
        FillGitShortLog();\r
        \r
-       \r
+       if(this->m_bExitThread)\r
+       {\r
+               InterlockedExchange(&m_bThreadRunning, FALSE);\r
+               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
+               if( i==0 && m_logEntries[i].m_CommitHash == GIT_REV_ZERO)\r
+               {\r
+                       m_logEntries[i].m_Files.Clear();\r
+                       m_logEntries[i].m_ParentHash.clear();\r
+                       m_logEntries[i].m_ParentHash.push_back(m_HeadHash);\r
+                       g_Git.GetCommitDiffList(m_logEntries[i].m_CommitHash,this->m_HeadHash,m_logEntries[i].m_Files);\r
+                       m_logEntries[i].m_Action =0;\r
+                       for(int j=0;j< m_logEntries[i].m_Files.GetCount();j++)\r
+                               m_logEntries[i].m_Action |= m_logEntries[i].m_Files[j].m_Action;\r
+                       \r
+                       m_logEntries[i].m_Body.Format(_T("%d files changed"),m_logEntries[i].m_Files.GetCount());\r
+                       ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM)0,0);\r
+                       continue;\r
+               }\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
+               ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM) i, 0);\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
+\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
-       ResizeAllListCtrlCols();\r
-       SetRedraw(true);\r
+//     SetRedraw(false);\r
+//     ResizeAllListCtrlCols();\r
+//     SetRedraw(true);\r
 \r
        if ( m_pStoreSelection )\r
        {\r
@@ -1503,42 +2153,17 @@ UINT CGitLogListBase::LogThread()
                        SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);\r
                }\r
        }\r
-       InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
+#endif\r
 \r
-       int index=0;\r
-       int updated=0;\r
-       int percent=0;\r
-       while(1)\r
-       {\r
-               for(int i=0;i<m_logEntries.size();i++)\r
-               {\r
-                       if(!m_logEntries.FetchFullInfo(i))\r
-                       {\r
-                               updated++;\r
-                       }\r
-                       \r
-                       percent=updated*98/m_logEntries.size() + GITLOG_START+1;\r
-                       if(percent == GITLOG_END)\r
-                               percent = GITLOG_END -1;\r
-                       \r
-                       if(m_ProcCallBack)\r
-                               m_ProcCallBack(m_ProcData,percent);\r
 \r
-                       if(m_bExitThread)\r
-                               break;\r
-               }\r
-               if(updated==m_logEntries.size())\r
-                       break;\r
-       }\r
 \r
+       //FetchFullLogInfo();\r
+       //FetchFullLogInfoOrig();\r
        //RefreshCursor();\r
        // make sure the filter is applied (if any) now, after we refreshed/fetched\r
        // the log messages\r
 \r
-       \r
-\r
-       if(m_ProcCallBack)\r
-               m_ProcCallBack(m_ProcData,GITLOG_END);\r
+       ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_END,0);\r
 \r
        InterlockedExchange(&m_bThreadRunning, FALSE);\r
 \r
@@ -1546,11 +2171,26 @@ UINT CGitLogListBase::LogThread()
 }\r
 \r
 void CGitLogListBase::Refresh()\r
-{\r
-       if(!m_bThreadRunning)\r
+{      \r
+       m_bExitThread=TRUE;\r
+       if(m_LoadingThread!=NULL)\r
        {\r
-               this->SetItemCountEx(0);\r
+               DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000);\r
+               if(ret == WAIT_TIMEOUT)\r
+                       TerminateThread();\r
+       }\r
+       \r
+       this->SetItemCountEx(0);\r
+       this->Clear();\r
+\r
+       //Update branch and Tag info\r
+       ReloadHashMap();\r
+       //Assume Thread have exited\r
+       //if(!m_bThreadRunning)\r
+       {\r
+               \r
                m_logEntries.clear();\r
+               m_bExitThread=FALSE;\r
                InterlockedExchange(&m_bThreadRunning, TRUE);\r
                InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
                if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
@@ -1662,7 +2302,7 @@ void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist)
                        }\r
                        if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_REVS))\r
                        {\r
-                               sRev.Format(_T("%ld"), m_logEntries[i].m_CommitHash);\r
+                               sRev.Format(_T("%s"), m_logEntries[i].m_CommitHash);\r
                                if (regex_search(wstring((LPCTSTR)sRev), pat, flags)&&IsEntryInDateRange(i))\r
                                {\r
                                        pShownlist->Add(&m_logEntries[i]);\r
@@ -1754,7 +2394,7 @@ void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist)
                        }\r
                        if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_REVS))\r
                        {\r
-                               sRev.Format(_T("%ld"), m_logEntries[i].m_CommitHash);\r
+                               sRev.Format(_T("%s"), m_logEntries[i].m_CommitHash);\r
                                if ((sRev.Find(find) >= 0)&&(IsEntryInDateRange(i)))\r
                                {\r
                                        pShownlist->Add(&m_logEntries[i]);\r
@@ -1790,6 +2430,7 @@ void CGitLogListBase::StartFilter()
        //ResizeAllListCtrlCols();\r
        SetRedraw(true);\r
        Invalidate();\r
+\r
 }\r
 void CGitLogListBase::RemoveFilter()\r
 {\r
@@ -1810,15 +2451,21 @@ 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
        SetItemCountEx(ShownCountWithStopped());\r
        RedrawItems(0, ShownCountWithStopped());\r
-       SetRedraw(false);\r
-       ResizeAllListCtrlCols();\r
-       SetRedraw(true);\r
+//     SetRedraw(false);\r
+//     ResizeAllListCtrlCols();\r
+//     SetRedraw(true);\r
 \r
        InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
 }\r
@@ -1826,12 +2473,80 @@ 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
+void CGitLogListBase::OnDestroy()\r
+{\r
+       // save the column widths to the registry\r
+       SaveColumnWidths();\r
 \r
+       if(this->m_bThreadRunning)\r
+       {\r
+               this->m_bExitThread=true;\r
+               DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000);\r
+               if(ret == WAIT_TIMEOUT)\r
+                       TerminateThread();\r
+       }\r
+       while(m_LogCache.SaveCache())\r
+       {\r
+               if(CMessageBox::Show(NULL,_T("Cannot Save Log Cache to Disk. To retry click yes. To give up click no."),_T("TortoiseGit"),\r
+                                                       MB_YESNO) == IDNO)\r
+                                                       break;\r
+       }\r
+       CHintListCtrl::OnDestroy();\r
+}\r
+\r
+LRESULT CGitLogListBase::OnLoad(WPARAM wParam,LPARAM lParam)\r
+{\r
+       CRect rect;\r
+       int i=(int)wParam;\r
+       this->GetItemRect(i,&rect,LVIR_BOUNDS);\r
+       this->InvalidateRect(rect);\r
+\r
+       if(this->GetItemState(i,LVIF_STATE) & LVIS_SELECTED)\r
+       {\r
+               int i=0;\r
+       }\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * Save column widths to the registry\r
+ */\r
+void CGitLogListBase::SaveColumnWidths()\r
+{\r
+       CHeaderCtrl* pHdrCtrl = (CHeaderCtrl*)(GetDlgItem(0));\r
+       if (pHdrCtrl)\r
+       {\r
+               int numcols = pHdrCtrl->GetItemCount();\r
+               for (int col = 0; col < numcols; col++)\r
+               {\r
+                       int width = GetColumnWidth( col );\r
+                       CString regentry;\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