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