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