1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 #include <sfx2/bindings.hxx>
13 #include <sfx2/viewfrm.hxx>
14 #include <vcl/svapp.hxx>
18 #include <unocrsr.hxx>
20 #include <com/sun/star/frame/XLayoutManager.hpp>
21 #include <com/sun/star/beans/XPropertySet.hpp>
23 // This method positions the cursor to the position rPos.
25 void SwNavigationMgr::GotoSwPosition(const SwPosition
&rPos
) {
26 // EnterStdMode() prevents the cursor to 'block' the current
27 // shell when it should move from the image back to the normal shell
28 m_rMyShell
.EnterStdMode();
29 m_rMyShell
.StartAllAction();
30 // cursor consists of two SwPositions: Point and Mark.
31 // Such a pair is called a PaM. SwPaM is derived from SwRing.
32 // The Ring contains the single regions of a multi-selection.
33 SwPaM
* pPaM
= m_rMyShell
.GetCursor();
36 pPaM
->DeleteMark(); // If there was a selection, get rid of it
37 *pPaM
->GetPoint() = rPos
; // Position Cursor
39 m_rMyShell
.EndAllAction();
42 // Ctor for the SwNavigationMgr class
43 // Sets the shell to the current shell
44 // and the index of the current position to 0
46 SwNavigationMgr::SwNavigationMgr(SwWrtShell
& rShell
)
47 : m_nCurrent(0), m_rMyShell(rShell
)
51 SwNavigationMgr::~SwNavigationMgr()
54 for (auto & it
: m_entries
)
56 EndListening(it
->m_aNotifier
);
61 void SwNavigationMgr::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
63 // our cursors may now spontaneously self-destruct: remove from
64 // m_entries if that happens
65 if (typeid(rHint
) == typeid(sw::UnoCursorHint
))
67 auto it
= std::find_if(m_entries
.begin(), m_entries
.end(),
68 [&rBC
](const sw::UnoCursorPointer
& rItem
) { return !rItem
|| &rBC
== &rItem
->m_aNotifier
; });
69 if (it
!= m_entries
.end())
77 // This method is used by the navigation shell - defined in sw/source/uibase/inc/navsh.hxx
78 // and implemented in sw/source/uibase/shells/navsh.cxx
79 // It is called when we want to check if the back button should be enabled or not.
80 // The back button should be enabled only if there are some entries in the navigation history
82 bool SwNavigationMgr::backEnabled() {
83 return (m_nCurrent
> 0);
86 // Similar to backEnabled() method.
87 // The forward button should be enabled if we ever clicked back
88 // Due to the implementation of the navigation class, this is when the
89 // current position within the navigation history entries in not the last one
90 // i.e. when the m_nCurrent index is not at the end of the m_entries vector
92 bool SwNavigationMgr::forwardEnabled() {
93 return m_nCurrent
+1 < m_entries
.size();
96 // The goBack() method positions the cursor to the previous entry in the navigation history
97 // If there was no history to go forward to, it adds the current position of the cursor
98 // to the history so we could go forward to where we came from
100 void SwNavigationMgr::goBack() {
102 // Although the button should be disabled whenever the backEnabled() returns false,
103 // the UI is sometimes not as responsive as we would like it to be :)
104 // this check prevents segmentation faults and in this way the class is not relying on the UI
106 if (!backEnabled()) return;
108 /* Trying to get the current cursor */
109 SwPaM
* pPaM
= m_rMyShell
.GetCursor();
113 // This flag will be used to manually refresh the buttons
115 bool bForwardWasDisabled
= !forwardEnabled();
117 // If we're going backwards in our history, but the current location is not
118 // in the history then we need to add *here* to it so that we can "go
119 // forward" to here again.
121 if (bForwardWasDisabled
) {
123 // the cursor consists of two SwPositions: Point and Mark.
124 // We are adding the current Point to the navigation history
125 // so we could later navigate forward to it
127 // The addEntry() method returns true iff we should decrement
128 // the index before navigating back
130 if (addEntry(*pPaM
->GetPoint()) ) {
135 // Position cursor to appropriate navigation history entry
136 GotoSwPosition(*m_entries
[m_nCurrent
]->GetPoint());
137 // Refresh the buttons
138 if (bForwardWasDisabled
)
139 m_rMyShell
.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_FORWARD
);
141 m_rMyShell
.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_BACK
);
144 // The goForward() method positions the cursor to the next entry in the navigation history
146 void SwNavigationMgr::goForward() {
148 // Although the button should be disabled whenever the backForward() returns false,
149 // the UI is sometimes not as responsive as we would like it to be :)
150 // this check prevents segmentation faults and in this way the class is not relying on the UI
152 if (!forwardEnabled()) return;
154 // This flag will be used to manually refresh the buttons
155 bool bBackWasDisabled
= !backEnabled();
156 // The current index is positioned at the current entry in the navigation history
157 // We have to increment it to go to the next entry
159 GotoSwPosition(*m_entries
[m_nCurrent
]->GetPoint());
160 // Refresh the buttons
161 if (bBackWasDisabled
)
162 m_rMyShell
.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_BACK
);
163 if (!forwardEnabled())
164 m_rMyShell
.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_FORWARD
);
167 // This method adds the SwPosition rPos to the navigation history
168 // rPos is usually the current position of the cursor in the document
170 bool SwNavigationMgr::addEntry(const SwPosition
& rPos
) {
171 // Flags that will be used for refreshing the buttons
172 bool bBackWasDisabled
= !backEnabled();
173 bool bForwardWasEnabled
= forwardEnabled();
175 bool bRet
= false; // return value of the function.
176 // Indicates whether the index should be decremented before
177 // jumping back or not
178 // The navigation history has recency with temporal ordering enhancement,
179 // as described on http://zing.ncsl.nist.gov/hfweb/proceedings/greenberg/
180 // If any forward history exists, twist the tail of the
181 // list from the current position to the end
182 if (bForwardWasEnabled
) {
184 size_t number_ofm_entries
= m_entries
.size(); // To avoid calling m_entries.size() multiple times
185 int curr
= m_nCurrent
; // Index from which we'll twist the tail.
186 int n
= (number_ofm_entries
- curr
) / 2; // Number of entries that will swap places
187 for (int i
= 0; i
< n
; i
++) {
188 std::swap(m_entries
[curr
+ i
], m_entries
[number_ofm_entries
-1 - i
]);
191 if (*m_entries
.back()->GetPoint() != rPos
)
193 sw::UnoCursorPointer
pCursor(m_rMyShell
.GetDoc()->CreateUnoCursor(rPos
));
194 StartListening(pCursor
->m_aNotifier
);
195 m_entries
.push_back(pCursor
);
200 if ( (!m_entries
.empty() && *m_entries
.back()->GetPoint() != rPos
) || m_entries
.empty() ) {
201 sw::UnoCursorPointer
pCursor(m_rMyShell
.GetDoc()->CreateUnoCursor(rPos
));
202 StartListening(pCursor
->m_aNotifier
);
203 m_entries
.push_back(pCursor
);
206 if (m_entries
.size() > 1 && *m_entries
.back()->GetPoint() == rPos
)
208 if (m_entries
.size() == 1 && *m_entries
.back()->GetPoint() == rPos
)
211 m_nCurrent
= m_entries
.size();
214 if (bBackWasDisabled
)
215 m_rMyShell
.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_BACK
);
216 if (bForwardWasEnabled
)
217 m_rMyShell
.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_FORWARD
);
219 // show the Navigation toolbar
220 css::uno::Reference
< css::frame::XFrame
> xFrame
=
221 m_rMyShell
.GetView().GetViewFrame()->GetFrame().GetFrameInterface();
224 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(xFrame
, css::uno::UNO_QUERY
);
227 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
228 css::uno::Any aValue
= xPropSet
->getPropertyValue("LayoutManager");
230 aValue
>>= xLayoutManager
;
231 if (xLayoutManager
.is())
233 const OUString
sResourceURL( "private:resource/toolbar/navigationobjectbar" );
234 css::uno::Reference
< css::ui::XUIElement
> xUIElement
= xLayoutManager
->getElement(sResourceURL
);
235 if (!xUIElement
.is())
237 xLayoutManager
->createElement( sResourceURL
);
238 xLayoutManager
->showElement( sResourceURL
);
247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */