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