From 074d3adb9ca35cccf6dc96b3d9e851f238f8df4e Mon Sep 17 00:00:00 2001 From: Fredrik Svensson Date: Mon, 30 Sep 2013 21:21:36 +0200 Subject: [PATCH] LogDlg: Add compressed graph view (fixes issue #1806) Signed-off-by: Fredrik Svensson Signed-off-by: Sven Strickroth --- Languages/Tortoise.pot | 4 +++ src/Changelog.txt | 1 + src/Resources/TortoiseProcENG.rc | 1 + src/TortoiseProc/GitLogListBase.cpp | 72 ++++++++++++++++++++++++++++++++++--- src/TortoiseProc/GitLogListBase.h | 23 ++++++++---- src/TortoiseProc/LogDataVector.cpp | 9 +++++ src/TortoiseProc/LogDlg.cpp | 20 +++++++++++ src/TortoiseProc/LogDlg.h | 2 ++ src/TortoiseProc/LogDlgHelper.h | 1 + src/TortoiseProc/resource.h | 1 + 10 files changed, 123 insertions(+), 11 deletions(-) diff --git a/Languages/Tortoise.pot b/Languages/Tortoise.pot index 239c467f4..4a16ad45c 100644 --- a/Languages/Tortoise.pot +++ b/Languages/Tortoise.pot @@ -513,6 +513,10 @@ msgstr "" msgid "&Compare revisions" msgstr "" +#. Resource IDs: (92) +msgid "&Compressed Graph" +msgstr "" + #. Resource IDs: (1239) msgid "&Configure" msgstr "" diff --git a/src/Changelog.txt b/src/Changelog.txt index 449f0b6e6..2592b2541 100644 --- a/src/Changelog.txt +++ b/src/Changelog.txt @@ -18,6 +18,7 @@ Released: Unreleased * Allow to edit hierarchical git settings If you have set "i18n.commitencoding" to something different than UTF-8 check your "user.name" setting * Fixed issue #1645: enable/disable spell checking in commit dialog + * Fixed issue #1806: Compressed graph in the log view == Bug Fixes == * Fixed issue #1859: Log too long when using Switch to New Branch option in Create Branch dialog diff --git a/src/Resources/TortoiseProcENG.rc b/src/Resources/TortoiseProcENG.rc index e4fc4c65a..852759768 100644 --- a/src/Resources/TortoiseProcENG.rc +++ b/src/Resources/TortoiseProcENG.rc @@ -4260,6 +4260,7 @@ BEGIN IDS_B_T_PREFILL_ORIGIN "When you type the URL, the remote name will be automatically filled with ""origin"" if the remote name is empty, so you do not have to." IDS_HINT "Hint" IDS_VIEW_SHOWGRAVATAR "G&ravatar" + IDS_WALKBEHAVIOUR_COMPRESSED "&Compressed Graph" END #endif // English (U.S.) resources diff --git a/src/TortoiseProc/GitLogListBase.cpp b/src/TortoiseProc/GitLogListBase.cpp index 2fdb25486..a3ab0ca9e 100644 --- a/src/TortoiseProc/GitLogListBase.cpp +++ b/src/TortoiseProc/GitLogListBase.cpp @@ -57,6 +57,7 @@ CGitLogListBase::CGitLogListBase():CHintListCtrl() , m_bStrictStopped(false) , m_pStoreSelection(NULL) , m_SelectedFilters(LOGFILTER_ALL) + , m_ShowFilter(FILTERSHOW_ALL) , m_bShowWC(false) , m_logEntries(&m_LogCache) , m_pFindDialog(NULL) @@ -1189,7 +1190,7 @@ void CGitLogListBase::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult) pLVCD->nmcd.uItemState &= ~(CDIS_SELECTED|CDIS_FOCUS); } - if (pLVCD->iSubItem == LOGLIST_GRAPH && m_sFilterText.IsEmpty()) + if (pLVCD->iSubItem == LOGLIST_GRAPH && m_sFilterText.IsEmpty() && (m_ShowFilter & FILTERSHOW_MERGEPOINTS)) { if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec && (!this->m_IsRebaseReplaceGraph) ) { @@ -2674,6 +2675,7 @@ UINT CGitLogListBase::LogThread() t2=t1=GetTickCount(); int oldprecentage = 0; size_t oldsize = m_logEntries.size(); + std::map> commitChildren; while (ret== 0 && !m_bExitThread) { g_Git.m_critGitDllSec.Lock(); @@ -2736,25 +2738,45 @@ UINT CGitLogListBase::LogThread() } pRev->ParserParentFromCommit(&commit); + if (m_ShowFilter & FILTERSHOW_MERGEPOINTS) // See also ShouldShowFilter() + { + for (size_t i = 0; i < pRev->m_ParentHash.size(); ++i) + { + const CGitHash &parentHash = pRev->m_ParentHash[i]; + auto it = commitChildren.find(parentHash); + if (it == commitChildren.end()) + { + it = commitChildren.insert(make_pair(parentHash, std::set())).first; + } + it->second.insert(pRev->m_CommitHash); + } + } #ifdef DEBUG pRev->DbgPrint(); TRACE(_T("\n")); #endif + bool visible = true; if(!m_sFilterText.IsEmpty()) { if(!IsMatchFilter(bRegex,pRev,pat)) - continue; + visible = false; } + if (visible && !ShouldShowFilter(pRev, commitChildren)) + visible = false; this->m_critSec.Lock(); - m_logEntries.push_back(hash); - m_arShownList.SafeAdd(pRev); + m_logEntries.append(hash, visible); + if (visible) + m_arShownList.SafeAdd(pRev); this->m_critSec.Unlock(); if (lastSelectedHashNItem == -1 && hash == m_lastSelectedHash) lastSelectedHashNItem = (int)m_arShownList.GetCount() - 1; + if (!visible) + continue; + t2=GetTickCount(); if(t2-t1>500 || (m_logEntries.size()-oldsize >100)) @@ -2774,6 +2796,10 @@ UINT CGitLogListBase::LogThread() ::PostMessage(this->GetParent()->m_hWnd,MSG_LOAD_PERCENTAGE,(WPARAM) percent,0); oldprecentage = percent; } + + if (lastSelectedHashNItem >= 0) + PostMessage(m_ScrollToMessage, lastSelectedHashNItem); + t1 = t2; } } @@ -3136,6 +3162,37 @@ BOOL CGitLogListBase::IsMatchFilter(bool bRegex, GitRev *pRev, std::tr1::wregex return FALSE; } +bool CGitLogListBase::ShouldShowFilter(GitRev *pRev, const std::map> &commitChildren) +{ + if (m_ShowFilter & FILTERSHOW_ANYCOMMIT) + return true; + + if (m_ShowFilter & FILTERSHOW_REFS) + { + // Keep all refs. + const STRING_VECTOR &refList = m_HashMap[pRev->m_CommitHash]; + if (!refList.empty()) + return true; + // Keep the head too. + if (pRev->m_CommitHash == m_HeadHash) + return true; + } + + if (m_ShowFilter & FILTERSHOW_MERGEPOINTS) + { + if (pRev->ParentsCount() > 1) + return true; + auto childrenIt = commitChildren.find(pRev->m_CommitHash); + if (childrenIt != commitChildren.end()) + { + const std::set &children = childrenIt->second; + if (children.size() > 1) + return true; + } + } + return false; +} + void CGitLogListBase::RecalculateShownList(CThreadSafePtrArray * pShownlist) { @@ -3534,7 +3591,14 @@ LRESULT CGitLogListBase::OnScrollToMessage(WPARAM itemToSelect, LPARAM /*lParam* { if (GetSelectedCount() != 0) return 0; + + CGitHash theSelectedHash = m_lastSelectedHash; SetItemState((int)itemToSelect, LVIS_SELECTED, LVIS_SELECTED); + m_lastSelectedHash = theSelectedHash; + + int countPerPage = GetCountPerPage(); + EnsureVisible(max(0, (int)itemToSelect-countPerPage/2), FALSE); + EnsureVisible(min(GetItemCount(), (int)itemToSelect+countPerPage/2), FALSE); EnsureVisible((int)itemToSelect, FALSE); return 0; } diff --git a/src/TortoiseProc/GitLogListBase.h b/src/TortoiseProc/GitLogListBase.h index f92d646ef..1e6c40ac3 100644 --- a/src/TortoiseProc/GitLogListBase.h +++ b/src/TortoiseProc/GitLogListBase.h @@ -78,13 +78,13 @@ enum LISTITEMSTATES_MINE { #define LOGFILTER_REFNAME 0x0080 #define LOGFILTER_EMAILS 0x0100 -#define LOGLIST_SHOWNOREFS 0x0000 -#define LOGLIST_SHOWLOCALBRANCHES 0x0001 -#define LOGLIST_SHOWREMOTEBRANCHES 0x0002 -#define LOGLIST_SHOWTAGS 0x0004 -#define LOGLIST_SHOWSTASH 0x0008 -#define LOGLIST_SHOWBISECT 0x0010 -#define LOGLIST_SHOWALLREFS 0xFFFF +#define LOGLIST_SHOWNOTHING 0x0000 +#define LOGLIST_SHOWLOCALBRANCHES 0x0001 +#define LOGLIST_SHOWREMOTEBRANCHES 0x0002 +#define LOGLIST_SHOWTAGS 0x0004 +#define LOGLIST_SHOWSTASH 0x0008 +#define LOGLIST_SHOWBISECT 0x0010 +#define LOGLIST_SHOWALLREFS 0xFFFF //typedef void CALLBACK_PROCESS(void * data, int progress); #define MSG_LOADED (WM_USER+110) @@ -299,6 +299,13 @@ public: ID_COPY_SUBJECT, ID_COPY_HASH, }; + enum FilterShow + { + FILTERSHOW_REFS = 1, + FILTERSHOW_MERGEPOINTS = 2, + FILTERSHOW_ANYCOMMIT = 4, + FILTERSHOW_ALL = FILTERSHOW_ANYCOMMIT | FILTERSHOW_REFS | FILTERSHOW_MERGEPOINTS + }; inline unsigned __int64 GetContextMenuBit(int i){ return ((unsigned __int64 )0x1)<> &commitChildren); CFindDlg *m_pFindDialog; static const UINT m_FindDialogMessage; @@ -324,6 +332,7 @@ public: void Clear(); DWORD m_SelectedFilters; + FilterShow m_ShowFilter; bool m_bFilterWithRegex; CLogDataVector m_logEntries; void RemoveFilter(); diff --git a/src/TortoiseProc/LogDataVector.cpp b/src/TortoiseProc/LogDataVector.cpp index 54f10053f..8aab83a5e 100644 --- a/src/TortoiseProc/LogDataVector.cpp +++ b/src/TortoiseProc/LogDataVector.cpp @@ -259,6 +259,15 @@ int CLogDataVector::ParserFromRefLog(CString ref) return 0; } +void CLogDataVector::append(CGitHash& sha, bool storeInVector) +{ + if (storeInVector) + this->push_back(sha); + + GitRev* r = &m_pLogCache->m_HashMap[sha]; + updateLanes(*r, this->m_Lns, sha); +} + void CLogDataVector::setLane(CGitHash& sha) { Lanes* l = &(this->m_Lns); diff --git a/src/TortoiseProc/LogDlg.cpp b/src/TortoiseProc/LogDlg.cpp index 2e4aa8b3b..a80d187a6 100644 --- a/src/TortoiseProc/LogDlg.cpp +++ b/src/TortoiseProc/LogDlg.cpp @@ -2317,6 +2317,19 @@ void CLogDlg::HandleShowLabels(bool var, int flag) m_LogList.Invalidate(); } +void CLogDlg::OnBnClickedCompressedGraph() +{ + UpdateData(); + + if (m_bCompressedGraph) + m_LogList.m_ShowFilter = static_cast(CGitLogListBase::FILTERSHOW_REFS | CGitLogListBase::FILTERSHOW_MERGEPOINTS); + else + m_LogList.m_ShowFilter = CGitLogListBase::FILTERSHOW_ALL; + + OnRefresh(); + FillLogMessageCtrl(false); +} + void CLogDlg::OnBnClickedBrowseRef() { CString newRef = CBrowseRefsDlg::PickRef(false, m_LogList.GetRange(), gPickRef_All, true); @@ -2377,6 +2390,7 @@ void AppendMenuChecked(CMenu &menu, UINT nTextID, UINT_PTR nItemID, BOOL checked #define WALKBEHAVIOUR_FIRSTPARENT 1 #define WALKBEHAVIOUR_FOLLOWRENAMES 2 +#define WALKBEHAVIOUR_COMPRESSEDGRAPH 3 void CLogDlg::OnBnClickedWalkBehaviour() { @@ -2385,6 +2399,8 @@ void CLogDlg::OnBnClickedWalkBehaviour() { AppendMenuChecked(popup, IDS_WALKBEHAVIOUR_FIRSTPARENT, WALKBEHAVIOUR_FIRSTPARENT, m_bFirstParent); AppendMenuChecked(popup, IDS_WALKBEHAVIOUR_FOLLOWRENAMES, WALKBEHAVIOUR_FOLLOWRENAMES, m_bFollowRenames, !(m_path.IsEmpty() || m_path.IsDirectory())); + popup.AppendMenu(MF_SEPARATOR, NULL); + AppendMenuChecked(popup, IDS_WALKBEHAVIOUR_COMPRESSED, WALKBEHAVIOUR_COMPRESSEDGRAPH, m_bCompressedGraph); m_tooltips.Pop(); RECT rect; @@ -2400,6 +2416,10 @@ void CLogDlg::OnBnClickedWalkBehaviour() m_bFollowRenames = !m_bFollowRenames; OnBnClickedFollowRenames(); break; + case WALKBEHAVIOUR_COMPRESSEDGRAPH: + m_bCompressedGraph = !m_bCompressedGraph; + OnBnClickedCompressedGraph(); + break; default: break; } diff --git a/src/TortoiseProc/LogDlg.h b/src/TortoiseProc/LogDlg.h index 877956c5c..f3858f79e 100644 --- a/src/TortoiseProc/LogDlg.h +++ b/src/TortoiseProc/LogDlg.h @@ -124,6 +124,7 @@ protected: afx_msg void OnBnClickedAllBranch(); void OnBnClickedFollowRenames(); void HandleShowLabels(bool var, int flag); + void OnBnClickedCompressedGraph(); afx_msg void OnBnClickedBrowseRef(); afx_msg void OnDtnDropdownDatefrom(NMHDR *pNMHDR, LRESULT *pResult); @@ -212,6 +213,7 @@ private: bool m_bShowLocalBranches; bool m_bShowRemoteBranches; bool m_bShowGravatar; + bool m_bCompressedGraph; CTGitPathList * m_currentChangedArray; LogChangedPathArray m_CurrentFilteredChangedArray; diff --git a/src/TortoiseProc/LogDlgHelper.h b/src/TortoiseProc/LogDlgHelper.h index 315ecedfb..2186c3d92 100644 --- a/src/TortoiseProc/LogDlgHelper.h +++ b/src/TortoiseProc/LogDlgHelper.h @@ -91,6 +91,7 @@ public: MAP_HASH_REV m_HashMap; void updateLanes(GitRev& c, Lanes& lns, CGitHash &sha) ; void setLane(CGitHash& sha) ; + void append(CGitHash& sha, bool storeInVector); BYTE_VECTOR m_RawlogData; std::vector m_RawLogStart; diff --git a/src/TortoiseProc/resource.h b/src/TortoiseProc/resource.h index 9a0174699..6a753a252 100644 --- a/src/TortoiseProc/resource.h +++ b/src/TortoiseProc/resource.h @@ -958,6 +958,7 @@ #define IDS_HINT 1460 #define IDS_VIEW_SHOWGRAVATAR 1461 #define IDC_SHOWUNVERSIONEDOVERLAY 1462 +#define IDS_WALKBEHAVIOUR_COMPRESSED 1462 #define IDC_LINK 1466 #define IDC_LINK_CHANGE_LOG 1467 #define IDC_EDIT1 1469 -- 2.11.4.GIT