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