+//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