Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : */
9 :
10 : #include "navmgr.hxx"
11 : #include "wrtsh.hxx"
12 : #include <sfx2/bindings.hxx>
13 : #include <sfx2/viewfrm.hxx>
14 : #include <cmdid.h>
15 : #include <view.hxx>
16 : #include <doc.hxx>
17 : #include <unocrsr.hxx>
18 :
19 : #include <com/sun/star/frame/XLayoutManager.hpp>
20 :
21 : /**
22 : * If SMART is defined, the navigation history has recency with temporal ordering enhancement,
23 : * as described on http://zing.ncsl.nist.gov/hfweb/proceedings/greenberg/
24 : */
25 :
26 : #define SMART 1
27 :
28 : // This method positions the cursor to the position rPos.
29 :
30 0 : void SwNavigationMgr::GotoSwPosition(const SwPosition &rPos) {
31 : // EnterStdMode() prevents the cursor to 'block' the current
32 : // shell when it should move from the image back to the normal shell
33 0 : m_rMyShell.EnterStdMode();
34 0 : m_rMyShell.StartAllAction();
35 : // cursor consists of two SwPositions: Point and Mark.
36 : // Such a pair is called a PaM. SwPaM is derived from SwRing.
37 : // The Ring contains the single regions of a multi-selection.
38 0 : SwPaM* pPaM = m_rMyShell.GetCrsr();
39 :
40 0 : if(pPaM->HasMark())
41 0 : pPaM->DeleteMark(); // If there was a selection, get rid of it
42 0 : *pPaM->GetPoint() = rPos; // Position Cursor
43 :
44 0 : m_rMyShell.EndAllAction();
45 0 : }
46 :
47 : // Ctor for the SwNavigationMgr class
48 : // Sets the shell to the current shell
49 : // and the index of the current position to 0
50 :
51 4708 : SwNavigationMgr::SwNavigationMgr(SwWrtShell & rShell)
52 4708 : : m_nCurrent(0), m_rMyShell(rShell)
53 : {
54 4708 : }
55 :
56 : // This method is used by the navigation shell - defined in sw/source/uibase/inc/navsh.hxx
57 : // and implemented in sw/source/uibase/shells/navsh.cxx
58 : // It is called when we want to check if the back button should be enabled or not.
59 : // The back button should be enabled only if there are some entries in the navigation history
60 :
61 18 : bool SwNavigationMgr::backEnabled() {
62 18 : return (m_nCurrent > 0);
63 : }
64 :
65 : // Similar to backEnabled() method.
66 : // The forward button should be enabled if we ever clicked back
67 : // Due to the implementation of the navigation class, this is when the
68 : // current position within the navigation history entries in not the last one
69 : // i.e. when the m_nCurrent index is not at the end of the m_entries vector
70 :
71 18 : bool SwNavigationMgr::forwardEnabled() {
72 18 : return m_nCurrent+1 < m_entries.size();
73 : }
74 :
75 : // The goBack() method positions the cursor to the previous entry in the navigation history
76 : // If there was no history to go forward to, it adds the current position of the cursor
77 : // to the history so we could go forward to where we came from
78 :
79 0 : void SwNavigationMgr::goBack() {
80 :
81 : // Although the button should be disabled whenever the backEnabled() returns false,
82 : // the UI is sometimes not as responsive as we would like it to be :)
83 : // this check prevents segmentation faults and in this way the class is not relying on the UI
84 :
85 0 : if (backEnabled()) {
86 : /* Trying to get the current cursor */
87 0 : SwPaM* pPaM = m_rMyShell.GetCrsr();
88 0 : if (!pPaM) {
89 0 : return;
90 : }
91 : // This flag will be used to manually refresh the buttons
92 :
93 0 : bool bForwardWasDisabled = !forwardEnabled();
94 :
95 : // If we're going backwards in our history, but the current location is not
96 : // in the history then we need to add *here* to it so that we can "go
97 : // forward" to here again.
98 :
99 0 : if (bForwardWasDisabled) {
100 :
101 : // the cursor consists of two SwPositions: Point and Mark.
102 : // We are adding the current Point to the navigation history
103 : // so we could later navigate forward to it
104 :
105 : // The addEntry() method returns true iff we should decrement
106 : // the index before navigating back
107 :
108 0 : if (addEntry(*pPaM->GetPoint()) ) {
109 0 : m_nCurrent--;
110 : }
111 : }
112 0 : m_nCurrent--;
113 : // Position cursor to appropriate navigation history entry
114 0 : GotoSwPosition(*m_entries[m_nCurrent]->GetPoint());
115 : // Refresh the buttons
116 0 : if (bForwardWasDisabled)
117 0 : m_rMyShell.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_FORWARD);
118 0 : if (!backEnabled())
119 0 : m_rMyShell.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_BACK);
120 : }
121 : }
122 :
123 : // The goForward() method positions the cursor to the next entry in the navigation history
124 :
125 0 : void SwNavigationMgr::goForward() {
126 :
127 : // Although the button should be disabled whenever the backForward() returns false,
128 : // the UI is sometimes not as responsive as we would like it to be :)
129 : // this check prevents segmentation faults and in this way the class is not relying on the UI
130 :
131 0 : if (forwardEnabled()) {
132 : // This flag will be used to manually refresh the buttons
133 0 : bool bBackWasDisabled = !backEnabled();
134 : // The current index is positioned at the current entry in the navigation history
135 : // We have to increment it to go to the next entry
136 0 : m_nCurrent++;
137 0 : GotoSwPosition(*m_entries[m_nCurrent]->GetPoint());
138 : // Refresh the buttons
139 0 : if (bBackWasDisabled)
140 0 : m_rMyShell.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_BACK);
141 0 : if (!forwardEnabled())
142 0 : m_rMyShell.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_FORWARD);
143 : }
144 0 : }
145 :
146 : // This method adds the SwPosition rPos to the navigation history
147 : // rPos is usually the current position of the cursor in the document
148 :
149 18 : bool SwNavigationMgr::addEntry(const SwPosition& rPos) {
150 : // Flags that will be used for refreshing the buttons
151 18 : bool bBackWasDisabled = !backEnabled();
152 18 : bool bForwardWasEnabled = forwardEnabled();
153 :
154 18 : bool bRet = false; // return value of the function.
155 : // Indicates whether the index should be decremented before
156 : // jumping back or not
157 : #if SMART
158 : // If any forward history exists, twist the tail of the
159 : // list from the current position to the end
160 18 : if (bForwardWasEnabled) {
161 :
162 0 : size_t number_ofm_entries = m_entries.size(); // To avoid calling m_entries.size() multiple times
163 0 : int curr = m_nCurrent; // Index from which we'll twist the tail.
164 0 : int n = (number_ofm_entries - curr) / 2; // Number of entries that will swap places
165 0 : for (int i = 0; i < n; i++) {
166 0 : ::std::swap(m_entries[curr + i], m_entries[number_ofm_entries -1 - i]);
167 : }
168 :
169 0 : if (*m_entries.back()->GetPoint() != rPos)
170 : {
171 0 : SwUnoCrsr *const pCursor = m_rMyShell.GetDoc()->CreateUnoCrsr(rPos);
172 0 : m_entries.push_back(::boost::shared_ptr<SwUnoCrsr>(pCursor));
173 : }
174 0 : bRet = true;
175 : }
176 : else {
177 18 : if ( (!m_entries.empty() && *m_entries.back()->GetPoint() != rPos) || m_entries.empty() ) {
178 18 : SwUnoCrsr *const pCursor = m_rMyShell.GetDoc()->CreateUnoCrsr(rPos);
179 18 : m_entries.push_back(::boost::shared_ptr<SwUnoCrsr>(pCursor));
180 18 : bRet = true;
181 : }
182 18 : if (m_entries.size() > 1 && *m_entries.back()->GetPoint() == rPos)
183 12 : bRet = true;
184 18 : if (m_entries.size() == 1 && *m_entries.back()->GetPoint() == rPos)
185 6 : bRet = false;
186 : }
187 : #else
188 : m_entries.erase(m_entries.begin() + m_nCurrent, m_entries.end());
189 : SwUnoCrsr *const pCursor = m_rMyShell.GetDoc()->CreateUnoCrsr(rPos);
190 : m_entries.push_back(::boost::shared_ptr<SwUnoCrsr>(pCursor));
191 : bRet = true;
192 : #endif
193 18 : m_nCurrent = m_entries.size();
194 :
195 : // Refresh buttons
196 18 : if (bBackWasDisabled)
197 6 : m_rMyShell.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_BACK);
198 18 : if (bForwardWasEnabled)
199 0 : m_rMyShell.GetView().GetViewFrame()->GetBindings().Invalidate(FN_NAVIGATION_FORWARD);
200 :
201 : // show the Navigation toolbar
202 : css::uno::Reference< css::frame::XFrame > xFrame =
203 18 : m_rMyShell.GetView().GetViewFrame()->GetFrame().GetFrameInterface();
204 18 : if (xFrame.is())
205 : {
206 18 : css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
207 18 : if (xPropSet.is())
208 : {
209 18 : css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
210 36 : css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
211 :
212 18 : aValue >>= xLayoutManager;
213 18 : if (xLayoutManager.is())
214 : {
215 18 : const OUString sResourceURL( "private:resource/toolbar/navigationobjectbar" );
216 36 : css::uno::Reference< css::ui::XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL);
217 18 : if (!xUIElement.is())
218 : {
219 6 : xLayoutManager->createElement( sResourceURL );
220 6 : xLayoutManager->showElement( sResourceURL );
221 18 : }
222 18 : }
223 18 : }
224 : }
225 :
226 18 : return bRet;
227 270 : }
228 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|