X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=src%2FTortoiseProc%2FGitLogListBase.cpp;h=9416d79409ec77c7024ab78674f06744224bdca6;hb=fcc031b5907ddbfe5e9f9f8d862cd4e14d605e67;hp=a805e59d013cec3e6d8b24753fc4c7932f435acf;hpb=8ceb139df526d440513caa6270bce4374482cba2;p=tortoisegit%2FTortoiseGitJp.git diff --git a/src/TortoiseProc/GitLogListBase.cpp b/src/TortoiseProc/GitLogListBase.cpp index a805e59..9416d79 100644 --- a/src/TortoiseProc/GitLogListBase.cpp +++ b/src/TortoiseProc/GitLogListBase.cpp @@ -57,6 +57,9 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl() , m_bStrictStopped(false) , m_pStoreSelection(NULL) , m_nSelectedFilter(LOGFILTER_ALL) + , m_bVista(false) + , m_bShowWC(false) + , m_logEntries(&m_LogCache) { // use the default GUI font, create a copy of it and // change the copy to BOLD (leave the rest of the font @@ -71,8 +74,12 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl() m_IsIDReplaceAction=FALSE; - m_wcRev.m_CommitHash=GIT_REV_ZERO; - m_wcRev.m_Subject=_T("Working Copy"); + m_wcRev.m_CommitHash.Empty(); + m_wcRev.m_Subject=_T("Working dir changes"); + m_wcRev.m_ParentHash.clear(); + m_wcRev.m_Mark=_T('-'); + m_wcRev.m_IsUpdateing=FALSE; + m_wcRev.m_IsFull = TRUE; m_hModifiedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONMODIFIED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); m_hReplacedIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_ACTIONREPLACED), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); @@ -83,6 +90,7 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl() g_Git.GetMapHashToFriendName(m_HashMap); m_CurrentBranch=g_Git.GetCurrentBranch(); + this->m_HeadHash=g_Git.GetHash(CString(_T("HEAD"))).Left(40); m_From=CTime(1970,1,2,0,0,0); m_To=CTime::GetCurrentTime(); @@ -90,6 +98,9 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl() m_LoadingThread = NULL; m_bExitThread=FALSE; + m_IsOldFirst = FALSE; + m_IsRebaseReplaceGraph = FALSE; + for(int i=0;i= 0x0600); + + m_ColumnRegKey=_T("log"); } CGitLogListBase::~CGitLogListBase() @@ -147,8 +173,25 @@ BEGIN_MESSAGE_MAP(CGitLogListBase, CHintListCtrl) ON_WM_CREATE() ON_WM_DESTROY() ON_MESSAGE(MSG_LOADED,OnLoad) + ON_WM_MEASUREITEM() + ON_WM_MEASUREITEM_REFLECT() END_MESSAGE_MAP() +void CGitLogListBase::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + // TODO: ÔÚ´ËÌí¼ÓÏûÏ¢´¦Àí³ÌÐò´úÂëºÍ/»òµ÷ÓÃĬÈÏÖµ + + CListCtrl::OnMeasureItem(nIDCtl, lpMeasureItemStruct); +} + +void CGitLogListBase::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + //if (m_nRowHeight>0) + { + lpMeasureItemStruct->itemHeight = 50; + } +} + int CGitLogListBase:: OnCreate(LPCREATESTRUCT lpCreateStruct) { PreSubclassWindow(); @@ -159,7 +202,9 @@ void CGitLogListBase::PreSubclassWindow() { SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES); // load the icons for the action columns - m_Theme.SetWindowTheme(GetSafeHwnd(), L"Explorer", NULL); +// m_Theme.Open(m_hWnd, L"ListView"); + m_Theme.Open(m_hWnd, L"Explorer::ListView;ListView"); + m_Theme.SetWindowTheme(m_hWnd, L"Explorer", NULL); CHintListCtrl::PreSubclassWindow(); } @@ -167,12 +212,20 @@ void CGitLogListBase::InsertGitColumn() { CString temp; - int c = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1; + int c = GetHeaderCtrl()->GetItemCount()-1; while (c>=0) DeleteColumn(c--); temp.LoadString(IDS_LOG_GRAPH); + if(m_IsRebaseReplaceGraph) + { + temp=_T("Rebase"); + } + else + { + temp.LoadString(IDS_LOG_GRAPH); + } InsertColumn(this->LOGLIST_GRAPH, temp); #if 0 @@ -236,7 +289,7 @@ void CGitLogListBase::ResizeAllListCtrlCols() { // get width for this col last time from registry CString regentry; - regentry.Format( _T("Software\\TortoiseGit\\log\\ColWidth%d"), col); + regentry.Format( _T("Software\\TortoiseGit\\%s\\ColWidth%d"),m_ColumnRegKey, col); CRegDWORD regwidth(regentry, 0); int cx = regwidth; if ( cx == 0 ) @@ -278,6 +331,7 @@ BOOL CGitLogListBase::GetShortName(CString ref, CString &shortname,CString prefi } return FALSE; } + void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect) { // HBRUSH brush; @@ -288,9 +342,12 @@ void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect) rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; GetItem(&rItem); + GitRev* pLogEntry = (GitRev*)m_arShownList.GetAt(Index); + HBRUSH brush = NULL; + + if (m_Theme.IsAppThemed() && m_bVista) { - m_Theme.Open(m_hWnd, L"Explorer"); int state = LISS_NORMAL; if (rItem.state & LVIS_SELECTED) { @@ -301,34 +358,34 @@ void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect) } else { -#if 0 - if (pLogEntry->bCopiedSelf) - { - // unfortunately, the pLVCD->nmcd.uItemState does not contain valid - // information at this drawing stage. But we can check the whether the - // previous stage changed the background color of the item - if (pLVCD->clrTextBk == GetSysColor(COLOR_MENU)) - { - HBRUSH brush; - brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU)); - if (brush) - { - ::FillRect(pLVCD->nmcd.hdc, &rect, brush); - ::DeleteObject(brush); - } - } - } -#endif + if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH) + brush = ::CreateSolidBrush(RGB(156,156,156)); + else if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_EDIT) + brush = ::CreateSolidBrush(RGB(200,200,128)); } - if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTDETAIL, state)) - m_Theme.DrawParentBackground(m_hWnd, hdc, &rect); + if (brush != NULL) + { + ::FillRect(hdc, &rect, brush); + ::DeleteObject(brush); + } + else + { + if (m_Theme.IsBackgroundPartiallyTransparent(LVP_LISTITEM, state)) + m_Theme.DrawParentBackground(m_hWnd, hdc, &rect); - m_Theme.DrawBackground(hdc, LVP_LISTDETAIL, state, &rect, NULL); + CRect rectDraw = rect; + if(rItem.state & LVIS_SELECTED) + rectDraw.InflateRect(1,0); + else + rectDraw.InflateRect(1,1); + + m_Theme.DrawBackground(hdc, LVP_LISTITEM, state, rectDraw, &rect); + } } else { - HBRUSH brush; + if (rItem.state & LVIS_SELECTED) { if (::GetFocus() == m_hWnd) @@ -341,6 +398,11 @@ void CGitLogListBase::FillBackGround(HDC hdc, int Index,CRect &rect) //if (pLogEntry->bCopiedSelf) // brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU)); //else + if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH) + brush = ::CreateSolidBrush(RGB(156,156,156)); + else if(pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_EDIT) + brush = ::CreateSolidBrush(RGB(200,200,128)); + else brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW)); } if (brush == NULL) @@ -369,24 +431,40 @@ void CGitLogListBase::DrawTagBranch(HDC hdc,CRect &rect,INT_PTR index) str=m_HashMap[data->m_CommitHash][i]; CString shortname; - HBRUSH brush=0; - shortname=_T(""); + HBRUSH brush = 0; + shortname = _T(""); + COLORREF colRef = 0; + + //Determine label color if(GetShortName(str,shortname,_T("refs/heads/"))) { if( shortname == m_CurrentBranch ) - brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::CurrentBranch)); + colRef = m_Colors.GetColor(CColors::CurrentBranch); else - brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::LocalBranch)); + colRef = m_Colors.GetColor(CColors::LocalBranch); }else if(GetShortName(str,shortname,_T("refs/remotes/"))) { - brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::RemoteBranch)); + colRef = m_Colors.GetColor(CColors::RemoteBranch); } else if(GetShortName(str,shortname,_T("refs/tags/"))) { - brush = ::CreateSolidBrush(m_Colors.GetColor(CColors::Tag)); + colRef = m_Colors.GetColor(CColors::Tag); + } + else if(GetShortName(str,shortname,_T("refs/stash"))) + { + colRef = m_Colors.GetColor(CColors::Stash); + shortname=_T("stash"); } + //When row selected, ajust label color + if (!(m_Theme.IsAppThemed() && m_bVista)) + if (rItem.state & LVIS_SELECTED) + colRef = CColors::MixColors(colRef, ::GetSysColor(COLOR_HIGHLIGHT), 150); + + brush = ::CreateSolidBrush(colRef); + + if(!shortname.IsEmpty()) { SIZE size; @@ -394,46 +472,97 @@ void CGitLogListBase::DrawTagBranch(HDC hdc,CRect &rect,INT_PTR index) GetTextExtentPoint32(hdc, shortname,shortname.GetLength(),&size); rt.SetRect(rt.left,rt.top,rt.left+size.cx,rt.bottom); - rt.right+=4; + rt.right+=8; + + //Fill interior of ref label ::FillRect(hdc, &rt, brush); - if (rItem.state & LVIS_SELECTED) + + //Draw edge of label + CDC W_Dc; + W_Dc.Attach(hdc); + + CRect rectEdge = rt; + + W_Dc.Draw3dRect(rectEdge, m_Colors.Lighten(colRef,100), m_Colors.Darken(colRef,100)); + rectEdge.DeflateRect(1,1); + W_Dc.Draw3dRect(rectEdge, m_Colors.Lighten(colRef,50), m_Colors.Darken(colRef,50)); + + W_Dc.Detach(); + + //Draw text inside label + if (m_Theme.IsAppThemed() && m_bVista) { - COLORREF clrOld = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT)); - ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER); - ::SetTextColor(hdc,clrOld); - }else + int txtState = LISS_NORMAL; + if (rItem.state & LVIS_SELECTED) + txtState = LISS_SELECTED; + + m_Theme.DrawText(hdc, LVP_LISTITEM, txtState, shortname, -1, DT_CENTER | DT_SINGLELINE | DT_VCENTER, 0, &rt); + } + else { - ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER); + if (rItem.state & LVIS_SELECTED) + { + COLORREF clrNew = ::GetSysColor(COLOR_HIGHLIGHTTEXT); + COLORREF clrOld = ::SetTextColor(hdc,clrNew); + ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER | DT_SINGLELINE | DT_VCENTER); + ::SetTextColor(hdc,clrOld); + }else + { + ::DrawText(hdc,shortname,shortname.GetLength(),&rt,DT_CENTER | DT_SINGLELINE | DT_VCENTER); + } } - ::MoveToEx(hdc,rt.left,rt.top,NULL); - ::LineTo(hdc,rt.right,rt.top); - ::LineTo(hdc,rt.right,rt.bottom); - ::LineTo(hdc,rt.left,rt.bottom); - ::LineTo(hdc,rt.left,rt.top); + //::MoveToEx(hdc,rt.left,rt.top,NULL); + //::LineTo(hdc,rt.right,rt.top); + //::LineTo(hdc,rt.right,rt.bottom); + //::LineTo(hdc,rt.left,rt.bottom); + //::LineTo(hdc,rt.left,rt.top); + - rt.left=rt.right+3; + rt.left=rt.right+1; } if(brush) ::DeleteObject(brush); } rt.right=rect.right; - if (rItem.state & LVIS_SELECTED) + if (m_Theme.IsAppThemed() && m_bVista) { - COLORREF clrOld = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT)); - ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT); - ::SetTextColor(hdc,clrOld); - }else + int txtState = LISS_NORMAL; + if (rItem.state & LVIS_SELECTED) + txtState = LISS_SELECTED; + + m_Theme.DrawText(hdc, LVP_LISTITEM, txtState, data->m_Subject, -1, DT_LEFT | DT_SINGLELINE | DT_VCENTER, 0, &rt); + } + else { - ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT); + if (rItem.state & LVIS_SELECTED) + { + COLORREF clrOld = ::SetTextColor(hdc,::GetSysColor(COLOR_HIGHLIGHTTEXT)); + ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT | DT_SINGLELINE | DT_VCENTER); + ::SetTextColor(hdc,clrOld); + }else + { + ::DrawText(hdc,data->m_Subject,data->m_Subject.GetLength(),&rt,DT_LEFT | DT_SINGLELINE | DT_VCENTER); + } } - } +static COLORREF blend(const COLORREF& col1, const COLORREF& col2, int amount = 128) { + + // Returns ((256 - amount)*col1 + amount*col2) / 256; + return RGB(((256 - amount)*GetRValue(col1) + amount*GetRValue(col2) ) / 256, + ((256 - amount)*GetGValue(col1) + amount*GetGValue(col2) ) / 256, + ((256 - amount)*GetBValue(col1) + amount*GetBValue(col2) ) / 256); +} + +Gdiplus::Color GetGdiColor(COLORREF col) +{ + return Gdiplus::Color(GetRValue(col),GetGValue(col),GetBValue(col)); +} void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, int x2, - const COLORREF& col,int top + const COLORREF& col,const COLORREF& activeColor, int top ) { int h = laneHeight / 2; @@ -448,12 +577,97 @@ void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, i #define P_270 m , 2 * h+top #define R_CENTER m - r, h - r+top, m - r+d, h - r+top+d + + #define DELTA_UR_B 2*(x1 - m), 2*h +top + #define DELTA_UR_E 0*16, 90*16 +top // -, + + #define DELTA_DR_B 2*(x1 - m), 2*-h +top + #define DELTA_DR_E 270*16, 90*16 +top // -' + + #define DELTA_UL_B 2*(x2 - m), 2*h +top + #define DELTA_UL_E 90*16, 90*16 +top // ,- + + #define DELTA_DL_B 2*(x2 - m),2*-h +top + #define DELTA_DL_E 180*16, 90*16 // '- + + #define CENTER_UR x1, 2*h, 225 + #define CENTER_DR x1, 0 , 135 + #define CENTER_UL x2, 2*h, 315 + #define CENTER_DL x2, 0 , 45 + + + Gdiplus::Graphics graphics( hdc ); + + // arc + switch (type) { + case Lanes::JOIN: + case Lanes::JOIN_R: + case Lanes::HEAD: + case Lanes::HEAD_R: + { + Gdiplus::LinearGradientBrush gradient( + Gdiplus::Point(x1-2, h+top-2), + Gdiplus::Point(P_270), + GetGdiColor(activeColor),GetGdiColor(col)); + + + Gdiplus::Pen mypen(&gradient,2); + //Gdiplus::Pen mypen(Gdiplus::Color(0,0,0),2); + + //graphics.DrawRectangle(&mypen,x1-(x2-x1)/2,top+h, x2-x1,laneHeight); + graphics.DrawArc(&mypen,x1-(x2-x1)/2-1,top+h-1, x2-x1+1,laneHeight+1,270,90); + //graphics.DrawLine(&mypen,x1-1,h+top,P_270); + + break; + } + case Lanes::JOIN_L: + { + + Gdiplus::Pen mypen(Gdiplus::Color(0,0,0),2); + + + graphics.DrawArc(&mypen,x1,top+h, x2-x1,laneHeight,270,90); + + break; + } + case Lanes::TAIL: + case Lanes::TAIL_R: + { + + Gdiplus::LinearGradientBrush gradient( + Gdiplus::Point(x1-2, h+top-2), + Gdiplus::Point(P_90), + GetGdiColor(activeColor),GetGdiColor(col)); + + + Gdiplus::Pen mypen(&gradient,2); + + graphics.DrawArc(&mypen,x1-(x2-x1)/2-1,top-h-1, x2-x1+1,laneHeight+1,0,90); + + +#if 0 + QConicalGradient gradient(CENTER_DR); + gradient.setColorAt(0.375, activeCol); + gradient.setColorAt(0.625, col); + myPen.setBrush(gradient); + p->setPen(myPen); + p->drawArc(P_CENTER, DELTA_DR); +#endif + break; + } + default: + break; + } + + //static QPen myPen(Qt::black, 2); // fast path here CPen pen; pen.CreatePen(PS_SOLID,2,col); //myPen.setColor(col); HPEN oldpen=(HPEN)::SelectObject(hdc,(HPEN)pen); + Gdiplus::Pen myPen(GetGdiColor(col),2); + //p->setPen(myPen); // vertical line @@ -466,31 +680,33 @@ void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, i case Lanes::JOIN: case Lanes::JOIN_R: case Lanes::JOIN_L: - DrawLine(hdc,P_90,P_270); + case Lanes::CROSS: + //DrawLine(hdc,P_90,P_270); + graphics.DrawLine(&myPen,P_90,P_270); //p->drawLine(P_90, P_270); break; - case Lanes::HEAD: - case Lanes::HEAD_R: case Lanes::HEAD_L: case Lanes::BRANCH: - DrawLine(hdc,P_CENTER,P_270); + //DrawLine(hdc,P_CENTER,P_270); + graphics.DrawLine(&myPen,P_CENTER,P_270); //p->drawLine(P_CENTER, P_270); break; - case Lanes::TAIL: - case Lanes::TAIL_R: case Lanes::TAIL_L: case Lanes::INITIAL: case Lanes::BOUNDARY: case Lanes::BOUNDARY_C: case Lanes::BOUNDARY_R: case Lanes::BOUNDARY_L: - DrawLine(hdc,P_90, P_CENTER); + //DrawLine(hdc,P_90, P_CENTER); + graphics.DrawLine(&myPen,P_90,P_CENTER); //p->drawLine(P_90, P_CENTER); break; default: break; } + myPen.SetColor(GetGdiColor(activeColor)); + // horizontal line switch (type) { case Lanes::MERGE_FORK: @@ -500,23 +716,22 @@ void CGitLogListBase::paintGraphLane(HDC hdc, int laneHeight,int type, int x1, i case Lanes::CROSS: case Lanes::CROSS_EMPTY: case Lanes::BOUNDARY_C: - DrawLine(hdc,P_180,P_0); + //DrawLine(hdc,P_180,P_0); + graphics.DrawLine(&myPen,P_180,P_0); //p->drawLine(P_180, P_0); break; case Lanes::MERGE_FORK_R: - case Lanes::JOIN_R: - case Lanes::HEAD_R: - case Lanes::TAIL_R: case Lanes::BOUNDARY_R: - DrawLine(hdc,P_180,P_CENTER); + //DrawLine(hdc,P_180,P_CENTER); + graphics.DrawLine(&myPen,P_180,P_CENTER); //p->drawLine(P_180, P_CENTER); break; case Lanes::MERGE_FORK_L: - case Lanes::JOIN_L: case Lanes::HEAD_L: case Lanes::TAIL_L: case Lanes::BOUNDARY_L: - DrawLine(hdc,P_CENTER,P_0); + //DrawLine(hdc,P_CENTER,P_0); + graphics.DrawLine(&myPen,P_CENTER,P_0); //p->drawLine(P_CENTER, P_0); break; default: @@ -592,6 +807,9 @@ void CGitLogListBase::DrawGraph(HDC hdc,CRect &rect,INT_PTR index) //todo unfinished // return; GitRev* data = (GitRev*)m_arShownList.GetAt(index); + if(data->m_CommitHash.IsEmpty()) + return; + CRect rt=rect; LVITEM rItem; SecureZeroMemory(&rItem, sizeof(LVITEM)); @@ -610,16 +828,37 @@ void CGitLogListBase::DrawGraph(HDC hdc,CRect &rect,INT_PTR index) std::vector& lanes=data->m_Lanes; UINT laneNum = lanes.size(); - UINT mergeLane = 0; + UINT activeLane = 0; for (UINT i = 0; i < laneNum; i++) if (Lanes::isMerge(lanes[i])) { - mergeLane = i; + activeLane = i; break; } int x1 = 0, x2 = 0; int maxWidth = rect.Width(); int lw = 3 * rect.Height() / 4; //laneWidth() + + COLORREF activeColor = m_LineColors[activeLane % Lanes::COLORS_NUM]; + //if (opt.state & QStyle::State_Selected) + // activeColor = blend(activeColor, opt.palette.highlightedText().color(), 208); + + + for (unsigned int i = 0; i < laneNum && x2 < maxWidth; i++) + { + + x1 = x2; + x2 += lw; + + int ln = lanes[i]; + if (ln == Lanes::EMPTY) + continue; + + COLORREF color = i == activeLane ? activeColor : m_LineColors[i % Lanes::COLORS_NUM]; + paintGraphLane(hdc, rect.Height(),ln, x1+rect.left, x2+rect.left, color,activeColor, rect.top); + } + +#if 0 for (UINT i = 0; i < laneNum && x2 < maxWidth; i++) { x1 = x2; @@ -630,16 +869,16 @@ void CGitLogListBase::DrawGraph(HDC hdc,CRect &rect,INT_PTR index) continue; UINT col = ( Lanes:: isHead(ln) ||Lanes:: isTail(ln) || Lanes::isJoin(ln) - || ln ==Lanes:: CROSS_EMPTY) ? mergeLane : i; + || ln ==Lanes:: CROSS_EMPTY) ? activeLane : i; if (ln == Lanes::CROSS) { paintGraphLane(hdc, rect.Height(),Lanes::NOT_ACTIVE, x1, x2, m_LineColors[col % Lanes::COLORS_NUM],rect.top); - paintGraphLane(hdc, rect.Height(),Lanes::CROSS, x1, x2, m_LineColors[mergeLane % Lanes::COLORS_NUM],rect.top); + paintGraphLane(hdc, rect.Height(),Lanes::CROSS, x1, x2, m_LineColors[activeLane % Lanes::COLORS_NUM],rect.top); } else paintGraphLane(hdc, rect.Height(),ln, x1, x2, m_LineColors[col % Lanes::COLORS_NUM],rect.top); } +#endif - TRACE(_T("index %d %d\r\n"),index,data->m_Lanes.size()); } void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult) @@ -688,15 +927,39 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult) if (data->bCopies) crText = m_Colors.GetColor(CColors::Modified); #endif + if (data->m_Action& (CTGitPath::LOGACTIONS_REBASE_DONE| CTGitPath::LOGACTIONS_REBASE_SKIP) ) + crText = RGB(128,128,128); + + if(data->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH) + pLVCD->clrTextBk = RGB(156,156,156); + else if(data->m_Action&CTGitPath::LOGACTIONS_REBASE_EDIT) + pLVCD->clrTextBk = RGB(200,200,128); + else + pLVCD->clrTextBk = ::GetSysColor(COLOR_WINDOW); + + if(data->m_Action&CTGitPath::LOGACTIONS_REBASE_CURRENT) + { + SelectObject(pLVCD->nmcd.hdc, m_boldFont); + *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT; + } + + if(data->m_CommitHash.ToString() == m_HeadHash) + { + SelectObject(pLVCD->nmcd.hdc, m_boldFont); + *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT; + } + // if ((data->childStackDepth)||(m_mergedRevs.find(data->Rev) != m_mergedRevs.end())) // crText = GetSysColor(COLOR_GRAYTEXT); -// if (data->Rev == m_wcRev) -// { -// SelectObject(pLVCD->nmcd.hdc, m_boldFont); +// + if (data->m_CommitHash.IsEmpty()) + { + //crText = GetSysColor(RGB(200,200,0)); + //SelectObject(pLVCD->nmcd.hdc, m_boldFont); // We changed the font, so we're returning CDRF_NEWFONT. This // tells the control to recalculate the extent of the text. -// *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT; -// } + *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT; + } } } if (m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec) @@ -718,13 +981,23 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult) if (pLVCD->iSubItem == LOGLIST_GRAPH) { - if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec) + if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec && (!this->m_IsRebaseReplaceGraph) ) { CRect rect; GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect); + if(pLVCD->iSubItem == 0) + { + CRect second; + GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem+1, LVIR_BOUNDS, second); + rect.right=second.left; + } + TRACE(_T("A Graphic left %d right %d\r\n"),rect.left,rect.right); FillBackGround(pLVCD->nmcd.hdc, (INT_PTR)pLVCD->nmcd.dwItemSpec,rect); - DrawGraph(pLVCD->nmcd.hdc,rect,pLVCD->nmcd.dwItemSpec); + + GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec); + if( !data ->m_CommitHash.IsEmpty()) + DrawGraph(pLVCD->nmcd.hdc,rect,pLVCD->nmcd.dwItemSpec); *pResult = CDRF_SKIPDEFAULT; return; @@ -757,7 +1030,8 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult) return; } - } + + } } if (pLVCD->iSubItem == 1) @@ -779,6 +1053,7 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult) GitRev* pLogEntry = reinterpret_cast(m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec)); CRect rect; GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect); + TRACE(_T("Action left %d right %d\r\n"),rect.left,rect.right); // Get the selected state of the // item being drawn. @@ -790,7 +1065,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); nIcons++; - if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_ADDED) + if (pLogEntry->m_Action & (CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_COPY) ) ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hAddedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL); nIcons++; @@ -840,7 +1115,14 @@ void CGitLogListBase::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult) pLogEntry = reinterpret_cast(m_arShownList.GetAt(pItem->iItem)); CString temp; - temp.Format(_T("%d"),m_arShownList.GetCount()-pItem->iItem); + if(m_IsOldFirst) + { + temp.Format(_T("%d"),pItem->iItem+1); + + }else + { + temp.Format(_T("%d"),m_arShownList.GetCount()-pItem->iItem); + } // Which column? switch (pItem->iSubItem) @@ -848,6 +1130,13 @@ void CGitLogListBase::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult) case this->LOGLIST_GRAPH: //Graphic if (pLogEntry) { + if(this->m_IsRebaseReplaceGraph) + { + CTGitPath path; + path.m_Action=pLogEntry->m_Action&CTGitPath::LOGACTIONS_REBASE_MODE_MASK; + + lstrcpyn(pItem->pszText,path.GetActionName(), pItem->cchTextMax); + } } break; case this->LOGLIST_ACTION: //action -- no text in the column @@ -863,7 +1152,7 @@ void CGitLogListBase::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult) lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorName, pItem->cchTextMax); break; case this->LOGLIST_DATE: //Date - if (pLogEntry) + if (!pLogEntry && pLogEntry->m_CommitHash.IsEmpty()) lstrcpyn(pItem->pszText, CAppUtils::FormatDateAndTime( pLogEntry->m_AuthorDate, m_DateFormat, true, m_bRelativeTimes ), pItem->cchTextMax); @@ -964,33 +1253,34 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point) } //entry is selected, now show the popup menu CIconMenu popup; + CIconMenu submenu; if (popup.CreatePopupMenu()) { + + if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_PICK)) + popup.AppendMenuIcon(ID_REBASE_PICK, IDS_REBASE_PICK, IDI_PICK); + + if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_SQUASH)) + popup.AppendMenuIcon(ID_REBASE_SQUASH,IDS_REBASE_SQUASH, IDI_SQUASH); + + if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_EDIT)) + popup.AppendMenuIcon(ID_REBASE_EDIT, IDS_REBASE_EDIT, IDI_EDIT); + + if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_SKIP)) + popup.AppendMenuIcon(ID_REBASE_SKIP, IDS_REBASE_SKIP, IDI_SKIP); + + if(m_ContextMenuMask&(GetContextMenuBit(ID_REBASE_SKIP)|GetContextMenuBit(ID_REBASE_EDIT)| + GetContextMenuBit(ID_REBASE_SQUASH)|GetContextMenuBit(ID_REBASE_PICK))) + popup.AppendMenu(MF_SEPARATOR, NULL); + if (GetSelectedCount() == 1) { -#if 0 - if (!m_path.IsDirectory()) - { - if (m_hasWC) - { - popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF); - popup.AppendMenuIcon(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME); - } - popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF); - popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF); - popup.AppendMenu(MF_SEPARATOR, NULL); - popup.AppendMenuIcon(ID_SAVEAS, IDS_LOG_POPUP_SAVE, IDI_SAVEAS); - popup.AppendMenuIcon(ID_OPEN, IDS_LOG_POPUP_OPEN, IDI_OPEN); - popup.AppendMenuIcon(ID_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN); - popup.AppendMenuIcon(ID_BLAME, IDS_LOG_POPUP_BLAME, IDI_BLAME); - popup.AppendMenu(MF_SEPARATOR, NULL); - } - else -#endif + { - if (m_hasWC) + if( !pSelLogEntry->m_CommitHash.IsEmpty()) { - popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF); + if(m_ContextMenuMask&GetContextMenuBit(ID_COMPARE)) + popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF); // TODO: // TortoiseMerge could be improved to take a /blame switch // and then not 'cat' the files from a unified diff but @@ -998,9 +1288,16 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point) // But until that's implemented, the context menu entry for // this feature is commented out. //popup.AppendMenu(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME); + }else + { + if(m_ContextMenuMask&GetContextMenuBit(ID_COMMIT)) + popup.AppendMenuIcon(ID_COMMIT, IDS_LOG_POPUP_COMMIT, IDI_COMMIT); } - popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF); - popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF); + if(m_ContextMenuMask&GetContextMenuBit(ID_GNUDIFF1)) + popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF); + + if(m_ContextMenuMask&GetContextMenuBit(ID_COMPAREWITHPREVIOUS)) + popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF); //popup.AppendMenuIcon(ID_BLAMEWITHPREVIOUS, IDS_LOG_POPUP_BLAMEWITHPREVIOUS, IDI_BLAME); popup.AppendMenu(MF_SEPARATOR, NULL); } @@ -1026,31 +1323,64 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point) //if (m_hasWC) // popup.AppendMenuIcon(ID_MERGEREV, IDS_LOG_POPUP_MERGEREV, IDI_MERGE); - CString str; - str.Format(_T("Reset %s to this"),g_Git.GetCurrentBranch()); - popup.AppendMenuIcon(ID_RESET,str,IDI_REVERT); - popup.AppendMenuIcon(ID_SWITCHTOREV, _T("Switch/Checkout to this") , IDI_SWITCH); - popup.AppendMenuIcon(ID_CREATE_BRANCH, _T("Create Branch at this version") , IDI_COPY); - popup.AppendMenuIcon(ID_CREATE_TAG, _T("Create Tag at this version"), IDI_COPY); - popup.AppendMenuIcon(ID_CHERRY_PICK, _T("Cherry Pick this version"), IDI_EXPORT); - popup.AppendMenuIcon(ID_EXPORT, _T("Export this version"), IDI_EXPORT); + CString str,format; + format.LoadString(IDS_RESET_TO_THIS_FORMAT); + str.Format(format,g_Git.GetCurrentBranch()); + + if(!pSelLogEntry->m_CommitHash.IsEmpty()) + { + if(m_ContextMenuMask&GetContextMenuBit(ID_RESET)) + popup.AppendMenuIcon(ID_RESET,str,IDI_REVERT); + + if(m_ContextMenuMask&GetContextMenuBit(ID_SWITCHTOREV)) + popup.AppendMenuIcon(ID_SWITCHTOREV, IDS_SWITCH_TO_THIS , IDI_SWITCH); + + if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_BRANCH)) + popup.AppendMenuIcon(ID_CREATE_BRANCH, IDS_CREATE_BRANCH_AT_THIS , IDI_COPY); + + if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_TAG)) + popup.AppendMenuIcon(ID_CREATE_TAG,IDS_CREATE_TAG_AT_THIS , IDI_COPY); + format.LoadString(IDS_REBASE_THIS_FORMAT); + str.Format(format,g_Git.GetCurrentBranch()); + + if(pSelLogEntry->m_CommitHash != m_HeadHash) + if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_TO_VERSION)) + popup.AppendMenuIcon(ID_REBASE_TO_VERSION, str , IDI_REBASE); + + if(m_ContextMenuMask&GetContextMenuBit(ID_EXPORT)) + popup.AppendMenuIcon(ID_EXPORT,IDS_EXPORT_TO_THIS, IDI_EXPORT); + + + popup.AppendMenu(MF_SEPARATOR, NULL); + } + + } + if(!pSelLogEntry->m_Ref.IsEmpty() && GetSelectedCount() == 1) + { + popup.AppendMenuIcon(ID_REFLOG_DEL, IDS_REFLOG_DEL, IDI_DELETE); + popup.AppendMenuIcon(ID_STASH_APPLY,IDS_MENUSTASHAPPLY, IDI_RELOCATE); popup.AppendMenu(MF_SEPARATOR, NULL); } - else if (GetSelectedCount() >= 2) + + if (GetSelectedCount() >= 2) { bool bAddSeparator = false; if (IsSelectionContinuous() || (GetSelectedCount() == 2)) { - popup.AppendMenuIcon(ID_COMPARETWO, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF); + if(m_ContextMenuMask&GetContextMenuBit(ID_COMPARETWO)) + popup.AppendMenuIcon(ID_COMPARETWO, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF); } + if (GetSelectedCount() == 2) { //popup.AppendMenuIcon(ID_BLAMETWO, IDS_LOG_POPUP_BLAMEREVS, IDI_BLAME); - popup.AppendMenuIcon(ID_GNUDIFF2, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF); + if(m_ContextMenuMask&GetContextMenuBit(ID_GNUDIFF2)) + popup.AppendMenuIcon(ID_GNUDIFF2, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF); bAddSeparator = true; } + if (m_hasWC) { //popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREVS, IDI_REVERT); @@ -1061,6 +1391,39 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point) if (bAddSeparator) popup.AppendMenu(MF_SEPARATOR, NULL); } + + if ( GetSelectedCount() >0 && (!pSelLogEntry->m_CommitHash.IsEmpty())) + { + if ( IsSelectionContinuous() && GetSelectedCount() >= 2 ) + { + if(m_ContextMenuMask&GetContextMenuBit(ID_COMBINE_COMMIT)) + { + CString head; + int headindex; + headindex = this->GetHeadIndex(); + if(headindex>=0) + { + head.Format(_T("HEAD~%d"),LastSelect-headindex); + CString hash=g_Git.GetHash(head); + hash=hash.Left(40); + GitRev* pLastEntry = reinterpret_cast(m_arShownList.GetAt(LastSelect)); + if(pLastEntry->m_CommitHash.ToString() == hash) + popup.AppendMenuIcon(ID_COMBINE_COMMIT,IDS_COMBINE_TO_ONE,IDI_COMBINE); + } + } + } + if(m_ContextMenuMask&GetContextMenuBit(ID_CHERRY_PICK)) + popup.AppendMenuIcon(ID_CHERRY_PICK, IDS_CHERRY_PICK_VERSION, IDI_EXPORT); + + if(GetSelectedCount()<=2 || (IsSelectionContinuous() && GetSelectedCount() > 0)) + if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_PATCH)) + popup.AppendMenuIcon(ID_CREATE_PATCH, IDS_CREATE_PATCH, IDI_PATCH); + + popup.AppendMenu(MF_SEPARATOR, NULL); + + } + + #if 0 // if ((selEntries.size() > 0)&&(bAllFromTheSameAuthor)) // { @@ -1077,13 +1440,49 @@ void CGitLogListBase::OnContextMenu(CWnd* pWnd, CPoint point) if (GetSelectedCount() == 1) { - popup.AppendMenuIcon(ID_COPYHASH, _T("Copy Commit Hash")); + if(m_ContextMenuMask&GetContextMenuBit(ID_COPYHASH)) + popup.AppendMenuIcon(ID_COPYHASH, IDS_COPY_COMMIT_HASH); } if (GetSelectedCount() != 0) { - popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD); + if(m_ContextMenuMask&GetContextMenuBit(ID_COPYCLIPBOARD)) + popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD); + } + + if(m_ContextMenuMask&GetContextMenuBit(ID_FINDENTRY)) + popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND); + + + if (GetSelectedCount() == 1) + { + if(m_ContextMenuMask &GetContextMenuBit(ID_DELETE)) + { + if( this->m_HashMap.find(pSelLogEntry->m_CommitHash) != m_HashMap.end() ) + { + CString str; + str.LoadString(IDS_DELETE_BRANCHTAG); + if( m_HashMap[pSelLogEntry->m_CommitHash].size() == 1 ) + { + str+=_T(" "); + str+=m_HashMap[pSelLogEntry->m_CommitHash].at(0); + popup.AppendMenuIcon(ID_DELETE,str+_T("..."),IDI_DELETE); + } + else if( m_HashMap[pSelLogEntry->m_CommitHash].size() > 1 ) + { + + submenu.CreatePopupMenu(); + for(int i=0;im_CommitHash].size();i++) + { + submenu.AppendMenuIcon(ID_DELETE+(i<<16),m_HashMap[pSelLogEntry->m_CommitHash][i]+_T("...")); + } + + popup.AppendMenu(MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT) submenu.m_hMenu,str); + + } + + } + } } - popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND); int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0); // DialogEnableWindow(IDOK, FALSE); @@ -1178,9 +1577,20 @@ void CGitLogListBase::CopySelectionToClipBoard(bool HashOnly) void CGitLogListBase::DiffSelectedRevWithPrevious() { -#if 0 if (m_bThreadRunning) return; + + int FirstSelect=-1, LastSelect=-1; + POSITION pos = GetFirstSelectedItemPosition(); + FirstSelect = GetNextSelectedItem(pos); + while(pos) + { + LastSelect = GetNextSelectedItem(pos); + } + + ContextMenuAction(ID_COMPAREWITHPREVIOUS,FirstSelect,LastSelect); + +#if 0 UpdateLogInfoLabel(); int selIndex = m_LogList.GetSelectionMark(); if (selIndex < 0) @@ -1301,12 +1711,12 @@ void CGitLogListBase::OnLvnOdfinditemLoglist(NMHDR *pNMHDR, LRESULT *pResult) *pResult = -1; } -int CGitLogListBase::FillGitLog(CTGitPath *path,int info) +int CGitLogListBase::FillGitLog(CTGitPath *path,int info,CString *from,CString *to) { ClearText(); this->m_logEntries.ClearAll(); - this->m_logEntries.ParserFromLog(path,-1,info); + this->m_logEntries.ParserFromLog(path,-1,info,from,to); //this->m_logEntries.ParserFromLog(); SetItemCountEx(this->m_logEntries.size()); @@ -1315,8 +1725,16 @@ int CGitLogListBase::FillGitLog(CTGitPath *path,int info) for(unsigned int i=0;im_arShownList.Add(&m_logEntries[i]); + if(m_IsOldFirst) + { + m_logEntries.GetGitRevAt(m_logEntries.size()-i-1).m_IsFull=TRUE; + this->m_arShownList.Add(&m_logEntries[m_logEntries.size()-i-1]); + + }else + { + m_logEntries.GetGitRevAt(i).m_IsFull=TRUE; + this->m_arShownList.Add(&m_logEntries[i]); + } } if(path) @@ -1325,11 +1743,12 @@ int CGitLogListBase::FillGitLog(CTGitPath *path,int info) } -int CGitLogListBase::FillGitShortLog() +int CGitLogListBase::BeginFetchLog() { ClearText(); this->m_logEntries.ClearAll(); + git_init(); m_LogCache.FetchCacheIndex(g_Git.m_CurrentDir); @@ -1344,20 +1763,31 @@ int CGitLogListBase::FillGitShortLog() mask = CGit::LOG_INFO_ONLY_HASH | CGit::LOG_INFO_BOUNDARY; // if(this->m_bAllBranch) mask |= m_ShowMask; - - this->m_logEntries.ParserShortLog(path,hash,-1,mask); + this->m_arShownList.RemoveAll(); + + if(m_bShowWC) + { + this->m_logEntries.insert(m_logEntries.begin(),this->m_wcRev.m_CommitHash); + this->m_LogCache.m_HashMap[m_wcRev.m_CommitHash]=m_wcRev; + } + + CString cmd=g_Git.GetLogCmd(m_StartRef,path,-1,mask,NULL,NULL,true); //this->m_logEntries.ParserFromLog(); if(IsInWorkingThread()) + { PostMessage(LVM_SETITEMCOUNT, (WPARAM) this->m_logEntries.size(),(LPARAM) LVSICF_NOINVALIDATEALL); + } else + { SetItemCountEx(this->m_logEntries.size()); - - this->m_arShownList.RemoveAll(); - - for(unsigned int i=0;im_arShownList.Add(&m_logEntries[i]); + } + + if(git_open_log(&m_DllGitLog,CUnicodeUtils::GetMulti(cmd,CP_ACP).GetBuffer())) + { + return -1; + } return 0; } @@ -1403,8 +1833,8 @@ void CGitLogListBase::OnNMDblclkLoglist(NMHDR * /*pNMHDR*/, LRESULT *pResult) // a double click on an entry in the revision list has happened *pResult = 0; - if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE)) - DiffSelectedRevWithPrevious(); + if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE)) + DiffSelectedRevWithPrevious(); } int CGitLogListBase::FetchLogAsync(void * data) @@ -1437,18 +1867,271 @@ void CGitLogListBase::GetTimeRange(CTime &oldest, CTime &latest) latest=CTime(1971,1,2,0,0,0); for(unsigned int i=0;i latest.GetTime()) + latest = m_logEntries.GetGitRevAt(i).m_AuthorDate.GetTime(); + + } +} + +//Helper class for FetchFullLogInfo() +class CGitCall_FetchFullLogInfo : public CGitCall +{ +public: + CGitCall_FetchFullLogInfo(CGitLogListBase* ploglist):m_ploglist(ploglist),m_CollectedCount(0){} + virtual bool OnOutputData(const BYTE* data, size_t size) + { + if(size==0) + return m_ploglist->m_bExitThread; + //Add received data to byte collector + m_ByteCollector.append(data,size); + + //Find loginfo endmarker + static const BYTE dataToFind[]={0,0,'#','<'}; + int found=m_ByteCollector.findData(dataToFind,4); + if(found<0) + return m_ploglist->m_bExitThread;//Not found + found+=2;//Position after loginfo end-marker + + //Prepare data for OnLogInfo and call it + BYTE_VECTOR logInfo; + logInfo.append(&*m_ByteCollector.begin(),found); + OnLogInfo(logInfo); + + //Remove loginfo from bytecollector + m_ByteCollector.erase(m_ByteCollector.begin(),m_ByteCollector.begin()+found); + + return m_ploglist->m_bExitThread; + } + virtual void OnEnd() + { + //Rest should be a complete log line. + if(!m_ByteCollector.empty()) + OnLogInfo(m_ByteCollector); + } + + + void OnLogInfo(BYTE_VECTOR& logInfo) + { + GitRev fullRev; + fullRev.ParserFromLog(logInfo); + MAP_HASH_REV::iterator itRev=m_ploglist->m_logEntries.m_HashMap.find(fullRev.m_CommitHash); + if(itRev==m_ploglist->m_logEntries.m_HashMap.end()) + { + //Should not occur, only when Git-tree updated in the mean time. (Race condition) + return;//Ignore + } + //Set updating + int rev=itRev->second; + GitRev* revInVector=&m_ploglist->m_logEntries.GetGitRevAt(rev); + + + if(revInVector->m_IsFull) + return; + + GitRev *pRev= m_ploglist->m_LogCache.GetCacheData(m_ploglist->m_logEntries[rev]); + if(pRev) + { + ++m_CollectedCount; + InterlockedExchange(&pRev->m_IsUpdateing,FALSE); + InterlockedExchange(&pRev->m_IsFull,TRUE); + ::PostMessage(m_ploglist->m_hWnd,MSG_LOADED,(WPARAM)rev,0); + return; + } + +// fullRev.m_IsUpdateing=TRUE; +// fullRev.m_IsFull=TRUE; + + + if(InterlockedExchange(&revInVector->m_IsUpdateing,TRUE)) + return;//Cannot update this row now. Ignore. + TCHAR oldmark=revInVector->m_Mark; + GIT_REV_LIST oldlist=revInVector->m_ParentHash; +// CString oldhash=m_CommitHash; + + //Parse new rev info + revInVector->ParserFromLog(logInfo); + + if(oldmark!=0) + revInVector->m_Mark=oldmark; //parser full log will cause old mark overwrited. + //So we need keep old bound mark. + revInVector->m_ParentHash=oldlist; + + //update cache + m_ploglist->m_LogCache.AddCacheEntry(*revInVector); + + //Reset updating + InterlockedExchange(&revInVector->m_IsFull,TRUE); + InterlockedExchange(&revInVector->m_IsUpdateing,FALSE); + + //Notify listcontrol and update progress bar + ++m_CollectedCount; + + ::PostMessage(m_ploglist->m_hWnd,MSG_LOADED,(WPARAM)rev,0); + + DWORD percent=m_CollectedCount*68/m_ploglist->m_logEntries.size() + GITLOG_START+1+30; + if(percent == GITLOG_END) + percent = GITLOG_END -1; + + ::PostMessage(m_ploglist->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent,0); + } + + CGitLogListBase* m_ploglist; + BYTE_VECTOR m_ByteCollector; + int m_CollectedCount; + +}; + +void CGitLogListBase::FetchFullLogInfo(CString &from, CString &to) +{ + CGitCall_FetchFullLogInfo fetcher(this); + int mask= + CGit::LOG_INFO_FULL_DIFF| + CGit::LOG_INFO_STAT| + CGit::LOG_INFO_FILESTATE| + CGit::LOG_INFO_DETECT_COPYRENAME| + CGit::LOG_INFO_SHOW_MERGEDFILE | + m_ShowMask; + + CTGitPath *path; + if(this->m_Path.IsEmpty()) + path=NULL; + else + path=&this->m_Path; + + g_Git.GetLog(&fetcher,CString(),path,-1,mask,&from,&to); +} + +void CGitLogListBase::FetchLastLogInfo() +{ + unsigned int updated=0; + int percent=0; + CRect rect; + { + for(unsigned int i=0;i latest.GetTime()) - latest = m_logEntries[i].m_AuthorDate.GetTime(); + GitRev *pRev = m_LogCache.GetCacheData(m_logEntries[i]); + if(pRev == NULL) + { + if(!m_logEntries.FetchFullInfo(i)) + { + updated++; + } + m_LogCache.AddCacheEntry(m_logEntries.GetGitRevAt(i)); + }else + { + updated++; + InterlockedExchange(&pRev->m_IsUpdateing,FALSE); + InterlockedExchange(&pRev->m_IsFull,TRUE); + } + + ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM)i,0); + + if(m_bExitThread) + { + InterlockedExchange(&m_bThreadRunning, FALSE); + InterlockedExchange(&m_bNoDispUpdates, FALSE); + return; + } + } } } UINT CGitLogListBase::LogThread() { + ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_START,0); + + InterlockedExchange(&m_bThreadRunning, TRUE); + InterlockedExchange(&m_bNoDispUpdates, TRUE); + ULONGLONG t1,t2; + + if(BeginFetchLog()) + return -1; + + //Update work copy item; + if( m_logEntries.size() > 0) + { + GitRev *pRev = &m_logEntries.GetGitRevAt(0); + + m_arShownList.Add(pRev); + + if( pRev->m_CommitHash.IsEmpty() ) + { + pRev->m_Files.Clear(); + pRev->m_ParentHash.clear(); + pRev->m_ParentHash.push_back(m_HeadHash); + g_Git.GetCommitDiffList(pRev->m_CommitHash.ToString(),this->m_HeadHash, pRev->m_Files); + pRev->m_Action =0; + + for(int j=0;j< pRev->m_Files.GetCount();j++) + pRev->m_Action |= pRev->m_Files[j].m_Action; + + pRev->m_Body.Format(_T("%d files changed"),m_logEntries.GetGitRevAt(0).m_Files.GetCount()); + ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM)0,0); + } + } + + InterlockedExchange(&m_bNoDispUpdates, FALSE); + + git_get_log_firstcommit(m_DllGitLog); + GIT_COMMIT commit; + t1=GetTickCount(); + + int oldsize=m_logEntries.size(); + while( git_get_log_nextcommit(this->m_DllGitLog,&commit) == 0) + { + //printf("%s\r\n",commit.m_Subject); + if(m_bExitThread) + break; + + CGitHash hash = (char*)commit.m_hash ; + + m_logEntries.push_back(hash); + + GitRev *pRev = m_LogCache.GetCacheData(hash); + + if(pRev == NULL || !pRev->m_IsFull) + { + pRev->ParserFromCommit(&commit); + pRev->ParserParentFromCommit(&commit); + + pRev->SafeFetchFullInfo(&g_Git); + git_free_commit(&commit); + + }else + { + ASSERT(pRev->m_CommitHash == hash); + pRev->ParserParentFromCommit(&commit); + } + + m_arShownList.Add(pRev); + + if(t2-t1>500 && m_logEntries.size()<(oldsize+100) ) + { + //update UI + oldsize = m_logEntries.size(); + PostMessage(LVM_SETITEMCOUNT, (WPARAM) this->m_logEntries.size(),(LPARAM) LVSICF_NOINVALIDATEALL|LVSICF_NOSCROLL); + ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_END,0); + } + } + + //Update UI; + PostMessage(LVM_SETITEMCOUNT, (WPARAM) this->m_logEntries.size(),(LPARAM) LVSICF_NOINVALIDATEALL|LVSICF_NOSCROLL); + ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_END,0); + + InterlockedExchange(&m_bThreadRunning, FALSE); + +#if 0 // if(m_ProcCallBack) // m_ProcCallBack(m_ProcData,GITLOG_START); ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_START,0); @@ -1466,7 +2149,71 @@ UINT CGitLogListBase::LogThread() FillGitShortLog(); if(this->m_bExitThread) + { + InterlockedExchange(&m_bThreadRunning, FALSE); + InterlockedExchange(&m_bNoDispUpdates, FALSE); return 0; + } + InterlockedExchange(&m_bNoDispUpdates, FALSE); + ::PostMessage(GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_START_ALL, 0); + + int start=0; CString firstcommit,lastcommit; + int update=0; + for(int i=0;im_HeadHash,m_logEntries.GetGitRevAt(i).m_Files); + m_logEntries.GetGitRevAt(i).m_Action =0; + for(int j=0;j< m_logEntries.GetGitRevAt(i).m_Files.GetCount();j++) + m_logEntries.GetGitRevAt(i).m_Action |= m_logEntries.GetGitRevAt(i).m_Files[j].m_Action; + + m_logEntries.GetGitRevAt(i).m_Body.Format(_T("%d files changed"),m_logEntries.GetGitRevAt(i).m_Files.GetCount()); + ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM)0,0); + continue; + } + + start=this->m_logEntries.GetGitRevAt(i).ParserFromLog(m_logEntries.m_RawlogData,start); + m_logEntries.m_HashMap[m_logEntries.GetGitRevAt(i).m_CommitHash.ToString()]=i; + + if(m_LogCache.GetCacheData(m_logEntries.GetGitRevAt(i))) + { + if(firstcommit.IsEmpty()) + firstcommit=m_logEntries.GetGitRevAt(i).m_CommitHash.ToString(); + lastcommit=m_logEntries.GetGitRevAt(i).m_CommitHash.ToString(); + + }else + { + InterlockedExchange(&m_logEntries.GetGitRevAt(i).m_IsUpdateing,FALSE); + InterlockedExchange(&m_logEntries.GetGitRevAt(i).m_IsFull,TRUE); + update++; + } + ::PostMessage(m_hWnd,MSG_LOADED,(WPARAM) i, 0); + + if(start<0) + break; + if(start>=m_logEntries.m_RawlogData.size()) + break; + + int percent=i*30/m_logEntries.size() + GITLOG_START+1; + + ::PostMessage(GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent, 0); + + if(this->m_bExitThread) + { + InterlockedExchange(&m_bThreadRunning, FALSE); + InterlockedExchange(&m_bNoDispUpdates, FALSE); + return 0; + } + } + if(!lastcommit.IsEmpty()) + FetchFullLogInfo(lastcommit,firstcommit); + + this->FetchLastLogInfo(); + #if 0 RedrawItems(0, m_arShownList.GetCount()); // SetRedraw(false); @@ -1491,47 +2238,11 @@ UINT CGitLogListBase::LogThread() } } #endif - InterlockedExchange(&m_bNoDispUpdates, FALSE); - unsigned int updated=0; - int percent=0; - CRect rect; - while(1) - { - for(unsigned int i=0;iGetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent,0); - - - } - if(updated==m_logEntries.size()) - break; - } + //FetchFullLogInfo(); + //FetchFullLogInfoOrig(); //RefreshCursor(); // make sure the filter is applied (if any) now, after we refreshed/fetched // the log messages @@ -1539,22 +2250,29 @@ UINT CGitLogListBase::LogThread() ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) GITLOG_END,0); InterlockedExchange(&m_bThreadRunning, FALSE); - +#endif return 0; } void CGitLogListBase::Refresh() { m_bExitThread=TRUE; - DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000); - if(ret == WAIT_TIMEOUT) - TerminateThread(); - + if(m_LoadingThread!=NULL) + { + DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000); + if(ret == WAIT_TIMEOUT) + TerminateThread(); + } + + this->SetItemCountEx(0); this->Clear(); - if(!m_bThreadRunning) + //Update branch and Tag info + ReloadHashMap(); + //Assume Thread have exited + //if(!m_bThreadRunning) { - this->SetItemCountEx(0); + m_logEntries.clear(); m_bExitThread=FALSE; InterlockedExchange(&m_bThreadRunning, TRUE); @@ -1612,17 +2330,17 @@ void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist) #endif if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_MESSAGES)) { - ATLTRACE(_T("messge = \"%s\"\n"),m_logEntries[i].m_Subject); - if (regex_search(wstring((LPCTSTR)m_logEntries[i].m_Subject), pat, flags)&&IsEntryInDateRange(i)) + ATLTRACE(_T("messge = \"%s\"\n"),m_logEntries.GetGitRevAt(i).m_Subject); + if (regex_search(wstring((LPCTSTR)m_logEntries.GetGitRevAt(i).m_Subject), pat, flags)&&IsEntryInDateRange(i)) { pShownlist->Add(&m_logEntries[i]); continue; } - ATLTRACE(_T("messge = \"%s\"\n"),m_logEntries[i].m_Body); - if (regex_search(wstring((LPCTSTR)m_logEntries[i].m_Body), pat, flags)&&IsEntryInDateRange(i)) + ATLTRACE(_T("messge = \"%s\"\n"),m_logEntries.GetGitRevAt(i).m_Body); + if (regex_search(wstring((LPCTSTR)m_logEntries.GetGitRevAt(i).m_Body), pat, flags)&&IsEntryInDateRange(i)) { - pShownlist->Add(&m_logEntries[i]); + pShownlist->Add(&m_logEntries.GetGitRevAt(i)); continue; } } @@ -1660,18 +2378,18 @@ void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist) #endif if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_AUTHORS)) { - if (regex_search(wstring((LPCTSTR)m_logEntries[i].m_AuthorName), pat, flags)&&IsEntryInDateRange(i)) + if (regex_search(wstring((LPCTSTR)m_logEntries.GetGitRevAt(i).m_AuthorName), pat, flags)&&IsEntryInDateRange(i)) { - pShownlist->Add(&m_logEntries[i]); + pShownlist->Add(&m_logEntries.GetGitRevAt(i)); continue; } } if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_REVS)) { - sRev.Format(_T("%ld"), m_logEntries[i].m_CommitHash); + sRev.Format(_T("%s"), m_logEntries.GetGitRevAt(i).m_CommitHash); if (regex_search(wstring((LPCTSTR)sRev), pat, flags)&&IsEntryInDateRange(i)) { - pShownlist->Add(&m_logEntries[i]); + pShownlist->Add(&m_logEntries.GetGitRevAt(i)); continue; } } @@ -1695,15 +2413,15 @@ void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist) #endif if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_MESSAGES)) { - CString msg = m_logEntries[i].m_Subject; + CString msg = m_logEntries.GetGitRevAt(i).m_Subject; msg = msg.MakeLower(); if ((msg.Find(find) >= 0)&&(IsEntryInDateRange(i))) { - pShownlist->Add(&m_logEntries[i]); + pShownlist->Add(&m_logEntries.GetGitRevAt(i)); continue; } - msg = m_logEntries[i].m_Body; + msg = m_logEntries.GetGitRevAt(i).m_Body; msg = msg.MakeLower(); if ((msg.Find(find) >= 0)&&(IsEntryInDateRange(i))) @@ -1750,20 +2468,20 @@ void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist) #endif if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_AUTHORS)) { - CString msg = m_logEntries[i].m_AuthorName; + CString msg = m_logEntries.GetGitRevAt(i).m_AuthorName; msg = msg.MakeLower(); if ((msg.Find(find) >= 0)&&(IsEntryInDateRange(i))) { - pShownlist->Add(&m_logEntries[i]); + pShownlist->Add(&m_logEntries.GetGitRevAt(i)); continue; } } if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_REVS)) { - sRev.Format(_T("%ld"), m_logEntries[i].m_CommitHash); + sRev.Format(_T("%s"), m_logEntries.GetGitRevAt(i).m_CommitHash); if ((sRev.Find(find) >= 0)&&(IsEntryInDateRange(i))) { - pShownlist->Add(&m_logEntries[i]); + pShownlist->Add(&m_logEntries.GetGitRevAt(i)); continue; } } @@ -1774,7 +2492,7 @@ void CGitLogListBase::RecalculateShownList(CPtrArray * pShownlist) BOOL CGitLogListBase::IsEntryInDateRange(int i) { - __time64_t time = m_logEntries[i].m_AuthorDate.GetTime(); + __time64_t time = m_logEntries.GetGitRevAt(i).m_AuthorDate.GetTime(); if ((time >= m_From.GetTime())&&(time <= m_To.GetTime())) return TRUE; @@ -1817,7 +2535,13 @@ void CGitLogListBase::RemoveFilter() for (DWORD i=0; im_IsOldFirst) + { + m_arShownList.Add(&m_logEntries[m_logEntries.size()-i-1]); + }else + { + m_arShownList.Add(&m_logEntries[i]); + } } // InterlockedExchange(&m_bNoDispUpdates, FALSE); DeleteAllItems(); @@ -1833,13 +2557,9 @@ void CGitLogListBase::RemoveFilter() void CGitLogListBase::Clear() { m_arShownList.RemoveAll(); - m_logEntries.clear(); - m_logEntries.m_HashMap.clear(); DeleteAllItems(); - m_logEntries.m_Lns.clear(); - m_logEntries.m_FirstFreeLane=0; - m_logEntries.m_Lns.clear(); + m_logEntries.ClearAll(); } @@ -1870,6 +2590,11 @@ LRESULT CGitLogListBase::OnLoad(WPARAM wParam,LPARAM lParam) int i=(int)wParam; this->GetItemRect(i,&rect,LVIR_BOUNDS); this->InvalidateRect(rect); + + if(this->GetItemState(i,LVIF_STATE) & LVIS_SELECTED) + { + int i=0; + } return 0; } @@ -1886,9 +2611,26 @@ void CGitLogListBase::SaveColumnWidths() { int width = GetColumnWidth( col ); CString regentry; - regentry.Format( _T("Software\\TortoiseGit\\log\\ColWidth%d"), col); + regentry.Format( _T("Software\\TortoiseGit\\%s\\ColWidth%d"),m_ColumnRegKey, col); CRegDWORD regwidth(regentry, 0); regwidth = width; // this writes it to reg } } } + +int CGitLogListBase::GetHeadIndex() +{ + if(m_HeadHash.IsEmpty()) + return -1; + + for(int i=0;im_CommitHash.ToString() == m_HeadHash ) + return i; + } + } + return -1; +} \ No newline at end of file