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