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