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