\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
{\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
\r
CGitLogListBase::~CGitLogListBase()\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
\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\\log\\ColWidth%d"), 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
+ // no saved value, setup sensible defaults\r
+ if (col == this->LOGLIST_MESSAGE)\r
{\r
- GitRev * pCurLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(index));\r
- if ((pCurLogEntry)&&(pCurLogEntry->m_CommitHash == m_wcRev.m_CommitHash))\r
- {\r
- // set the bold font and ask for the string width again\r
- SendMessage(WM_SETFONT, (WPARAM)m_boldFont, NULL);\r
- linewidth = GetStringWidth(GetItemText(index, col)) + 14;\r
- // restore the system font\r
- SendMessage(WM_SETFONT, NULL, NULL);\r
- }\r
- }\r
- if (index == 0)\r
- {\r
- // add the image size\r
- CImageList * pImgList = GetImageList(LVSIL_SMALL);\r
- if ((pImgList)&&(pImgList->GetImageCount()))\r
- {\r
- IMAGEINFO imginfo;\r
- pImgList->GetImageInfo(0, &imginfo);\r
- linewidth += (imginfo.rcImage.right - imginfo.rcImage.left);\r
- linewidth += 3; // 3 pixels between icon and text\r
- }\r
+ 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
rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
GetItem(&rItem);\r
\r
+ GitRev* pLogEntry = (GitRev*)m_arShownList.GetAt(Index);\r
+\r
if (m_Theme.IsAppThemed() && m_bVista)\r
{\r
m_Theme.Open(m_hWnd, L"Explorer");\r
//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
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->childStackDepth)||(m_mergedRevs.find(data->Rev) != m_mergedRevs.end()))\r
// crText = GetSysColor(COLOR_GRAYTEXT);\r
// if (data->Rev == m_wcRev)\r
\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
::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
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
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
case this->LOGLIST_DATE: //Date\r
if (pLogEntry)\r
lstrcpyn(pItem->pszText,\r
- CAppUtils::FormatDateAndTime( pLogEntry->m_AuthorDate, m_DateFormat ), \r
+ CAppUtils::FormatDateAndTime( pLogEntry->m_AuthorDate, m_DateFormat, true, m_bRelativeTimes ), \r
pItem->cchTextMax);\r
break;\r
\r
CIconMenu popup;\r
if (popup.CreatePopupMenu())\r
{\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_PICK))\r
+ popup.AppendMenuIcon(ID_REBASE_PICK, _T("Pick"), IDI_OPEN);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_SQUASH))\r
+ popup.AppendMenuIcon(ID_REBASE_SQUASH, _T("Squash"), IDI_OPEN);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_EDIT))\r
+ popup.AppendMenuIcon(ID_REBASE_EDIT, _T("Edit"), IDI_OPEN);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_REBASE_SKIP))\r
+ popup.AppendMenuIcon(ID_REBASE_SKIP, _T("SKIP"), IDI_OPEN);\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
{\r
if (m_hasWC)\r
{\r
- popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_COMPARE))\r
+ popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
// TODO:\r
// TortoiseMerge could be improved to take a /blame switch\r
// and then not 'cat' the files from a unified diff but\r
// this feature is commented out.\r
//popup.AppendMenu(ID_BLAMECOMPARE, IDS_LOG_POPUP_BLAMECOMPARE, IDI_BLAME);\r
}\r
- popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
- popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_GNUDIFF1))\r
+ popup.AppendMenuIcon(ID_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF_CH, IDI_DIFF);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_COMPAREWITHPREVIOUS))\r
+ popup.AppendMenuIcon(ID_COMPAREWITHPREVIOUS, IDS_LOG_POPUP_COMPAREWITHPREVIOUS, IDI_DIFF);\r
//popup.AppendMenuIcon(ID_BLAMEWITHPREVIOUS, IDS_LOG_POPUP_BLAMEWITHPREVIOUS, IDI_BLAME);\r
popup.AppendMenu(MF_SEPARATOR, NULL);\r
}\r
\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
+\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, _T("Switch/Checkout to this") , IDI_SWITCH);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_BRANCH))\r
+ popup.AppendMenuIcon(ID_CREATE_BRANCH, _T("Create Branch at this version") , IDI_COPY);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_CREATE_TAG))\r
+ popup.AppendMenuIcon(ID_CREATE_TAG, _T("Create Tag at this version"), IDI_COPY);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_CHERRY_PICK))\r
+ popup.AppendMenuIcon(ID_CHERRY_PICK, _T("Cherry Pick this version"), IDI_EXPORT);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_EXPORT))\r
+ popup.AppendMenuIcon(ID_EXPORT, _T("Export this version"), IDI_EXPORT); \r
\r
\r
popup.AppendMenu(MF_SEPARATOR, NULL);\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 ( IsSelectionContinuous() )\r
+ {\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_COMBINE_COMMIT))\r
+ {\r
+ CString head;\r
+ head.Format(_T("HEAD~%d"),LastSelect);\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,_T("Combine to one commit"),IDI_MERGE);\r
+ }\r
+ }\r
if (m_hasWC)\r
{\r
//popup.AppendMenuIcon(ID_REVERTREV, IDS_LOG_POPUP_REVERTREVS, IDI_REVERT);\r
\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, _T("Copy Commit Hash"));\r
}\r
if (GetSelectedCount() != 0)\r
{\r
- popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD);\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_COPYCLIPBOARD))\r
+ popup.AppendMenuIcon(ID_COPYCLIPBOARD, IDS_LOG_POPUP_COPYTOCLIPBOARD);\r
}\r
- popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND);\r
+\r
+ if(m_ContextMenuMask&GetContextMenuBit(ID_FINDENTRY))\r
+ popup.AppendMenuIcon(ID_FINDENTRY, IDS_LOG_POPUP_FIND);\r
\r
int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
// DialogEnableWindow(IDOK, FALSE);\r
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)CAppUtils::FormatDateAndTime( pLogEntry->m_AuthorDate, m_DateFormat ),\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
*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
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
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
+// if(this->m_bAllBranch)\r
+ mask |= m_ShowMask;\r
\r
this->m_logEntries.ParserShortLog(path,hash,-1,mask);\r
\r
this->m_arShownList.RemoveAll();\r
\r
for(unsigned int i=0;i<m_logEntries.size();i++)\r
- this->m_arShownList.Add(&m_logEntries[i]);\r
+ {\r
+ 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
}\r
}\r
\r
-UINT CGitLogListBase::LogThread()\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,2);\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
-// 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
+ 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
- //does the user force the cache to refresh (shift or control key down)?\r
- bool refresh = (GetKeyState (VK_CONTROL) < 0) \r
- || (GetKeyState (VK_SHIFT) < 0);\r
\r
- //disable the "Get All" button while we're receiving\r
- //log messages.\r
+// fullRev.m_IsUpdateing=TRUE;\r
+// fullRev.m_IsFull=TRUE;\r
\r
- CString temp;\r
- temp.LoadString(IDS_PROGRESSWAIT);\r
- ShowText(temp, true);\r
\r
- FillGitShortLog();\r
- \r
- if(this->m_bExitThread)\r
- return 0;\r
-#if 0\r
- RedrawItems(0, m_arShownList.GetCount());\r
- SetRedraw(false);\r
- ResizeAllListCtrlCols();\r
- SetRedraw(true);\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
- if ( m_pStoreSelection )\r
- {\r
- // Deleting the instance will restore the\r
- // selection of the CLogDlg.\r
- delete m_pStoreSelection;\r
- m_pStoreSelection = NULL;\r
- }\r
- else\r
- {\r
- // If no selection has been set then this must be the first time\r
- // the revisions are shown. Let's preselect the topmost revision.\r
- if ( GetItemCount()>0 )\r
- {\r
- SetSelectionMark(0);\r
- SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);\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
+ //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*98/m_ploglist->m_logEntries.size() + GITLOG_START+1;\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
-#endif\r
- InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
\r
- int index=0;\r
+ CGitLogListBase* m_ploglist;\r
+ BYTE_VECTOR m_ByteCollector;\r
+ int m_CollectedCount;\r
+\r
+};\r
+\r
+void CGitLogListBase::FetchFullLogInfo()\r
+{\r
+ CGitCall_FetchFullLogInfo fetcher(this);\r
+ int mask=\r
+ CGit::LOG_INFO_STAT|\r
+ CGit::LOG_INFO_FILESTATE|\r
+ CGit::LOG_INFO_DETECT_COPYRENAME|\r
+ m_ShowMask;\r
+ g_Git.GetLog(&fetcher,CString(),NULL,-1,mask);\r
+}\r
+\r
+void CGitLogListBase::FetchFullLogInfoOrig()\r
+{\r
unsigned int updated=0;\r
int percent=0;\r
CRect rect;\r
::PostMessage(m_hWnd,MSG_LOADED,(WPARAM)i,0);\r
\r
if(m_bExitThread)\r
- return 0;\r
+ {\r
+ InterlockedExchange(&m_bThreadRunning, FALSE);\r
+ InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
+ return;\r
+ }\r
\r
percent=updated*98/m_logEntries.size() + GITLOG_START+1;\r
if(percent == GITLOG_END)\r
if(updated==m_logEntries.size())\r
break;\r
}\r
+}\r
+\r
+UINT CGitLogListBase::LogThread()\r
+{\r
+\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
\r
+ //does the user force the cache to refresh (shift or control key down)?\r
+ bool refresh = (GetKeyState (VK_CONTROL) < 0) \r
+ || (GetKeyState (VK_SHIFT) < 0);\r
+\r
+ //disable the "Get All" button while we're receiving\r
+ //log messages.\r
+\r
+ FillGitShortLog();\r
+ \r
+ if(this->m_bExitThread)\r
+ {\r
+ InterlockedExchange(&m_bThreadRunning, FALSE);\r
+ InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
+ return 0;\r
+ }\r
+#if 0\r
+ RedrawItems(0, m_arShownList.GetCount());\r
+// SetRedraw(false);\r
+// ResizeAllListCtrlCols();\r
+// SetRedraw(true);\r
+\r
+ if ( m_pStoreSelection )\r
+ {\r
+ // Deleting the instance will restore the\r
+ // selection of the CLogDlg.\r
+ delete m_pStoreSelection;\r
+ m_pStoreSelection = NULL;\r
+ }\r
+ else\r
+ {\r
+ // If no selection has been set then this must be the first time\r
+ // the revisions are shown. Let's preselect the topmost revision.\r
+ if ( GetItemCount()>0 )\r
+ {\r
+ SetSelectionMark(0);\r
+ SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);\r
+ }\r
+ }\r
+#endif\r
+ InterlockedExchange(&m_bNoDispUpdates, FALSE);\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
void CGitLogListBase::Refresh()\r
-{\r
- if(!m_bThreadRunning)\r
+{ \r
+ m_bExitThread=TRUE;\r
+ DWORD ret =::WaitForSingleObject(m_LoadingThread->m_hThread,20000);\r
+ if(ret == WAIT_TIMEOUT)\r
+ TerminateThread();\r
+\r
+ this->Clear();\r
+\r
+ //Update branch and Tag info\r
+ ReloadHashMap();\r
+ //Assume Thread have exited\r
+ //if(!m_bThreadRunning)\r
{\r
this->SetItemCountEx(0);\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
}\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
}\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
\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
\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
}\r
while(m_LogCache.SaveCache())\r
{\r
- if(CMessageBox::Show(NULL,_T("Can Save Log Cache to Disk,click yes for retry, click no for give up"),_T("TortoiseGit"),\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
this->InvalidateRect(rect);\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\\log\\ColWidth%d"), col);\r
+ CRegDWORD regwidth(regentry, 0);\r
+ regwidth = width; // this writes it to reg\r
+ }\r
+ }\r
+}\r
+\r