diff options
author | Jim Raykowski <raykowj@gmail.com> | 2020-07-27 17:52:41 -0800 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2020-07-30 12:03:56 +0200 |
commit | 835cd06a047717dfe5e0f117959f3c042e13b21b (patch) | |
tree | 74a334fb89d401370e9dcd51d5a3c4ad93edcc64 /sw/source | |
parent | b2686de46250d0c8d14365a2af8428387baa0c24 (diff) |
tdf#38093 Writer outline folding - outline visibility and on canvas ui
Patch 2/6
Outline content visibility and on canvas collapse/expand control button
implementations.
Change-Id: I8481125b102d2f07bfcfce91e1379d8e786a7aa2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99653
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'sw/source')
-rw-r--r-- | sw/source/core/crsr/crstrvl.cxx | 8 | ||||
-rw-r--r-- | sw/source/core/txtnode/ndtxt.cxx | 20 | ||||
-rw-r--r-- | sw/source/uibase/docvw/FrameControlsManager.cxx | 108 | ||||
-rw-r--r-- | sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx | 237 | ||||
-rw-r--r-- | sw/source/uibase/docvw/edtwin.cxx | 133 | ||||
-rw-r--r-- | sw/source/uibase/docvw/edtwin2.cxx | 4 | ||||
-rw-r--r-- | sw/source/uibase/inc/FrameControlsManager.hxx | 5 | ||||
-rw-r--r-- | sw/source/uibase/inc/OutlineContentVisibilityWin.hxx | 49 | ||||
-rw-r--r-- | sw/source/uibase/inc/edtwin.hxx | 7 | ||||
-rw-r--r-- | sw/source/uibase/inc/wrtsh.hxx | 4 | ||||
-rw-r--r-- | sw/source/uibase/utlui/content.cxx | 61 | ||||
-rw-r--r-- | sw/source/uibase/wrtsh/wrtsh1.cxx | 120 |
12 files changed, 752 insertions, 4 deletions
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index 5ee44842b56f..5bea3f176289 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -1278,11 +1278,13 @@ bool SwCursorShell::GetContentAtPos( const Point& rPt, && IsAttrAtPos::Outline & rContentAtPos.eContentAtPos && !rNds.GetOutLineNds().empty() ) { - const SwTextNode* pONd = pTextNd->FindOutlineNodeOfLevel(MAXLEVEL-1, GetLayout()); - if( pONd ) + // only for nodes in outline nodes + SwOutlineNodes::size_type nPos; + if(rNds.GetOutLineNds().Seek_Entry(pTextNd, &nPos)) { rContentAtPos.eContentAtPos = IsAttrAtPos::Outline; - rContentAtPos.sStr = sw::GetExpandTextMerged(GetLayout(), *pONd, true, false, ExpandMode::ExpandFootnote); + rContentAtPos.sStr = sw::GetExpandTextMerged(GetLayout(), *pTextNd, true, false, ExpandMode::ExpandFootnote); + rContentAtPos.aFnd.pNode = pTextNd; bRet = true; } } diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 6200eb040abd..56fa589eaef5 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -71,6 +71,7 @@ #include <numrule.hxx> #include <docsh.hxx> #include <SwNodeNum.hxx> +#include <svl/grabbagitem.hxx> #include <svl/intitem.hxx> #include <list.hxx> #include <sortedobjs.hxx> @@ -4036,6 +4037,25 @@ void SwTextNode::SetAttrOutlineLevel(int nLevel) } } +bool SwTextNode::GetAttrOutlineContentVisible(bool& bOutlineContentVisibleAttr) +{ + SfxGrabBagItem aGrabBagItem(dynamic_cast<const SfxGrabBagItem&>(GetAttr(RES_PARATR_GRABBAG))); + auto it = aGrabBagItem.GetGrabBag().find("OutlineContentVisibleAttr"); + if (it != aGrabBagItem.GetGrabBag().end()) + { + it->second >>= bOutlineContentVisibleAttr; + return true; + } + return false; +} + +void SwTextNode::SetAttrOutlineContentVisible(bool bVisible) +{ + SfxGrabBagItem aGrabBagItem(RES_PARATR_GRABBAG); + aGrabBagItem.GetGrabBag()["OutlineContentVisibleAttr"] <<= bVisible; + GetTextNode()->SetAttr(aGrabBagItem); +} + // #i70748# void SwTextNode::SetEmptyListStyleDueToSetOutlineLevelAttr() diff --git a/sw/source/uibase/docvw/FrameControlsManager.cxx b/sw/source/uibase/docvw/FrameControlsManager.cxx index 9d68bc950435..63bca779d473 100644 --- a/sw/source/uibase/docvw/FrameControlsManager.cxx +++ b/sw/source/uibase/docvw/FrameControlsManager.cxx @@ -17,6 +17,10 @@ #include <viewopt.hxx> #include <view.hxx> #include <wrtsh.hxx> +#include <txtfrm.hxx> +#include <OutlineContentVisibilityWin.hxx> +#include <ndtxt.hxx> +#include <IDocumentOutlineNodes.hxx> using namespace std; @@ -33,6 +37,7 @@ SwFrameControlsManager::~SwFrameControlsManager() void SwFrameControlsManager::dispose() { m_aControls.clear(); + m_aTextNodeContentFrameMap.clear(); } SwFrameControlPtr SwFrameControlsManager::GetControl( FrameControlType eType, const SwFrame* pFrame ) @@ -179,6 +184,109 @@ SwFrameMenuButtonBase::SwFrameMenuButtonBase( SwEditWin* pEditWin, const SwFrame { } +void SwFrameControlsManager::SetOutlineContentVisibilityButtons() +{ + // remove entries with outline node keys that are not in the outline nodes list + IDocumentOutlineNodes::tSortedOutlineNodeList aOutlineNodes; + m_pEditWin->GetView().GetWrtShell().getIDocumentOutlineNodesAccess()->getOutlineNodes(aOutlineNodes); + std::map<const SwTextNode*, const SwContentFrame*>::iterator it = m_aTextNodeContentFrameMap.begin(); + while(it != m_aTextNodeContentFrameMap.end()) + { + const SwNode* pNd = it->first; + IDocumentOutlineNodes::tSortedOutlineNodeList::iterator i = std::find(aOutlineNodes.begin(), aOutlineNodes.end(), pNd); + if (i == aOutlineNodes.end()) + { + RemoveControlsByType(FrameControlType::Outline, it->second); + it = m_aTextNodeContentFrameMap.erase(it); + } + else + it++; + } + for (SwNode* pNd : m_pEditWin->GetView().GetWrtShell().GetNodes().GetOutLineNds()) + { + bool bOutlineContentVisibleAttr = true; + pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); + if (!bOutlineContentVisibleAttr) + SetOutlineContentVisibilityButton(pNd->GetTextNode()); + } +} + +void SwFrameControlsManager::SetOutlineContentVisibilityButton(const SwTextNode* pTextNd) +{ + const SwContentFrame* pContentFrame = pTextNd->getLayoutFrame(nullptr); + + // has node frame changed or been deleted + std::map<const SwTextNode*, const SwContentFrame*>::iterator iter = m_aTextNodeContentFrameMap.find(pTextNd); + if (iter != m_aTextNodeContentFrameMap.end()) + { + const SwContentFrame* pFrameWas = iter->second; + if (pContentFrame != pFrameWas) + { + // frame does not match frame in map for node + RemoveControlsByType(FrameControlType::Outline, pFrameWas); + m_aTextNodeContentFrameMap.erase(iter); + } + } + if (pContentFrame && !pContentFrame->IsInDtor()) + { + // frame is not being destroyed and isn't in map + m_aTextNodeContentFrameMap.insert(make_pair(pTextNd, pContentFrame)); + } + else + { + if (pContentFrame) + { + // frame is being destroyed + RemoveControlsByType(FrameControlType::Outline, pContentFrame); + } + return; + } + + // Check if we already have the control + SwFrameControlPtr pControl; + + SwFrameControlPtrMap& rControls = m_aControls[FrameControlType::Outline]; + + SwFrameControlPtrMap::iterator lb = rControls.lower_bound(pContentFrame); + if (lb != rControls.end() && !(rControls.key_comp()(pContentFrame, lb->first))) + { + pControl = lb->second; + } + else + { + SwFrameControlPtr pNewControl = + std::make_shared<SwFrameControl>(VclPtr<SwOutlineContentVisibilityWin>::Create( + m_pEditWin, pContentFrame).get()); + rControls.insert(lb, make_pair(pContentFrame, pNewControl)); + pControl.swap(pNewControl); + } + + SwOutlineContentVisibilityWin* pWin = dynamic_cast<SwOutlineContentVisibilityWin *>(pControl->GetWindow()); + assert(pWin != nullptr) ; + pWin->Set(); + + if (pWin->GetSymbol() == SymbolType::ARROW_RIGHT) + { + // show expand button immediatly + pWin->Show(); + // outline content might not be folded, this happens on undo, outline moves, and folded outline content reveals + SwOutlineNodes::size_type nPos; + SwOutlineNodes rOutlineNds = m_pEditWin->GetView().GetWrtShell().GetNodes().GetOutLineNds(); + if (rOutlineNds.Seek_Entry(const_cast<SwTextNode*>(pTextNd), &nPos)) + { + // don't toggle if next node is an outline node or end node + SwNodeIndex aIdx(*pTextNd, 1); + if (!(aIdx.GetNode().IsEndNode() || ((nPos + 1 < rOutlineNds.size()) && &aIdx.GetNode() == rOutlineNds[nPos +1])) + && aIdx.GetNode().IsContentNode() && aIdx.GetNode().GetContentNode()->getLayoutFrame(nullptr)) + { + m_pEditWin->GetView().GetWrtShell().ToggleOutlineContentVisibility(nPos, true); // force fold + } + } + } + else if (!pWin->IsVisible() && pWin->GetSymbol() == SymbolType::ARROW_DOWN) + pWin->ShowAll(true); +} + const SwPageFrame* SwFrameMenuButtonBase::GetPageFrame() const { if (m_pFrame->IsPageFrame()) diff --git a/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx b/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx new file mode 100644 index 000000000000..44772f367813 --- /dev/null +++ b/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <edtwin.hxx> +#include <OutlineContentVisibilityWin.hxx> +#include <view.hxx> +#include <viewopt.hxx> +#include <wrtsh.hxx> + +#include <memory> + +#include <IDocumentOutlineNodes.hxx> +#include <txtfrm.hxx> +#include <ndtxt.hxx> +#include <vcl/button.hxx> +#include <vcl/event.hxx> +#include <strings.hrc> +#include <svx/svdview.hxx> + +#define BUTTON_WIDTH 18 +#define BUTTON_HEIGHT 20 + +SwOutlineContentVisibilityWin::SwOutlineContentVisibilityWin(SwEditWin* pEditWin, + const SwFrame* pFrame) + : PushButton(pEditWin, 0) + , m_pEditWin(pEditWin) + , m_pFrame(pFrame) + , m_nDelayAppearing(0) + , m_bDestroyed(false) +{ + SetSizePixel(Size(BUTTON_WIDTH, BUTTON_HEIGHT)); + + m_aDelayTimer.SetTimeout(50); + m_aDelayTimer.SetInvokeHandler(LINK(this, SwOutlineContentVisibilityWin, DelayHandler)); +} + +void SwOutlineContentVisibilityWin::dispose() +{ + m_bDestroyed = true; + m_aDelayTimer.Stop(); + + m_pEditWin.clear(); + m_pFrame = nullptr; + + PushButton::dispose(); +} + +void SwOutlineContentVisibilityWin::Set() +{ + const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(GetFrame()); + + // outline node frame containing folded outline node content might be folded so need to hide it + if (!pTextFrame || pTextFrame->IsInDtor()) + { + SetSymbol(SymbolType::DONTKNOW); + Hide(); + return; + } + const SwTextNode* pTextNode = pTextFrame->GetTextNodeFirst(); + SwWrtShell& rSh = GetEditWin()->GetView().GetWrtShell(); + const SwOutlineNodes& rOutlineNodes = rSh.GetNodes().GetOutLineNds(); + rOutlineNodes.Seek_Entry(static_cast<SwNode*>(const_cast<SwTextNode*>(pTextNode)), + &m_nOutlinePos); + assert(m_nOutlinePos != SwOutlineNodes::npos); + + // don't set if no content and no subs with content + auto nPos = m_nOutlinePos; + SwNode* pSttNd = rOutlineNodes[nPos]; + SwNode* pEndNd; + SwNodeIndex aIdx(*pSttNd); + while (true) + { + if (rOutlineNodes.size() > ++nPos) + pEndNd = rOutlineNodes[nPos]; + else + pEndNd = &rSh.GetNodes().GetEndOfContent(); + if (!pSttNd->IsEndNode()) + aIdx.Assign(*pSttNd, +1); + if (pSttNd->IsEndNode() + || ((&aIdx.GetNode() == pEndNd && pEndNd->IsEndNode()) + || (&aIdx.GetNode() == pEndNd && pSttNd->IsTextNode() && pEndNd->IsTextNode() + && pSttNd->GetTextNode()->GetAttrOutlineLevel() + >= pEndNd->GetTextNode()->GetAttrOutlineLevel()))) + { + SetSymbol(SymbolType::DONTKNOW); + Hide(); + return; + } + if (&aIdx.GetNode() != pEndNd) + break; + pSttNd = pEndNd; + } + + // set symbol displayed on button + SetSymbol(rSh.IsOutlineContentFolded(m_nOutlinePos) ? SymbolType::ARROW_RIGHT + : SymbolType::ARROW_DOWN); + + // set quick help + SwOutlineNodes::size_type nOutlineNodesCount + = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount(); + int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(m_nOutlinePos); + OUString sQuickHelp(SwResId(STR_OUTLINE_CONTENT_TOGGLE_VISIBILITY)); + if (m_nOutlinePos + 1 < nOutlineNodesCount + && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(m_nOutlinePos + 1) > nLevel) + sQuickHelp += " (" + SwResId(STR_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT) + ")"; + SetQuickHelpText(sQuickHelp); + + // Set the position of the window + SwRect aSwRect = GetFrame()->getFrameArea(); // not far in margin + //SwRect aSwRect = GetFrame()->GetPaintArea(); // far in margin + aSwRect.AddTop(GetFrame()->GetTopMargin()); + Point aPxPt(GetEditWin()->GetOutDev()->LogicToPixel( + aSwRect.TopLeft() - (aSwRect.TopLeft() - aSwRect.BottomLeft()) / 2)); + aPxPt.AdjustX(-GetSizePixel().getWidth() + 1); + aPxPt.AdjustY(-GetSizePixel().getHeight() / 2); + SetPosPixel(aPxPt); +} + +void SwOutlineContentVisibilityWin::ShowAll(bool bShow) +{ + if (bShow) + { + m_nDelayAppearing = 0; + if (!m_bDestroyed && m_aDelayTimer.IsActive()) + m_aDelayTimer.Stop(); + if (!m_bDestroyed) + m_aDelayTimer.Start(); + } + else + Hide(); +} + +bool SwOutlineContentVisibilityWin::Contains(const Point& rDocPt) const +{ + ::tools::Rectangle aRect(GetPosPixel(), GetSizePixel()); + if (aRect.IsInside(rDocPt)) + return true; + return false; +} + +void SwOutlineContentVisibilityWin::ToggleOutlineContentVisibility(const bool bSubs) +{ + SwWrtShell& rSh = GetEditWin()->GetView().GetWrtShell(); + rSh.LockView(true); + if (GetEditWin()->GetView().GetDrawView()->IsTextEdit()) + rSh.EndTextEdit(); + if (GetEditWin()->GetView().IsDrawMode()) + GetEditWin()->GetView().LeaveDrawCreate(); + rSh.EnterStdMode(); + if (bSubs) + { + // toggle including sub levels + SwOutlineNodes::size_type nPos = m_nOutlinePos; + SwOutlineNodes::size_type nOutlineNodesCount + = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount(); + int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(m_nOutlinePos); + bool bFold = rSh.IsOutlineContentFolded(m_nOutlinePos); + do + { + if (rSh.IsOutlineContentFolded(nPos) == bFold) + rSh.ToggleOutlineContentVisibility(nPos); + } while (++nPos < nOutlineNodesCount + && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel); + } + else + rSh.ToggleOutlineContentVisibility(m_nOutlinePos); + SetSymbol(rSh.IsOutlineContentFolded(m_nOutlinePos) ? SymbolType::ARROW_RIGHT + : SymbolType::ARROW_DOWN); + rSh.GotoOutline(m_nOutlinePos); // sets cursor position + rSh.LockView(false); +} + +void SwOutlineContentVisibilityWin::KeyInput(const KeyEvent& rKEvt) +{ + vcl::KeyCode aKeyCode = rKEvt.GetKeyCode(); + if (!aKeyCode.GetModifier() + && (aKeyCode.GetCode() == KEY_RETURN || aKeyCode.GetCode() == KEY_SPACE)) + { + ToggleOutlineContentVisibility(aKeyCode.GetCode() == KEY_RETURN); + } + else if (aKeyCode.GetCode() == KEY_ESCAPE) + { + Hide(); + GrabFocusToDocument(); + } +} + +void SwOutlineContentVisibilityWin::MouseMove(const MouseEvent& rMEvt) +{ + if (rMEvt.IsLeaveWindow()) + { + // MouseMove event may not be seen by edit window + // hide collapse button and grab focus to document + if (GetSymbol() != SymbolType::ARROW_RIGHT) + Hide(); + GrabFocusToDocument(); + } + else if (rMEvt.IsEnterWindow()) + { + if (!m_bDestroyed && m_aDelayTimer.IsActive()) + m_aDelayTimer.Stop(); + // bring button to top and grab focus + SetZOrder(this, ZOrderFlags::First); + GrabFocus(); + } + GetEditWin()->SetSavedOutlineFrame(const_cast<SwFrame*>(GetFrame())); +} + +void SwOutlineContentVisibilityWin::MouseButtonDown(const MouseEvent& rMEvt) +{ + ToggleOutlineContentVisibility(rMEvt.IsRight() || rMEvt.IsMod1()); +} + +IMPL_LINK_NOARG(SwOutlineContentVisibilityWin, DelayHandler, Timer*, void) +{ + const int TICKS_BEFORE_WE_APPEAR = 5; + if (m_nDelayAppearing < TICKS_BEFORE_WE_APPEAR) + { + ++m_nDelayAppearing; + m_aDelayTimer.Start(); + return; + } + if (GetEditWin()->GetSavedOutlineFrame() == GetFrame()) + { + Show(); + GrabFocus(); + } + m_aDelayTimer.Stop(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 2a2d6634a0ea..8f0751024e2d 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -139,6 +139,11 @@ #include <sfx2/event.hxx> #include <memory> +#include <IDocumentOutlineNodes.hxx> +#include <ndtxt.hxx> +#include <cntfrm.hxx> +#include <txtfrm.hxx> + using namespace sw::mark; using namespace ::com::sun::star; @@ -1330,6 +1335,32 @@ void SwEditWin::KeyInput(const KeyEvent &rKEvt) } } + if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + // not allowed if outline content is folded + sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode(); + if ((rSh.IsSttPara() && (nKey == KEY_BACKSPACE || nKey == KEY_LEFT)) + || (rSh.IsEndOfPara() && (nKey == KEY_DELETE || nKey == KEY_RETURN || nKey == KEY_RIGHT))) + { + SwContentNode* pContentNode = rSh.GetCurrentShellCursor().GetContentNode(); + SwOutlineNodes::size_type nPos; + if (rSh.GetDoc()->GetNodes().GetOutLineNds().Seek_Entry(pContentNode, &nPos)) + { + bool bOutlineContentVisibleAttr = true; + pContentNode->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); + if (!bOutlineContentVisibleAttr) + return; // outline node is folded + if (rSh.IsSttPara() && (nKey == KEY_BACKSPACE || nKey == KEY_LEFT) && (nPos-1 != SwOutlineNodes::npos)) + { + bOutlineContentVisibleAttr = true; + rSh.GetDoc()->GetNodes().GetOutLineNds()[nPos-1]->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); + if (!bOutlineContentVisibleAttr) + return; // previous outline node is folded + } + } + } + } + if( rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE && m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard ) { @@ -2628,6 +2659,10 @@ KEYINPUT_CHECKTABLE_INSDEL: } } + // x11 backend doesn't like not having this + if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()) + GetFrameControlsManager().SetOutlineContentVisibilityButtons(); + // update the page number in the statusbar sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode(); if( KEY_UP == nKey || KEY_DOWN == nKey || KEY_PAGEUP == nKey || KEY_PAGEDOWN == nKey ) @@ -3813,6 +3848,52 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt) if( rSh.ActionPend() ) return ; + if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + // add/remove outline collapse button + SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline); + if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), aSwContentAtPos)) + { + if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode()) + { + const SwNodes& rNds = rSh.GetDoc()->GetNodes(); + SwOutlineNodes::size_type nPos; + SwContentFrame* pContentFrame = aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(nullptr); + if (pContentFrame != m_pSavedOutlineFrame) + { + // remove collapse button when saved frame is not frame at mouse position + if (m_pSavedOutlineFrame && /* is it possible that m_pSavedOutlineFrame is removed? */ !m_pSavedOutlineFrame->IsInDtor() && + rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos) && + !rSh.IsOutlineContentFolded(nPos)) + { + GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame); + } + m_pSavedOutlineFrame = pContentFrame; + } + // show collapse button + if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos) && + !rSh.IsOutlineContentFolded(nPos)) + { + GetFrameControlsManager().SetOutlineContentVisibilityButton(aSwContentAtPos.aFnd.pNode->GetTextNode()); + } + } + } + else if (m_pSavedOutlineFrame && !m_pSavedOutlineFrame->IsInDtor()) + { + // current pointer pos is not over an outline frame + // previous frame was an outline frame + // remove collapse button if showing + const SwNodes& rNds = rSh.GetDoc()->GetNodes(); + SwOutlineNodes::size_type nPos; + if (rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos) && + !rSh.IsOutlineContentFolded(nPos)) + { + GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame); + } + m_pSavedOutlineFrame = nullptr; + } + } + if( m_pShadCursor && 0 != (rMEvt.GetModifier() + rMEvt.GetButtons() ) ) { m_pShadCursor.reset(); @@ -3847,6 +3928,21 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt) const Point aOldPt( rSh.VisArea().Pos() ); const bool bInsWin = rSh.VisArea().IsInside( aDocPt ) || comphelper::LibreOfficeKit::isActive(); + if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + if (m_pSavedOutlineFrame && !bInsWin) + { + // the mouse pointer has left the building + // 86 the collapse button if showing + const SwNodes& rNds = rSh.GetDoc()->GetNodes(); + SwOutlineNodes::size_type nPos; + rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos); + if (!rSh.IsOutlineContentFolded(nPos)) + GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame); + m_pSavedOutlineFrame = nullptr; + } + } + if( m_pShadCursor && !bInsWin ) { m_pShadCursor.reset(); @@ -5275,6 +5371,11 @@ void SwEditWin::Command( const CommandEvent& rCEvt ) case CommandEventId::Wheel: case CommandEventId::StartAutoScroll: case CommandEventId::AutoScroll: + if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame); + m_pSavedOutlineFrame = nullptr; + } m_pShadCursor.reset(); bCallBase = !m_rView.HandleWheelCommands( rCEvt ); break; @@ -6421,6 +6522,38 @@ void SwEditWin::SetGraphicTwipPosition(bool bStart, const Point& rPosition) } } +void SwEditWin::SetOutlineContentVisiblityButtons() +{ + SwWrtShell& rSh = m_rView.GetWrtShell(); + const SwOutlineNodes& rOutlineNodes = rSh.GetDoc()->GetNodes().GetOutLineNds(); + if (!rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos) + { + bool bOutlineContentVisibleAttr = true; + rOutlineNodes[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); + if (!bOutlineContentVisibleAttr) + { + // unfold and then set outline content visible attr to false for persistence + rSh.ToggleOutlineContentVisibility(nPos); + rOutlineNodes[nPos]->GetTextNode()->SetAttrOutlineContentVisible(false); + } + } + GetFrameControlsManager().HideControls(FrameControlType::Outline); + } + else + { + for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos) + { + bool bOutlineContentVisibleAttr = true; + rOutlineNodes[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); + if (!bOutlineContentVisibleAttr) + rSh.ToggleOutlineContentVisibility(nPos, true); + } + } + GetView().Invalidate(); // set state of dependent slots (FN_TOGGLE_OUTLINE_CONTENT_VISIBILITY) +} + SwFrameControlsManager& SwEditWin::GetFrameControlsManager() { return *m_pFrameControlsManager; diff --git a/sw/source/uibase/docvw/edtwin2.cxx b/sw/source/uibase/docvw/edtwin2.cxx index da67d799008f..064ddee8de01 100644 --- a/sw/source/uibase/docvw/edtwin2.cxx +++ b/sw/source/uibase/docvw/edtwin2.cxx @@ -49,6 +49,7 @@ #include <IDocumentMarkAccess.hxx> #include <txtfrm.hxx> #include <ndtxt.hxx> +#include <FrameControlsManager.hxx> static OUString lcl_GetRedlineHelp( const SwRangeRedline& rRedl, bool bBalloon ) { @@ -429,6 +430,9 @@ void SwEditWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle if( bPaintShadowCursor ) m_pShadCursor->Paint(); + + if (pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + GetFrameControlsManager().SetOutlineContentVisibilityButtons(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/inc/FrameControlsManager.hxx b/sw/source/uibase/inc/FrameControlsManager.hxx index 66685bd8b174..cb51be62f860 100644 --- a/sw/source/uibase/inc/FrameControlsManager.hxx +++ b/sw/source/uibase/inc/FrameControlsManager.hxx @@ -18,6 +18,8 @@ class SwPageFrame; class SwEditWin; +class SwContentFrame; +class SwTextNode; typedef std::shared_ptr< SwFrameControl > SwFrameControlPtr; @@ -30,6 +32,7 @@ class SwFrameControlsManager private: VclPtr<SwEditWin> m_pEditWin; std::map< FrameControlType, SwFrameControlPtrMap > m_aControls; + std::map<const SwTextNode*, const SwContentFrame*> m_aTextNodeContentFrameMap; public: SwFrameControlsManager( SwEditWin* pEditWin ); @@ -46,6 +49,8 @@ class SwFrameControlsManager void SetHeaderFooterControl( const SwPageFrame* pPageFrame, FrameControlType eType, Point aOffset ); void SetPageBreakControl( const SwPageFrame* pPageFrame ); void SetUnfloatTableButton( const SwFlyFrame* pFlyFrame, bool bShow, Point aTopRightPixel = Point() ); + void SetOutlineContentVisibilityButton(const SwTextNode* pTextNd); + void SetOutlineContentVisibilityButtons(); }; #endif diff --git a/sw/source/uibase/inc/OutlineContentVisibilityWin.hxx b/sw/source/uibase/inc/OutlineContentVisibilityWin.hxx new file mode 100644 index 000000000000..13f29fd0f2eb --- /dev/null +++ b/sw/source/uibase/inc/OutlineContentVisibilityWin.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef INCLUDED_SW_SOURCE_UIBASE_INC_OUTLINECONTENTVISIBILITYWIN_HXX +#define INCLUDED_SW_SOURCE_UIBASE_INC_OUTLINECONTENTVISIBILITYWIN_HXX + +#include "edtwin.hxx" +#include "FrameControl.hxx" + +class SwOutlineContentVisibilityWin : public PushButton, public ISwFrameControl +{ +private: + VclPtr<SwEditWin> m_pEditWin; + const SwFrame* m_pFrame; + int m_nDelayAppearing; ///< Before we show the control, wait a few timer ticks to avoid appearing with every mouse over. + Timer m_aDelayTimer; + bool m_bDestroyed; + size_t m_nOutlinePos; + + void ToggleOutlineContentVisibility(const bool bSubs); + +public: + SwOutlineContentVisibilityWin(SwEditWin* pEditWin, const SwFrame* pFrame); + virtual ~SwOutlineContentVisibilityWin() override { disposeOnce(); } + virtual void dispose() override; + + virtual void KeyInput(const KeyEvent& rKEvt) override; + virtual void MouseButtonDown(const MouseEvent& rMEvt) override; + virtual void MouseMove(const MouseEvent& rMEvt) override; + virtual void ShowAll(bool bShow) override; + virtual bool Contains(const Point& rDocPt) const override; + virtual void SetReadonly(bool /*bReadonly*/) override {} + virtual const SwFrame* GetFrame() override { return m_pFrame; } + virtual SwEditWin* GetEditWin() override { return m_pEditWin; } + + void Set(); + +private: + DECL_LINK(DelayHandler, Timer*, void); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx index 855a2ff4158c..49f09827dd9c 100644 --- a/sw/source/uibase/inc/edtwin.hxx +++ b/sw/source/uibase/inc/edtwin.hxx @@ -127,6 +127,8 @@ class SW_DLLPUBLIC SwEditWin final : public vcl::Window, std::unique_ptr<SwFrameControlsManager> m_pFrameControlsManager; + SwFrame* m_pSavedOutlineFrame = nullptr; + void LeaveArea(const Point &); void JustifyAreaTimer(); inline void EnterArea(); @@ -288,7 +290,10 @@ public: /// Allows starting or ending a graphic move or resize action. void SetGraphicTwipPosition(bool bStart, const Point& rPosition); - void SetOutlineContentVisiblityButtons() {(void)this;} + const SwFrame* GetSavedOutlineFrame() { return m_pSavedOutlineFrame; } + void SetSavedOutlineFrame(SwFrame* pFrame) { m_pSavedOutlineFrame = pFrame; } + + void SetOutlineContentVisiblityButtons(); virtual FactoryFunction GetUITestFactory() const override; }; diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx index 4c02e5e465b5..8cb74403c795 100644 --- a/sw/source/uibase/inc/wrtsh.hxx +++ b/sw/source/uibase/inc/wrtsh.hxx @@ -489,6 +489,10 @@ typedef bool (SwWrtShell:: *FNSimpleMove)(); /// Inserts a new annotation/comment at the current cursor position / selection. void InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq); + bool IsOutlineContentFolded(const size_t nPos); + void ToggleOutlineContentVisibility(SwNode* pNd, bool bForceFold = false); + void ToggleOutlineContentVisibility(const size_t nPos, bool bForceFold = false); + private: SAL_DLLPRIVATE void OpenMark(); diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx index e9d498d2b426..1fcd1873d8f3 100644 --- a/sw/source/uibase/utlui/content.cxx +++ b/sw/source/uibase/utlui/content.cxx @@ -89,6 +89,8 @@ #include <fmtcntnt.hxx> #include <docstat.hxx> +#include <viewopt.hxx> + #define CTYPE_CNT 0 #define CTYPE_CTT 1 @@ -2639,6 +2641,7 @@ void SwContentTree::ExecCommand(const OString& rCmd, bool bOutlineWithChildren) SwOutlineNodes::difference_type nDirLast = bUp ? -1 : 1; bool bStartedAction = false; + std::vector<SwNode*> aFoldedOutlineNdsArray; for (auto const& pCurrentEntry : selected) { assert(pCurrentEntry && lcl_IsContent(*pCurrentEntry, *m_xTreeView)); @@ -2660,6 +2663,28 @@ void SwContentTree::ExecCommand(const OString& rCmd, bool bOutlineWithChildren) if (!bStartedAction) { pShell->StartAllAction(); + if (bUpDown) + { + if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + // unfold all folded outline content + SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds(); + for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos) + { + SwNode* pNd = rOutlineNds[nPos]; + if (pNd->IsTextNode()) // should aways be true + { + bool bOutlineContentVisibleAttr = true; + pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); + if (!bOutlineContentVisibleAttr) + { + aFoldedOutlineNdsArray.push_back(pNd); + pShell->ToggleOutlineContentVisibility(nPos); + } + } + } + } + } pShell->StartUndo(bLeftRight ? SwUndoId::OUTLINE_LR : SwUndoId::OUTLINE_UD); bStartedAction = true; } @@ -2831,6 +2856,15 @@ void SwContentTree::ExecCommand(const OString& rCmd, bool bOutlineWithChildren) if (bStartedAction) { pShell->EndUndo(); + if (bUpDown) + { + if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + // fold all outlines that were folded before chapter promote/demote + for (SwNode* pNd : aFoldedOutlineNdsArray) + pShell->ToggleOutlineContentVisibility(pNd, true); + } + } pShell->EndAllAction(); if (m_aActiveContentArr[ContentTypeId::OUTLINE]) m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate(); @@ -3006,6 +3040,27 @@ void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos) { SwWrtShell *const pShell = GetWrtShell(); pShell->StartAllAction(); + std::vector<SwNode*> aFoldedOutlineNdsArray; + + if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + // unfold all folded outline content + SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds(); + for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos) + { + SwNode* pNd = rOutlineNds[nPos]; + if (pNd->IsTextNode()) // should aways be true + { + bool bOutlineContentVisibleAttr = true; + pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr); + if (!bOutlineContentVisibleAttr) + { + aFoldedOutlineNdsArray.push_back(pNd); + pShell->ToggleOutlineContentVisibility(nPos); + } + } + } + } pShell->StartUndo(SwUndoId::OUTLINE_UD); SwOutlineNodes::size_type nPrevSourcePos = SwOutlineNodes::npos; @@ -3056,6 +3111,12 @@ void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos) } pShell->EndUndo(); + if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + // fold all outlines that were folded before chapter promote/demote + for (SwNode* pNd : aFoldedOutlineNdsArray) + pShell->ToggleOutlineContentVisibility(pNd, true); + } pShell->EndAllAction(); m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate(); Display(true); diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx index 444db135021d..2c208eb2d592 100644 --- a/sw/source/uibase/wrtsh/wrtsh1.cxx +++ b/sw/source/uibase/wrtsh/wrtsh1.cxx @@ -100,6 +100,9 @@ #include <comphelper/lok.hxx> #include <memory> +#include <frmtool.hxx> +#include <viewopt.hxx> + using namespace sw::mark; using namespace com::sun::star; namespace { @@ -1989,5 +1992,122 @@ void SwWrtShell::InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq) pFormat->Broadcast( SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::FOCUS, &GetView() ) ); } } +bool SwWrtShell::IsOutlineContentFolded(const size_t nPos) +{ + const SwNodes& rNodes = GetDoc()->GetNodes(); + const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds(); + + assert(nPos < rOutlineNodes.size()); + + SwNode* pOutlineNode = rOutlineNodes[nPos]; + if (pOutlineNode->IsEndNode()) + return false; + + bool bOutlineContentVisibleAttr = false; + if (pOutlineNode->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr)) + return !bOutlineContentVisibleAttr; + + return false; +} + +void SwWrtShell::ToggleOutlineContentVisibility(SwNode* pNd, bool bForceFold) +{ + SwOutlineNodes::size_type nPos; + if (GetNodes().GetOutLineNds().Seek_Entry(pNd, &nPos)) + ToggleOutlineContentVisibility(nPos, bForceFold); +} + +void SwWrtShell::ToggleOutlineContentVisibility(size_t nPos, bool bForceFold) +{ + const SwNodes& rNodes = GetNodes(); + const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds(); + + assert(nPos < rOutlineNodes.size()); + + SwNode* pSttNd = rOutlineNodes[nPos]; + if (pSttNd->IsEndNode()) + return; + + SwNode* pEndNd = &rNodes.GetEndOfContent(); + if (rOutlineNodes.size() > nPos + 1) + pEndNd = rOutlineNodes[nPos + 1]; + + if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex()) + { + // limit folding to within table box + if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex() ) + pEndNd = pSttNd->EndOfSectionNode(); + } + // if pSttNd isn't in table but pEndNd is, skip over all outline nodes in table + else if (pEndNd->GetTableBox()) + { + pEndNd = &rNodes.GetEndOfContent(); + for (size_t nOutlinePos = nPos + 2; nOutlinePos < rOutlineNodes.size(); nOutlinePos++) + { + if (!(rOutlineNodes[nOutlinePos]->GetTableBox())) + { + pEndNd = rOutlineNodes[nOutlinePos]; + break; + } + } + } + + if (IsOutlineContentFolded(nPos) && !bForceFold) + { + // unfold + SwNodeIndex aIdx(*pSttNd, +1); + MakeFrames(GetDoc(), aIdx, *pEndNd); + + pSttNd->GetTextNode()->SetAttrOutlineContentVisible(true); + + if (GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + // remove fold button if focus is not on outline frame control window + SwContentFrame* pFrame = pSttNd->GetTextNode()->getLayoutFrame(nullptr); + if (pFrame && !pFrame->IsInDtor()) + { + SwFrameControlPtr pOutlineFrameControl = GetView().GetEditWin().GetFrameControlsManager().GetControl(FrameControlType::Outline, pFrame); + if (pOutlineFrameControl && pOutlineFrameControl->GetWindow() && !pOutlineFrameControl->GetWindow()->HasFocus()) + GetView().GetEditWin().GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, pFrame); + } + + // fold revealed outline nodes that have collapsed content + while (aIdx != *pEndNd) + { + SwNode* pTmpNd = &aIdx.GetNode(); + if (pTmpNd->IsTextNode() && pTmpNd->GetTextNode()->IsOutline()) + { + SwTextNode* pTmpTextNd = pTmpNd->GetTextNode(); + bool bOutlineContentVisibleAttr = true; + if (pTmpTextNd->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr) && + !bOutlineContentVisibleAttr) + { + SwOutlineNodes::size_type iPos; + if (rOutlineNodes.Seek_Entry(pTmpTextNd, &iPos)) + { + if (pTmpTextNd->getLayoutFrame(nullptr)) + ToggleOutlineContentVisibility(iPos, true); + } + } + } + aIdx++; + } + } + } + else + { + // fold + for (SwNodeIndex aIdx(*pSttNd, +1); &aIdx.GetNode() != pEndNd; aIdx++) + { + SwNode* pNd = &aIdx.GetNode(); + if (pNd->IsContentNode()) + pNd->GetContentNode()->DelFrames(nullptr); + else if (pNd->IsTableNode()) + pNd->GetTableNode()->DelFrames(nullptr); + } + pSttNd->GetTextNode()->SetAttrOutlineContentVisible(false); + } + GetView().GetEditWin().Invalidate(); +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |