From c1936307755ae75741c91f89f9bda3a4eed1a274 Mon Sep 17 00:00:00 2001 From: Mohit Marathe Date: Fri, 12 Jul 2024 19:51:47 +0530 Subject: sort comments by time or position Change-Id: I1f4014e20b4baaca0dde742e7384397c1311f926 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170492 Reviewed-by: Sarper Akdemir Tested-by: Jenkins --- sw/source/uibase/sidebar/CommentsPanel.cxx | 209 ++++++++++++++++++++++------- sw/source/uibase/sidebar/CommentsPanel.hxx | 13 +- sw/uiconfig/swriter/ui/commentspanel.ui | 2 + 3 files changed, 172 insertions(+), 52 deletions(-) (limited to 'sw') diff --git a/sw/source/uibase/sidebar/CommentsPanel.cxx b/sw/source/uibase/sidebar/CommentsPanel.cxx index 1e5e3e4ea1eb..86f38f17829d 100644 --- a/sw/source/uibase/sidebar/CommentsPanel.cxx +++ b/sw/source/uibase/sidebar/CommentsPanel.cxx @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -46,6 +48,7 @@ #include #include "CommentsPanel.hxx" +#include #include @@ -84,29 +87,15 @@ void Comment::InitControls(const SwPostItField* pPostItField) maTime = tools::Time(pPostItField->GetDateTime().GetTime()); mbResolved = pPostItField->GetResolved(); - // Format date and time according to the system locale - const SvtSysLocale aSysLocale; - const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData(); - OUString sMeta; - if (maDate.IsValidAndGregorian()) - { - sMeta = rLocalData.getDate(maDate); - } - else - { - sMeta = SwResId(STR_NODATE); - } - if (mxDate->get_label() != sMeta) - { - mxDate->set_label(sMeta); - } - if (pPostItField->GetTime().GetTime() != 0) + OUString sDate = sw::sidebar::CommentsPanel::FormatDate(maDate); + OUString sTime = sw::sidebar::CommentsPanel::FormatTime(maTime); + if (mxDate->get_label() != sDate) { - sMeta = " " + rLocalData.getTime(pPostItField->GetTime(), false); + mxDate->set_label(sDate); } - if (mxTime->get_label() != sMeta) + if (mxTime->get_label() != sTime) { - mxTime->set_label(sMeta); + mxTime->set_label(sTime); } mxAuthor->set_label(msAuthor); @@ -155,6 +144,9 @@ CommentsPanel::CommentsPanel(weld::Widget* pParent) , mxSortbyTime(m_xBuilder->weld_radio_button("sortby_time")) , mxThreadsContainer(m_xBuilder->weld_box("comment_threads")) { + mxSortbyPosition->connect_toggled(LINK(this, CommentsPanel, SortHdl)); + mxSortbyTime->connect_toggled(LINK(this, CommentsPanel, SortHdl)); + SwView* pView = GetActiveView(); if (!pView) return; @@ -165,6 +157,8 @@ CommentsPanel::CommentsPanel(weld::Widget* pParent) StartListening(*mpPostItMgr); } +IMPL_LINK_NOARG(CommentsPanel, SortHdl, weld::Toggleable&, void) { populateComments(); } + void CommentsPanel::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) { if (rHint.GetId() == SfxHintId::SwFormatField) @@ -195,7 +189,8 @@ void CommentsPanel::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) { sw::annotation::SwAnnotationWin* pAnnotationWin = mpPostItMgr->GetRemovedAnnotationWin(pField); - deleteComment(pAnnotationWin); + sal_uInt32 nId = getPostItId(pAnnotationWin); + deleteComment(nId); break; } case SwFormatFieldHintWhich::FOCUS: @@ -216,6 +211,34 @@ void CommentsPanel::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) } } +OUString CommentsPanel::FormatDate(Date& rDate) +{ + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData(); + OUString sMeta; + if (rDate.IsValidAndGregorian()) + { + sMeta = rLocalData.getDate(rDate); + } + else + { + sMeta = SwResId(STR_NODATE); + } + return sMeta; +} + +OUString CommentsPanel::FormatTime(tools::Time& rTime) +{ + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData(); + OUString sMeta; + if (rTime.GetTime() != 0) + { + sMeta = " " + rLocalData.getTime(rTime, false); + } + return sMeta; +} + sw::annotation::SwAnnotationWin* CommentsPanel::getRootCommentWin(const SwFormatField* pFormatField) { if (!pFormatField) @@ -261,40 +284,125 @@ sw::annotation::SwAnnotationWin* CommentsPanel::getAnnotationWin(Comment* pComme return mpPostItMgr->GetAnnotationWin(pPostItField); } +bool CommentsPanel::comp_dateTime(SwFormatField* a, SwFormatField* b) +{ + SwPostItField* pA = static_cast(a->GetField()); + SwPostItField* pB = static_cast(b->GetField()); + + Date aDateA(pA->GetDateTime().GetDate()); + tools::Time aTimeA(pA->GetDateTime().GetTime()); + Date aDateB(pB->GetDateTime().GetDate()); + tools::Time aTimeB(pB->GetDateTime().GetTime()); + + OUString sDateTimeA = FormatTime(aTimeA) + " " + FormatDate(aDateA); + OUString sDateTimeB = FormatTime(aTimeB) + " " + FormatDate(aDateB); + + return sDateTimeA > sDateTimeB; +} + +SwPosition CommentsPanel::getAnchorPosition(SwFormatField* pField) +{ + SwTextField* pTextField = pField->GetTextField(); + SwTextNode* pTextNode = pTextField->GetpTextNode(); + + SwPosition aPos(*pTextNode, pTextField->GetStart()); + return aPos; +} + +bool CommentsPanel::comp_position(SwFormatField* a, SwFormatField* b) +{ + SwPosition aPosA = getAnchorPosition(a); + SwPosition aPosB = getAnchorPosition(b); + + return aPosA < aPosB; +} + void CommentsPanel::populateComments() { + if (!mpCommentsMap.empty()) + { + for (auto it = mpCommentsMap.begin(); it != mpCommentsMap.end();) + { + sal_uInt32 nId = it->first; + it++; + deleteComment(nId); + } + } + if (!mpPostItMgr) return; std::vector vFormatFields = mpPostItMgr->UpdatePostItsParentInfo(); + if (mxSortbyTime->get_active()) + { + std::sort(vFormatFields.begin(), vFormatFields.end(), + [](SwFormatField* a, SwFormatField* b) { + return sw::sidebar::CommentsPanel::comp_dateTime(a, b); + }); + } + else + { + std::stable_sort(vFormatFields.begin(), vFormatFields.end(), + [](SwFormatField* a, SwFormatField* b) { + return sw::sidebar::CommentsPanel::comp_position(a, b); + }); + } for (auto pFormatField : vFormatFields) { sw::annotation::SwAnnotationWin* pRootNote = getRootCommentWin(pFormatField); if (!pRootNote) continue; - sal_uInt32 nPostItId = getPostItId(pRootNote); + sal_uInt32 nRootId = getPostItId(pRootNote); - if (mpThreadsMap.find(nPostItId) != mpThreadsMap.end()) - continue; // Skip if root comment is already present + if (mpThreadsMap.find(nRootId) != mpThreadsMap.end()) + { + if (mxSortbyPosition->get_active()) + continue; + else + { + auto pThread = mpThreadsMap[nRootId].get(); + SwPostItField* pPostItField = static_cast(pFormatField->GetField()); + sal_uInt32 nId = pPostItField->GetPostItId(); + auto pComment = std::make_unique(pThread->getCommentBoxWidget(), *this); + pThread->getCommentBoxWidget()->reorder_child(pComment->get_widget(), + pThread->mnComments++); + pComment->InitControls(pPostItField); + mpCommentsMap[nId] = std::move(pComment); + continue; + } + } auto pThread = std::make_unique(mxThreadsContainer.get()); mxThreadsContainer->reorder_child(pThread->get_widget(), mnThreads++); - for (sw::annotation::SwAnnotationWin* pCurrent = pRootNote;;) + if (mxSortbyPosition->get_active()) + { + for (sw::annotation::SwAnnotationWin* pCurrent = pRootNote;;) + { + sal_uInt32 nId = getPostItId(pCurrent); + auto pComment = std::make_unique(pThread->getCommentBoxWidget(), *this); + pThread->getCommentBoxWidget()->reorder_child(pComment->get_widget(), + pThread->mnComments++); + pComment->InitControls(pCurrent->GetPostItField()); + mpCommentsMap[nId] = std::move(pComment); + sw::annotation::SwAnnotationWin* next + = mpPostItMgr->GetNextPostIt(KEY_PAGEDOWN, pCurrent); + if (!next || next->GetTopReplyNote() != pRootNote) + break; + pCurrent = next; + } + } + else { - sal_uInt32 nId = getPostItId(pCurrent); + SwPostItField* pPostItField = static_cast(pFormatField->GetField()); + sal_uInt32 nId = pPostItField->GetPostItId(); auto pComment = std::make_unique(pThread->getCommentBoxWidget(), *this); pThread->getCommentBoxWidget()->reorder_child(pComment->get_widget(), pThread->mnComments++); - pComment->InitControls(pCurrent->GetPostItField()); + pComment->InitControls(pPostItField); mpCommentsMap[nId] = std::move(pComment); - sw::annotation::SwAnnotationWin* next - = mpPostItMgr->GetNextPostIt(KEY_PAGEDOWN, pCurrent); - if (!next || next->GetTopReplyNote() != pRootNote) - break; - pCurrent = next; } - mpThreadsMap[nPostItId] = std::move(pThread); + mpThreadsMap[nRootId] = std::move(pThread); } } @@ -337,35 +445,34 @@ void CommentsPanel::addComment(const SwFormatField* pField) pComment->InitControls(pNote->GetPostItField()); mpCommentsMap[nNoteId] = std::move(pComment); } + populateComments(); } -void CommentsPanel::deleteComment(sw::annotation::SwAnnotationWin* pAnnotationWin) +void CommentsPanel::deleteComment(sal_uInt32 nId) { - if (!pAnnotationWin) - return; - sal_uInt32 nId = getPostItId(pAnnotationWin); + sw::annotation::SwAnnotationWin* pAnnotationWin = getAnnotationWin(mpCommentsMap[nId].get()); SwFormatField* pFormatField = pAnnotationWin->GetFormatField(); - sw::annotation::SwAnnotationWin* pRootNote = nullptr; - // If the root comment is deleted, the new root comment of the thread should be the next comment in the thread - // but due to a bug `getRootCommentWin` returns root comment of some other/random thread so we completely lose - // access to the current thread. - if (mpThreadsMap.find(nId) != mpThreadsMap.end()) - { - pRootNote = pAnnotationWin; - } - else - { - pRootNote = getRootCommentWin(pFormatField); - } + sw::annotation::SwAnnotationWin* pRootNote = getRootCommentWin(pFormatField); + // // If the root comment is deleted, the new root comment of the thread should be the next comment in the thread + // // but due to a bug `getRootCommentWin` returns root comment of some other/random thread so we completely lose + // // access to the current thread. + // if (mpThreadsMap.find(nId) != mpThreadsMap.end()) + // { + // pRootNote = mpThreadsMap[nId]; + // } + // else + // { + // pRootNote = getRootCommentWin(pFormatField); + // } sal_uInt32 nRootId = getPostItId(pRootNote); if (mpThreadsMap.find(nRootId) == mpThreadsMap.end()) - return; + throw std::runtime_error("Cannot delete comment: Thread does not exist"); auto& pComment = mpCommentsMap[nId]; auto& pThread = mpThreadsMap[nRootId]; if (!pComment) - return; + throw std::runtime_error("Cannot delete comment: Comment does not exist"); pThread->getCommentBoxWidget()->move(pComment->get_widget(), nullptr); mpCommentsMap.erase(nId); diff --git a/sw/source/uibase/sidebar/CommentsPanel.hxx b/sw/source/uibase/sidebar/CommentsPanel.hxx index 3e20ac47798e..9c214d88bb56 100644 --- a/sw/source/uibase/sidebar/CommentsPanel.hxx +++ b/sw/source/uibase/sidebar/CommentsPanel.hxx @@ -126,6 +126,12 @@ public: void ReplyComment(Comment* pComment); + DECL_LINK(SortHdl, weld::Toggleable&, void); + + // utility functions + static OUString FormatDate(Date& rDate); + static OUString FormatTime(tools::Time& rTime); + private: SwPostItMgr* mpPostItMgr; @@ -142,13 +148,18 @@ private: sal_uInt16 mnThreads = 0; + // utility functions sw::annotation::SwAnnotationWin* getRootCommentWin(const SwFormatField* pField); static sal_uInt32 getPostItId(sw::annotation::SwAnnotationWin* pAnnotationWin); sw::annotation::SwAnnotationWin* getAnnotationWin(Comment* pComment); + static bool comp_dateTime(SwFormatField* a, SwFormatField* b); + static SwPosition getAnchorPosition(SwFormatField* pField); + static bool comp_position(SwFormatField* a, SwFormatField* b); + // event handlers (To sync with AnnotationWin) void populateComments(); void addComment(const SwFormatField* pField); - void deleteComment(sw::annotation::SwAnnotationWin* pAnnotationWin); + void deleteComment(sal_uInt32 nId); void setResolvedStatus(sw::annotation::SwAnnotationWin* pAnnotationWin); static void editComment(SwPostItField* pPostItField, Comment* pComment); }; diff --git a/sw/uiconfig/swriter/ui/commentspanel.ui b/sw/uiconfig/swriter/ui/commentspanel.ui index da3f6d4f70cd..739e5f18a38c 100644 --- a/sw/uiconfig/swriter/ui/commentspanel.ui +++ b/sw/uiconfig/swriter/ui/commentspanel.ui @@ -59,6 +59,7 @@ center True True + True True @@ -76,6 +77,7 @@ True True True + sortby_position 1 -- cgit v1.2.3