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