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