diff options
author | Jim Raykowski <raykowj@gmail.com> | 2020-07-27 21:03:58 -0800 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2020-07-30 12:04:56 +0200 |
commit | dce97e84f2bb748e4403841593bb7b0b92ea44c4 (patch) | |
tree | 7804ec4277d6d56ecbd560eb7f218f1286ab94c5 | |
parent | 12ff89af74cd12375436b67b85674a4a2064ef8d (diff) |
tdf#38093 Writer outline folding - Navigator UI
Patch 5/6 that breaks down https://gerrit.libreoffice.org/c/core/+/96672
Adds submenu 'Outline Content Visibilty' and action handling for submenu
items to Navigator Headings context menu.
Change-Id: Iccdcbc7518a83cc1b2e2e75f3052f8dbbffb1338
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99656
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r-- | sw/inc/strings.hrc | 4 | ||||
-rw-r--r-- | sw/source/uibase/inc/conttree.hxx | 2 | ||||
-rw-r--r-- | sw/source/uibase/utlui/content.cxx | 178 | ||||
-rw-r--r-- | sw/uiconfig/swriter/ui/navigatorcontextmenu.ui | 20 |
4 files changed, 199 insertions, 5 deletions
diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc index 20d45f5cc19b..a9b2ab36d587 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -647,6 +647,10 @@ #define STR_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT NC_("STR_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT", "hold Ctrl or right-click to include sub levels") #define STR_ClICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY NC_("STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY", "Click to Toggle Outline Content Visibility") #define STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT NC_("STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT", "right-click to include sub levels") +#define STR_OUTLINE_CONTENT_VISIBILITY NC_("STR_OUTLINE_CONTENT", "Outline Content Visibility") +#define STR_OUTLINE_CONTENT_VISIBILITY_TOGGLE NC_("STR_OUTLINE_CONTENT_VISIBILITY_TOGGLE", "Toggle") +#define STR_OUTLINE_CONTENT_VISIBILITY_SHOW_ALL NC_("STR_OUTLINE_CONTENT_VISIBILITY_SHOW_ALL", "Show All") +#define STR_OUTLINE_CONTENT_VISIBILITY_HIDE_ALL NC_("STR_OUTLINE_CONTENT_VISIBILITY_HIDE_ALL", "Hide All") #define STR_EXPANDALL NC_("STR_EXPANDALL", "Expand All") #define STR_COLLAPSEALL NC_("STR_COLLAPSEALL", "Collapse All") diff --git a/sw/source/uibase/inc/conttree.hxx b/sw/source/uibase/inc/conttree.hxx index 0a090a1d18f0..6f65b1984523 100644 --- a/sw/source/uibase/inc/conttree.hxx +++ b/sw/source/uibase/inc/conttree.hxx @@ -121,7 +121,7 @@ class SwContentTree final : public SfxListener // outline root mode drag & drop std::vector<std::unique_ptr<weld::TreeIter>> m_aDndOutlinesSelected; - bool m_bIsInPromoteDemote = false; + bool m_bIgnoreViewChange = false; /** * Before any data will be deleted, the last active entry has to be found. diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx index 1fcd1873d8f3..e92cddc641ef 100644 --- a/sw/source/uibase/utlui/content.cxx +++ b/sw/source/uibase/utlui/content.cxx @@ -1152,6 +1152,122 @@ static bool lcl_InsertExpandCollapseAllItem(weld::TreeView& rContentTree, weld:: return true; } +static void lcl_SetOutlineContentEntriesSensitivities(SwContentTree* pThis, weld::TreeView& rContentTree, weld::TreeIter& rEntry, weld::Menu& rPop) +{ + rPop.set_sensitive(OString::number(1512), false); + rPop.set_sensitive(OString::number(1513), false); + rPop.set_sensitive(OString::number(1514), false); + + if (!pThis->GetActiveWrtShell()->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + return; + + // todo: multi selection + if (rContentTree.count_selected_rows() > 1) + return; + + const SwNodes& rNodes = pThis->GetWrtShell()->GetNodes(); + const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds(); + size_t nOutlinePos = weld::GetAbsPos(rContentTree, rEntry); + + bool bIsRoot = lcl_IsContentType(rEntry, rContentTree); + + if (!bIsRoot) + --nOutlinePos; + + if (nOutlinePos >= rOutlineNodes.size()) + return; + + int nFirstLevel = pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos); + { + // determine if any concerned outline node has content + bool bHasContent(false); + size_t nPos = nOutlinePos; + SwNode* pSttNd = rOutlineNodes[nPos]; + SwNode* pEndNd = &rNodes.GetEndOfContent(); + if (rOutlineNodes.size() > nPos + 1) + pEndNd = rOutlineNodes[nPos + 1]; + + // selected + SwNodeIndex aIdx(*pSttNd); + if (rNodes.GoNext(&aIdx) != pEndNd) + bHasContent = true; + + // decendants + if (!bHasContent && (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry))) + { + while (++nPos < rOutlineNodes.size() && + (bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel)) + { + pSttNd = rOutlineNodes[nPos]; + pEndNd = &rNodes.GetEndOfContent(); + if (rOutlineNodes.size() > nPos + 1) + pEndNd = rOutlineNodes[nPos + 1]; + + // test for content in outline node + aIdx.Assign(*pSttNd); + if (rNodes.GoNext(&aIdx) != pEndNd) + { + bHasContent = true; + break; + } + } + } + + if (!bHasContent) + return; // no content in any of the concerned outline nodes + } + + // determine for subs if all are folded or unfolded or if they are mixed + if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry)) + { + // skip no content nodes + // we know there is content from results above so this is presumably safe + size_t nPos = nOutlinePos; + while (true) + { + SwNode* pSttNd = rOutlineNodes[nPos]; + SwNode* pEndNd = rOutlineNodes.back(); + if (!bIsRoot && rOutlineNodes.size() > nPos + 1) + pEndNd = rOutlineNodes[nPos + 1]; + + SwNodeIndex aIdx(*pSttNd); + if (rNodes.GoNext(&aIdx) != pEndNd) + break; + nPos++; + } + + bool bHasFolded(pThis->GetWrtShell()->IsOutlineContentFolded(nPos)); + bool bHasUnfolded(!bHasFolded); + + while ((++nPos < pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount()) && + (bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel)) + { + + SwNode* pSttNd = rOutlineNodes[nPos]; + SwNode* pEndNd = &rNodes.GetEndOfContent(); + if (rOutlineNodes.size() > nPos + 1) + pEndNd = rOutlineNodes[nPos + 1]; + + SwNodeIndex aIdx(*pSttNd); + if (rNodes.GoNext(&aIdx) == pEndNd) + continue; // skip if no content + + if (pThis->GetWrtShell()->IsOutlineContentFolded(nPos)) + bHasFolded = true; + else + bHasUnfolded = true; + + if (bHasFolded && bHasUnfolded) + break; // mixed so no need to continue + } + + rPop.set_sensitive(OString::number(1513), bHasUnfolded); + rPop.set_sensitive(OString::number(1514), bHasFolded); + } + + bIsRoot ? rPop.remove(OString::number(1512)) : rPop.set_sensitive(OString::number(1512), true); +} + IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) { if (rCEvt.GetCommand() != CommandEventId::ContextMenu) @@ -1166,6 +1282,11 @@ IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) std::unique_ptr<weld::Menu> xSubPop3 = xBuilder->weld_menu("displaymenu"); std::unique_ptr<weld::Menu> xSubPopOutlineTracking = xBuilder->weld_menu("outlinetracking"); + std::unique_ptr<weld::Menu> xSubPopOutlineContent = xBuilder->weld_menu("outlinecontent"); + xSubPopOutlineContent->append(OUString::number(1512), SwResId(STR_OUTLINE_CONTENT_VISIBILITY_TOGGLE)); + xSubPopOutlineContent->append(OUString::number(1513), SwResId(STR_OUTLINE_CONTENT_VISIBILITY_HIDE_ALL)); + xSubPopOutlineContent->append(OUString::number(1514), SwResId(STR_OUTLINE_CONTENT_VISIBILITY_SHOW_ALL)); + for(int i = 1; i <= 3; ++i) xSubPopOutlineTracking->append_radio(OUString::number(i + 10), m_aContextStrings[IDX_STR_OUTLINE_TRACKING + i]); xSubPopOutlineTracking->set_active(OString::number(10 + m_nOutlineTracking), true); @@ -1259,6 +1380,7 @@ IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) if(ContentTypeId::OUTLINE == nContentType) { bOutline = true; + lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry, *xSubPopOutlineContent); bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop); if (!bReadonly) { @@ -1326,6 +1448,7 @@ IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) if (ContentTypeId::OUTLINE == pType->GetType()) { bOutline = true; + lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry, *xSubPopOutlineContent); bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop); bRemoveSendOutlineEntry = false; } @@ -1402,6 +1525,14 @@ IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool) xSubPopOutlineTracking.reset(); xPop->remove(OString::number(4)); // outline tracking menu } + if (!bOutline + || !m_pActiveShell->GetViewOptions()->IsShowOutlineContentVisibilityButton() + || m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() == 0) + { + xSubPopOutlineContent.reset(); + xPop->remove(OString::number(5)); // outline content menu + xPop->remove("separator1511"); + } OString sCommand = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))); if (!sCommand.isEmpty()) @@ -2036,7 +2167,7 @@ void SwContentTree::Display( bool bActive ) } } - if (!m_bIsInPromoteDemote && GetEntryCount() == nOldEntryCount) + if (!m_bIgnoreViewChange && GetEntryCount() == nOldEntryCount) { m_xTreeView->vadjustment_set_value(nOldScrollPos); } @@ -2545,7 +2676,7 @@ void SwContentTree::Notify(SfxBroadcaster & rBC, SfxHint const& rHint) switch (rHint.GetId()) { case SfxHintId::DocChanged: - if (!m_bIsInPromoteDemote) + if (!m_bIgnoreViewChange) { m_bViewHasChanged = true; TimerUpdate(&m_aUpdTimer); @@ -2590,7 +2721,7 @@ void SwContentTree::ExecCommand(const OString& rCmd, bool bOutlineWithChildren) return; } - m_bIsInPromoteDemote = true; + m_bIgnoreViewChange = true; SwWrtShell *const pShell = GetWrtShell(); sal_Int8 nActOutlineLevel = m_nOutlineLevel; @@ -2911,7 +3042,7 @@ void SwContentTree::ExecCommand(const OString& rCmd, bool bOutlineWithChildren) } } } - m_bIsInPromoteDemote = false; + m_bIgnoreViewChange = false; } void SwContentTree::ShowTree() @@ -3421,6 +3552,45 @@ void SwContentTree::ExecuteContextMenuAction(const OString& rSelectedPopupEntry) auto nSelectedPopupEntry = rSelectedPopupEntry.toUInt32(); switch (nSelectedPopupEntry) { + case 1512: // fold or unfold outline content of selected entry + case 1513: // fold outline content of selected entry and decendents + case 1514: // unfold outline content of selected entry and decendents + { + m_pActiveShell->EnterStdMode(); + m_bIgnoreViewChange = true; + SwOutlineContent* pCntFirst = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xFirst).toInt64()); + if (nSelectedPopupEntry == 1512) + { + m_pActiveShell->ToggleOutlineContentVisibility(pCntFirst->GetOutlinePos()); + } + else + { + // with subs + SwOutlineNodes::size_type nPos = pCntFirst->GetOutlinePos(); + if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry + nPos = SwOutlineNodes::npos; + SwOutlineNodes::size_type nOutlineNodesCount = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(); + int nLevel = -1; + if (nPos != SwOutlineNodes::npos) // not root + nLevel = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos); + else + nPos = 0; + bool bFold(nSelectedPopupEntry == 1514); + do + { + if (m_pActiveShell->IsOutlineContentFolded(nPos) == bFold) + m_pActiveShell->ToggleOutlineContentVisibility(nPos); + } while (++nPos < nOutlineNodesCount + && (nLevel == -1 || m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel)); + } + if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry + m_pActiveShell->GotoPage(1, true); + else + GotoContent(pCntFirst); + grab_focus(); + m_bIgnoreViewChange = false; + } + break; case 11: case 12: case 13: diff --git a/sw/uiconfig/swriter/ui/navigatorcontextmenu.ui b/sw/uiconfig/swriter/ui/navigatorcontextmenu.ui index b324c1a26c74..aecbc2cb1852 100644 --- a/sw/uiconfig/swriter/ui/navigatorcontextmenu.ui +++ b/sw/uiconfig/swriter/ui/navigatorcontextmenu.ui @@ -183,6 +183,26 @@ </object> </child> <child> + <object class="GtkMenuItem" id="5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="navigatorcontextmenu|STR_OUTLINE_CONTENT">Outline Content Visibility</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="outlinecontent"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + </child> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem" id="separator1511"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + </child> + <child> <object class="GtkMenuItem" id="4"> <property name="visible">True</property> <property name="can_focus">False</property> |