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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <bookmrk.hxx>
21 : #include <IDocumentMarkAccess.hxx>
22 : #include <IDocumentUndoRedo.hxx>
23 : #include <IDocumentLinksAdministration.hxx>
24 : #include <IDocumentState.hxx>
25 : #include <doc.hxx>
26 : #include <ndtxt.hxx>
27 : #include <pam.hxx>
28 : #include <swserv.hxx>
29 : #include <sfx2/linkmgr.hxx>
30 : #include <swtypes.hxx>
31 : #include <UndoBookmark.hxx>
32 : #include <unobookmark.hxx>
33 : #include <rtl/random.h>
34 : #include <xmloff/odffields.hxx>
35 :
36 : using namespace ::sw::mark;
37 : using namespace ::com::sun::star;
38 : using namespace ::com::sun::star::uno;
39 :
40 : namespace
41 : {
42 300480 : static void lcl_FixPosition(SwPosition& rPos)
43 : {
44 : // make sure the position has 1) the proper node, and 2) a proper index
45 300480 : SwTxtNode* pTxtNode = rPos.nNode.GetNode().GetTxtNode();
46 300480 : if(pTxtNode == NULL && rPos.nContent.GetIndex() > 0)
47 : {
48 : OSL_TRACE(
49 : "bookmrk.cxx::lcl_FixPosition"
50 : " - illegal position: %d without proper TxtNode", rPos.nContent.GetIndex());
51 0 : rPos.nContent.Assign(NULL, 0);
52 : }
53 300480 : else if(pTxtNode != NULL && rPos.nContent.GetIndex() > pTxtNode->Len())
54 : {
55 : OSL_TRACE(
56 : "bookmrk.cxx::lcl_FixPosition"
57 : " - illegal position: %d is beyond %d", rPos.nContent.GetIndex(), pTxtNode->Len());
58 4 : rPos.nContent.Assign(pTxtNode, pTxtNode->Len());
59 : }
60 300480 : }
61 :
62 218 : static void lcl_AssureFieldMarksSet(Fieldmark* const pField,
63 : SwDoc* const io_pDoc,
64 : const sal_Unicode aStartMark,
65 : const sal_Unicode aEndMark)
66 : {
67 218 : io_pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_UI_REPLACE, NULL);
68 :
69 218 : SwPosition rStart = pField->GetMarkStart();
70 218 : SwTxtNode const*const pStartTxtNode = rStart.nNode.GetNode().GetTxtNode();
71 218 : const sal_Unicode ch_start = ( rStart.nContent.GetIndex() >= pStartTxtNode->GetTxt().getLength() ) ? 0 :
72 218 : pStartTxtNode->GetTxt()[rStart.nContent.GetIndex()];
73 218 : if( ( ch_start != aStartMark ) && ( aEndMark != CH_TXT_ATR_FORMELEMENT ) )
74 : {
75 184 : SwPaM aStartPaM(rStart);
76 184 : io_pDoc->getIDocumentContentOperations().InsertString(aStartPaM, OUString(aStartMark));
77 184 : rStart.nContent--;
78 184 : pField->SetMarkStartPos( rStart );
79 : }
80 :
81 218 : SwPosition& rEnd = pField->GetMarkEnd();
82 218 : SwTxtNode const*const pEndTxtNode = rEnd.nNode.GetNode().GetTxtNode();
83 408 : const sal_Int32 nEndPos = ( rEnd == rStart || rEnd.nContent.GetIndex() == 0 ) ?
84 246 : rEnd.nContent.GetIndex() : rEnd.nContent.GetIndex() - 1;
85 218 : const sal_Unicode ch_end = nEndPos >= pEndTxtNode->GetTxt().getLength() ? 0 : pEndTxtNode->GetTxt()[nEndPos];
86 218 : if ( aEndMark && ( ch_end != aEndMark ) )
87 : {
88 214 : SwPaM aEndPaM(rEnd);
89 214 : io_pDoc->getIDocumentContentOperations().InsertString(aEndPaM, OUString(aEndMark));
90 214 : rEnd.nContent++;
91 : }
92 :
93 218 : io_pDoc->GetIDocumentUndoRedo().EndUndo(UNDO_UI_REPLACE, NULL);
94 218 : };
95 :
96 0 : static void lcl_RemoveFieldMarks(Fieldmark* const pField,
97 : SwDoc* const io_pDoc,
98 : const sal_Unicode aStartMark,
99 : const sal_Unicode aEndMark)
100 : {
101 0 : io_pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_UI_REPLACE, NULL);
102 :
103 0 : const SwPosition& rStart = pField->GetMarkStart();
104 0 : SwTxtNode const*const pStartTxtNode = rStart.nNode.GetNode().GetTxtNode();
105 : const sal_Unicode ch_start =
106 0 : pStartTxtNode->GetTxt()[rStart.nContent.GetIndex()];
107 :
108 0 : if( ch_start == aStartMark )
109 : {
110 0 : SwPaM aStart(rStart, rStart);
111 0 : aStart.End()->nContent++;
112 0 : io_pDoc->getIDocumentContentOperations().DeleteRange(aStart);
113 : }
114 :
115 0 : const SwPosition& rEnd = pField->GetMarkEnd();
116 0 : SwTxtNode const*const pEndTxtNode = rEnd.nNode.GetNode().GetTxtNode();
117 0 : const sal_Int32 nEndPos = ( rEnd == rStart || rEnd.nContent.GetIndex() == 0 )
118 0 : ? rEnd.nContent.GetIndex()
119 0 : : rEnd.nContent.GetIndex() - 1;
120 0 : const sal_Unicode ch_end = pEndTxtNode->GetTxt()[nEndPos];
121 0 : if ( ch_end == aEndMark )
122 : {
123 0 : SwPaM aEnd(rEnd, rEnd);
124 0 : aEnd.Start()->nContent--;
125 0 : io_pDoc->getIDocumentContentOperations().DeleteRange(aEnd);
126 : }
127 :
128 0 : io_pDoc->GetIDocumentUndoRedo().EndUndo(UNDO_UI_REPLACE, NULL);
129 0 : };
130 : }
131 :
132 : namespace sw { namespace mark
133 : {
134 196998 : MarkBase::MarkBase(const SwPaM& aPaM,
135 : const OUString& rName)
136 : : SwModify(0)
137 196998 : , m_pPos1(new SwPosition(*(aPaM.GetPoint())))
138 393996 : , m_aName(rName)
139 : {
140 196998 : m_pPos1->nContent.SetMark(this);
141 196998 : lcl_FixPosition(*m_pPos1);
142 196998 : if (aPaM.HasMark() && (*aPaM.GetMark() != *aPaM.GetPoint()))
143 : {
144 103482 : MarkBase::SetOtherMarkPos(*(aPaM.GetMark()));
145 103482 : lcl_FixPosition(*m_pPos2);
146 : }
147 196998 : }
148 :
149 : // For fieldmarks, the CH_TXT_ATR_FIELDSTART and CH_TXT_ATR_FIELDEND
150 : // themselves are part of the covered range. This is guaranteed by
151 : // TextFieldmark::InitDoc/lcl_AssureFieldMarksSet.
152 2480 : bool MarkBase::IsCoveringPosition(const SwPosition& rPos) const
153 : {
154 2480 : return GetMarkStart() <= rPos && rPos < GetMarkEnd();
155 : }
156 :
157 4269 : void MarkBase::SetMarkPos(const SwPosition& rNewPos)
158 : {
159 4269 : ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos1);
160 4269 : m_pPos1->nContent.SetMark(this);
161 4269 : }
162 :
163 108123 : void MarkBase::SetOtherMarkPos(const SwPosition& rNewPos)
164 : {
165 108123 : ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos2);
166 108123 : m_pPos2->nContent.SetMark(this);
167 108123 : }
168 :
169 0 : OUString MarkBase::ToString( ) const
170 : {
171 0 : return "Mark: ( Name, [ Node1, Index1 ] ): ( " + m_aName + ", [ "
172 0 : + OUString::number( GetMarkPos().nNode.GetIndex( ) ) + ", "
173 0 : + OUString::number( GetMarkPos().nContent.GetIndex( ) ) + " ] )";
174 : }
175 :
176 196998 : MarkBase::~MarkBase()
177 196998 : { }
178 :
179 196978 : OUString MarkBase::GenerateNewName(const OUString& rPrefix)
180 : {
181 196978 : static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != NULL);
182 :
183 196978 : if (bHack)
184 : {
185 : static sal_Int64 nIdCounter = SAL_CONST_INT64(6000000000);
186 0 : return rPrefix + OUString::number(nIdCounter++);
187 : }
188 : else
189 : {
190 196978 : static rtlRandomPool aPool = rtl_random_createPool();
191 196978 : static OUString sUniquePostfix;
192 : static sal_Int32 nCount = SAL_MAX_INT32;
193 196978 : OUStringBuffer aResult(rPrefix);
194 196978 : if(nCount == SAL_MAX_INT32)
195 : {
196 : sal_Int32 nRandom;
197 68 : rtl_random_getBytes(aPool, &nRandom, sizeof(nRandom));
198 68 : sUniquePostfix = OUStringBuffer(13).append('_').append(static_cast<sal_Int32>(abs(nRandom))).makeStringAndClear();
199 68 : nCount = 0;
200 : }
201 : // putting the counter in front of the random parts will speed up string comparisons
202 196978 : return aResult.append(nCount++).append(sUniquePostfix).makeStringAndClear();
203 : }
204 : }
205 :
206 0 : void MarkBase::Modify( const SfxPoolItem *pOld, const SfxPoolItem *pNew )
207 : {
208 0 : NotifyClients(pOld, pNew);
209 0 : if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
210 : { // invalidate cached uno object
211 0 : SetXBookmark(uno::Reference<text::XTextContent>(0));
212 : }
213 0 : }
214 :
215 : // TODO: everything else uses MarkBase::GenerateNewName ?
216 0 : NavigatorReminder::NavigatorReminder(const SwPaM& rPaM)
217 0 : : MarkBase(rPaM, OUString("__NavigatorReminder__"))
218 0 : { }
219 :
220 188414 : UnoMark::UnoMark(const SwPaM& aPaM)
221 188414 : : MarkBase(aPaM, MarkBase::GenerateNewName(OUString("__UnoMark__")))
222 188414 : { }
223 :
224 8280 : DdeBookmark::DdeBookmark(const SwPaM& aPaM)
225 : : MarkBase(aPaM, MarkBase::GenerateNewName(OUString("__DdeLink__")))
226 8280 : , m_aRefObj(NULL)
227 8280 : { }
228 :
229 4 : void DdeBookmark::SetRefObject(SwServerObject* pObj)
230 : {
231 4 : m_aRefObj = pObj;
232 4 : }
233 :
234 842 : void DdeBookmark::DeregisterFromDoc(SwDoc* const pDoc)
235 : {
236 842 : if(m_aRefObj.Is())
237 0 : pDoc->getIDocumentLinksAdministration().GetLinkManager().RemoveServer(m_aRefObj);
238 842 : }
239 :
240 16562 : DdeBookmark::~DdeBookmark()
241 : {
242 8280 : if( m_aRefObj.Is() )
243 : {
244 2 : if(m_aRefObj->HasDataLinks())
245 : {
246 0 : ::sfx2::SvLinkSource* p = &m_aRefObj;
247 0 : p->SendDataChanged();
248 : }
249 2 : m_aRefObj->SetNoServer();
250 : }
251 8282 : }
252 :
253 8278 : Bookmark::Bookmark(const SwPaM& aPaM,
254 : const vcl::KeyCode& rCode,
255 : const OUString& rName,
256 : const OUString& rShortName)
257 : : DdeBookmark(aPaM)
258 : , ::sfx2::Metadatable()
259 : , m_aCode(rCode)
260 8278 : , m_sShortName(rShortName)
261 : {
262 8278 : m_aName = rName;
263 8278 : }
264 :
265 8278 : void Bookmark::InitDoc(SwDoc* const io_pDoc)
266 : {
267 8278 : if (io_pDoc->GetIDocumentUndoRedo().DoesUndo())
268 : {
269 2078 : io_pDoc->GetIDocumentUndoRedo().AppendUndo(
270 2078 : new SwUndoInsBookmark(*this));
271 : }
272 8278 : io_pDoc->getIDocumentState().SetModified();
273 8278 : }
274 :
275 28 : ::sfx2::IXmlIdRegistry& Bookmark::GetRegistry()
276 : {
277 28 : SwDoc *const pDoc( GetMarkPos().GetDoc() );
278 : OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?");
279 28 : return pDoc->GetXmlIdRegistry();
280 : }
281 :
282 2616 : bool Bookmark::IsInClipboard() const
283 : {
284 2616 : SwDoc *const pDoc( GetMarkPos().GetDoc() );
285 : OSL_ENSURE(pDoc, "Bookmark::IsInClipboard: no doc?");
286 2616 : return pDoc->IsClipBoard();
287 : }
288 :
289 2616 : bool Bookmark::IsInUndo() const
290 : {
291 2616 : return false;
292 : }
293 :
294 32 : bool Bookmark::IsInContent() const
295 : {
296 32 : SwDoc *const pDoc( GetMarkPos().GetDoc() );
297 : OSL_ENSURE(pDoc, "Bookmark::IsInContent: no doc?");
298 32 : return !pDoc->IsInHeaderFooter( SwNodeIndex(GetMarkPos().nNode) );
299 : }
300 :
301 0 : uno::Reference< rdf::XMetadatable > Bookmark::MakeUnoObject()
302 : {
303 0 : SwDoc *const pDoc( GetMarkPos().GetDoc() );
304 : OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?");
305 : const uno::Reference< rdf::XMetadatable> xMeta(
306 0 : SwXBookmark::CreateXBookmark(*pDoc, this), uno::UNO_QUERY);
307 0 : return xMeta;
308 : }
309 :
310 218 : Fieldmark::Fieldmark(const SwPaM& rPaM)
311 218 : : MarkBase(rPaM, MarkBase::GenerateNewName(OUString("__Fieldmark__")))
312 : {
313 218 : if(!IsExpanded())
314 206 : SetOtherMarkPos(GetMarkPos());
315 218 : }
316 :
317 184 : void Fieldmark::SetMarkStartPos( const SwPosition& rNewStartPos )
318 : {
319 184 : if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
320 184 : return SetMarkPos( rNewStartPos );
321 : else
322 0 : return SetOtherMarkPos( rNewStartPos );
323 : }
324 :
325 26 : void Fieldmark::SetMarkEndPos( const SwPosition& rNewEndPos )
326 : {
327 26 : if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
328 26 : return SetOtherMarkPos( rNewEndPos );
329 : else
330 0 : return SetMarkPos( rNewEndPos );
331 : }
332 :
333 0 : OUString Fieldmark::ToString( ) const
334 : {
335 0 : return "Fieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( " + m_aName + ", "
336 0 : + m_aFieldname + ", [ " + OUString::number( GetMarkPos().nNode.GetIndex( ) )
337 0 : + ", " + OUString::number( GetMarkPos( ).nContent.GetIndex( ) ) + " ], ["
338 0 : + OUString::number( GetOtherMarkPos().nNode.GetIndex( ) ) + ", "
339 0 : + OUString::number( GetOtherMarkPos( ).nContent.GetIndex( ) ) + " ] ) ";
340 : }
341 :
342 0 : void Fieldmark::Invalidate( )
343 : {
344 : // TODO: Does exist a better solution to trigger a format of the
345 : // fieldmark portion? If yes, please use it.
346 0 : SwPaM aPaM( this->GetMarkPos(), this->GetOtherMarkPos() );
347 0 : aPaM.InvalidatePaM();
348 0 : }
349 :
350 192 : TextFieldmark::TextFieldmark(const SwPaM& rPaM)
351 192 : : Fieldmark(rPaM)
352 192 : { }
353 :
354 192 : void TextFieldmark::InitDoc(SwDoc* const io_pDoc)
355 : {
356 192 : lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
357 192 : }
358 :
359 0 : void TextFieldmark::ReleaseDoc(SwDoc* const pDoc)
360 : {
361 0 : lcl_RemoveFieldMarks(this, pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
362 0 : }
363 :
364 26 : CheckboxFieldmark::CheckboxFieldmark(const SwPaM& rPaM)
365 26 : : Fieldmark(rPaM)
366 26 : { }
367 :
368 26 : void CheckboxFieldmark::InitDoc(SwDoc* const io_pDoc)
369 : {
370 26 : lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT);
371 :
372 : // For some reason the end mark is moved from 1 by the Insert: we don't
373 : // want this for checkboxes
374 26 : SwPosition aNewEndPos = this->GetMarkEnd();
375 26 : aNewEndPos.nContent--;
376 26 : SetMarkEndPos( aNewEndPos );
377 26 : }
378 :
379 0 : void CheckboxFieldmark::ReleaseDoc(SwDoc* const pDoc)
380 : {
381 : lcl_RemoveFieldMarks(this, pDoc,
382 0 : CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT);
383 0 : }
384 :
385 22 : void CheckboxFieldmark::SetChecked(bool checked)
386 : {
387 22 : if ( IsChecked() != checked )
388 : {
389 8 : (*GetParameters())[OUString(ODF_FORMCHECKBOX_RESULT)] = makeAny(checked);
390 : // mark document as modified
391 8 : SwDoc *const pDoc( GetMarkPos().GetDoc() );
392 8 : if ( pDoc )
393 8 : pDoc->getIDocumentState().SetModified();
394 : }
395 22 : }
396 :
397 32 : bool CheckboxFieldmark::IsChecked() const
398 : {
399 32 : bool bResult = false;
400 32 : parameter_map_t::const_iterator pResult = GetParameters()->find(OUString(ODF_FORMCHECKBOX_RESULT));
401 32 : if(pResult != GetParameters()->end())
402 4 : pResult->second >>= bResult;
403 32 : return bResult;
404 : }
405 :
406 0 : OUString CheckboxFieldmark::toString( ) const
407 : {
408 :
409 : return "CheckboxFieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( "
410 0 : + m_aName + ", " + GetFieldname() + ", [ "
411 0 : + OUString::number(GetMarkPos().nNode.GetIndex( ) ) + ", "
412 0 : + OUString::number( GetMarkPos( ).nContent.GetIndex( ) ) + " ], ["
413 0 : + OUString::number( GetOtherMarkPos().nNode.GetIndex( ) ) + ", "
414 0 : + OUString::number( GetOtherMarkPos( ).nContent.GetIndex( ) ) + " ] ) ";
415 : }
416 270 : }}
417 :
418 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|