xref: /aoo41x/main/sw/source/core/crsr/bookmrk.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <bookmrk.hxx>
33 #include <IDocumentMarkAccess.hxx>
34 #include <IDocumentUndoRedo.hxx>
35 #include <doc.hxx>
36 #include <errhdl.hxx>
37 #include <ndtxt.hxx>
38 #include <pam.hxx>
39 #include <swserv.hxx>
40 #include <sfx2/linkmgr.hxx>
41 #include <swtypes.hxx>
42 #include <UndoBookmark.hxx>
43 #include <unobookmark.hxx>
44 #include <rtl/random.h>
45 #include <xmloff/odffields.hxx>
46 
47 
48 SV_IMPL_REF( SwServerObject )
49 
50 using namespace ::sw::mark;
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::uno;
53 
54 namespace
55 {
56     static void lcl_FixPosition(SwPosition& rPos)
57     {
58         // make sure the position has 1) the proper node, and 2) a proper index
59         SwTxtNode* pTxtNode = rPos.nNode.GetNode().GetTxtNode();
60         if(pTxtNode == NULL && rPos.nContent.GetIndex() > 0)
61         {
62             OSL_TRACE(
63                 "bookmrk.cxx::lcl_FixPosition"
64                 " - illegal position: %d without proper TxtNode", rPos.nContent.GetIndex());
65             rPos.nContent.Assign(NULL, 0);
66         }
67         else if(pTxtNode != NULL && rPos.nContent.GetIndex() > pTxtNode->Len())
68         {
69             OSL_TRACE(
70                 "bookmrk.cxx::lcl_FixPosition"
71                 " - illegal position: %d is beyond %d", rPos.nContent.GetIndex(), pTxtNode->Len());
72             rPos.nContent.Assign(pTxtNode, pTxtNode->Len());
73         }
74     };
75 
76     static void lcl_AssureFieldMarksSet(Fieldmark* const pField,
77         SwDoc* const io_pDoc,
78         const sal_Unicode aStartMark,
79         const sal_Unicode aEndMark)
80     {
81         SwPosition& rStart = pField->GetMarkStart();
82         SwPosition& rEnd = pField->GetMarkEnd();
83         SwTxtNode const*const pStartTxtNode =
84             rStart.nNode.GetNode().GetTxtNode();
85         SwTxtNode const*const pEndTxtNode = rEnd.nNode.GetNode().GetTxtNode();
86         const sal_Unicode ch_start=pStartTxtNode->GetTxt().GetChar(rStart.nContent.GetIndex());
87         const sal_Unicode ch_end=pEndTxtNode->GetTxt().GetChar(rEnd.nContent.GetIndex()-1);
88         SwPaM aStartPaM(rStart);
89         SwPaM aEndPaM(rEnd);
90         io_pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_UI_REPLACE, NULL);
91         if(ch_start != aStartMark)
92         {
93             io_pDoc->InsertString(aStartPaM, aStartMark);
94         }
95         if ( aEndMark && ( ch_end != aEndMark ) && ( rStart != rEnd ) )
96         {
97             io_pDoc->InsertString(aEndPaM, aEndMark);
98         }
99         io_pDoc->GetIDocumentUndoRedo().EndUndo(UNDO_UI_REPLACE, NULL);
100     };
101 }
102 
103 namespace sw { namespace mark
104 {
105     MarkBase::MarkBase(const SwPaM& aPaM,
106         const ::rtl::OUString& rName)
107         : SwModify(0)
108         , m_pPos1(new SwPosition(*(aPaM.GetPoint())))
109         , m_aName(rName)
110     {
111         lcl_FixPosition(*m_pPos1);
112         if (aPaM.HasMark() && (*aPaM.GetMark() != *aPaM.GetPoint()))
113         {
114             MarkBase::SetOtherMarkPos(*(aPaM.GetMark()));
115             lcl_FixPosition(*m_pPos2);
116         }
117     }
118 
119     bool MarkBase::IsCoveringPosition(const SwPosition& rPos) const
120     {
121         return GetMarkStart() <= rPos && rPos <= GetMarkEnd();
122     }
123 
124     void MarkBase::SetMarkPos(const SwPosition& rNewPos)
125     {
126         ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos1);
127         //lcl_FixPosition(*m_pPos1);
128     }
129 
130     void MarkBase::SetOtherMarkPos(const SwPosition& rNewPos)
131     {
132         ::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos2);
133         //lcl_FixPosition(*m_pPos2);
134     }
135 
136     rtl::OUString MarkBase::ToString( ) const
137     {
138         rtl::OUStringBuffer buf;
139         buf.appendAscii( "Mark: ( Name, [ Node1, Index1 ] ): ( " );
140         buf.append( m_aName ).appendAscii( ", [ " );
141         buf.append( sal_Int32( GetMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " );
142         buf.append( sal_Int32( GetMarkPos().nContent.GetIndex( ) ) ).appendAscii( " ] )" );
143 
144         return buf.makeStringAndClear( );
145     }
146 
147     MarkBase::~MarkBase()
148     { }
149 
150     ::rtl::OUString MarkBase::GenerateNewName(const ::rtl::OUString& rPrefix)
151     {
152         static rtlRandomPool aPool = rtl_random_createPool();
153         static ::rtl::OUString sUniquePostfix;
154         static sal_Int32 nCount = SAL_MAX_INT32;
155         ::rtl::OUStringBuffer aResult(rPrefix);
156         if(nCount == SAL_MAX_INT32)
157         {
158             sal_Int32 nRandom;
159             ::rtl::OUStringBuffer sUniquePostfixBuffer;
160             rtl_random_getBytes(aPool, &nRandom, sizeof(nRandom));
161             sUniquePostfix = ::rtl::OUStringBuffer(13).appendAscii("_").append(static_cast<sal_Int32>(abs(nRandom))).makeStringAndClear();
162             nCount = 0;
163         }
164         // putting the counter in front of the random parts will speed up string comparisons
165         return aResult.append(nCount++).append(sUniquePostfix).makeStringAndClear();
166     }
167 
168 
169     void MarkBase::Modify( const SfxPoolItem *pOld, const SfxPoolItem *pNew )
170     {
171         NotifyClients(pOld, pNew);
172         if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
173         {   // invalidate cached uno object
174             SetXBookmark(uno::Reference<text::XTextContent>(0));
175         }
176     }
177 
178 
179     NavigatorReminder::NavigatorReminder(const SwPaM& rPaM)
180         : MarkBase(rPaM, our_sNamePrefix)
181     { }
182 
183     const ::rtl::OUString NavigatorReminder::our_sNamePrefix = ::rtl::OUString::createFromAscii("__NavigatorReminder__");
184 
185     UnoMark::UnoMark(const SwPaM& aPaM)
186         : MarkBase(aPaM, MarkBase::GenerateNewName(our_sNamePrefix))
187     { }
188 
189     const ::rtl::OUString UnoMark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__UnoMark__");
190 
191     DdeBookmark::DdeBookmark(const SwPaM& aPaM)
192         : MarkBase(aPaM, MarkBase::GenerateNewName(our_sNamePrefix))
193         , m_aRefObj(NULL)
194     { }
195 
196     void DdeBookmark::SetRefObject(SwServerObject* pObj)
197     {
198         m_aRefObj = pObj;
199     }
200 
201     const ::rtl::OUString DdeBookmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__DdeLink__");
202 
203     void DdeBookmark::DeregisterFromDoc(SwDoc* const pDoc)
204     {
205         if(m_aRefObj.Is())
206             pDoc->GetLinkManager().RemoveServer(m_aRefObj);
207     }
208 
209     DdeBookmark::~DdeBookmark()
210     {
211         if( m_aRefObj.Is() )
212         {
213             if(m_aRefObj->HasDataLinks())
214             {
215                 ::sfx2::SvLinkSource* p = &m_aRefObj;
216                 p->SendDataChanged();
217             }
218             m_aRefObj->SetNoServer();
219         }
220     }
221 
222     Bookmark::Bookmark(const SwPaM& aPaM,
223         const KeyCode& rCode,
224         const ::rtl::OUString& rName,
225         const ::rtl::OUString& rShortName)
226         : DdeBookmark(aPaM)
227         , ::sfx2::Metadatable()
228         , m_aCode(rCode)
229         , m_sShortName(rShortName)
230     {
231         m_aName = rName;
232     }
233 
234     void Bookmark::InitDoc(SwDoc* const io_pDoc)
235     {
236         if (io_pDoc->GetIDocumentUndoRedo().DoesUndo())
237         {
238             io_pDoc->GetIDocumentUndoRedo().AppendUndo(
239                     new SwUndoInsBookmark(*this));
240         }
241         io_pDoc->SetModified();
242     }
243 
244     // ::sfx2::Metadatable
245     ::sfx2::IXmlIdRegistry& Bookmark::GetRegistry()
246     {
247         SwDoc *const pDoc( GetMarkPos().GetDoc() );
248         OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?");
249         return pDoc->GetXmlIdRegistry();
250     }
251 
252     bool Bookmark::IsInClipboard() const
253     {
254         SwDoc *const pDoc( GetMarkPos().GetDoc() );
255         OSL_ENSURE(pDoc, "Bookmark::IsInClipboard: no doc?");
256         return pDoc->IsClipBoard();
257     }
258 
259     bool Bookmark::IsInUndo() const
260     {
261         return false;
262     }
263 
264     bool Bookmark::IsInContent() const
265     {
266         SwDoc *const pDoc( GetMarkPos().GetDoc() );
267         OSL_ENSURE(pDoc, "Bookmark::IsInContent: no doc?");
268         return !pDoc->IsInHeaderFooter( SwNodeIndex(GetMarkPos().nNode) );
269     }
270 
271     uno::Reference< rdf::XMetadatable > Bookmark::MakeUnoObject()
272     {
273         // create new SwXBookmark
274         SwDoc *const pDoc( GetMarkPos().GetDoc() );
275         OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?");
276         const uno::Reference< rdf::XMetadatable> xMeta(
277                 SwXBookmark::CreateXBookmark(*pDoc, *this), uno::UNO_QUERY);
278         return xMeta;
279     }
280 
281 
282     Fieldmark::Fieldmark(const SwPaM& rPaM)
283         : MarkBase(rPaM, MarkBase::GenerateNewName(our_sNamePrefix))
284     {
285         if(!IsExpanded())
286             SetOtherMarkPos(GetMarkPos());
287     }
288 
289     rtl::OUString Fieldmark::ToString( ) const
290     {
291         rtl::OUStringBuffer buf;
292         buf.appendAscii( "Fieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( " );
293         buf.append( m_aName ).appendAscii( ", " );
294         buf.append( m_aFieldname ).appendAscii( ", [ " );
295         buf.append( sal_Int32( GetMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " );
296         buf.append( sal_Int32( GetMarkPos( ).nContent.GetIndex( ) ) ).appendAscii( " ], [" );
297         buf.append( sal_Int32( GetOtherMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " );
298         buf.append( sal_Int32( GetOtherMarkPos( ).nContent.GetIndex( ) ) ).appendAscii( " ] ) " );
299 
300         return buf.makeStringAndClear( );
301     }
302 
303     void Fieldmark::Invalidate( )
304     {
305         // @TODO: Does exist a better solution to trigger a format of the
306         //        fieldmark portion? If yes, please use it.
307         SwPaM aPaM( this->GetMarkPos(), this->GetOtherMarkPos() );
308         aPaM.InvalidatePaM();
309     }
310 
311     const ::rtl::OUString Fieldmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__Fieldmark__");
312 
313     TextFieldmark::TextFieldmark(const SwPaM& rPaM)
314         : Fieldmark(rPaM)
315     { }
316 
317     void TextFieldmark::InitDoc(SwDoc* const io_pDoc)
318     {
319         lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
320     }
321 
322     CheckboxFieldmark::CheckboxFieldmark(const SwPaM& rPaM)
323         : Fieldmark(rPaM)
324     { }
325 
326     void CheckboxFieldmark::InitDoc(SwDoc* const io_pDoc)
327     {
328         lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FORMELEMENT, CH_TXT_ATR_FIELDEND);
329 
330         // For some reason the end mark is moved from 1 by the Insert: we don't
331         // want this for checkboxes
332         this->GetMarkEnd( ).nContent--;
333     }
334     void CheckboxFieldmark::SetChecked(bool checked)
335     {
336         (*GetParameters())[::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_RESULT)] = makeAny(checked);
337     }
338 
339     bool CheckboxFieldmark::IsChecked() const
340     {
341         bool bResult = false;
342         parameter_map_t::const_iterator pResult = GetParameters()->find(::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_RESULT));
343         if(pResult != GetParameters()->end())
344             pResult->second >>= bResult;
345         return bResult;
346     }
347 
348 }}
349