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 33 #include <stdlib.h> 34 35 #ifndef _APP_HXX 36 #include <vcl/svapp.hxx> 37 #endif 38 #include <tools/urlobj.hxx> 39 40 #define _SVSTDARR_STRINGS 41 #include <svl/svstdarr.hxx> 42 #include <sfx2/linkmgr.hxx> // LinkManager 43 #include <unotools/charclass.hxx> 44 #include <fmtcntnt.hxx> 45 #include <doc.hxx> 46 #include <swserv.hxx> // fuer Server-Funktionalitaet 47 #include <IMark.hxx> 48 #include <bookmrk.hxx> 49 #include <section.hxx> // fuer SwSectionFmt 50 #include <swtable.hxx> // fuer SwTable 51 #include <node.hxx> 52 #include <ndtxt.hxx> 53 #include <pam.hxx> 54 #include <docary.hxx> 55 #include <MarkManager.hxx> 56 57 using namespace ::com::sun::star; 58 59 namespace 60 { 61 62 static ::sw::mark::DdeBookmark* lcl_FindDdeBookmark(const IDocumentMarkAccess& rMarkAccess, const String& rName, bool bCaseSensitive) 63 { 64 //Iterating over all bookmarks, checking DdeBookmarks 65 const ::rtl::OUString sNameLc = bCaseSensitive ? rName : GetAppCharClass().lower(rName); 66 for(IDocumentMarkAccess::const_iterator_t ppMark = rMarkAccess.getMarksBegin(); 67 ppMark != rMarkAccess.getMarksEnd(); 68 ppMark++) 69 { 70 if (::sw::mark::DdeBookmark* const pBkmk = dynamic_cast< ::sw::mark::DdeBookmark*>(ppMark->get())) 71 { 72 if ( 73 (bCaseSensitive && (pBkmk->GetName() == sNameLc)) || 74 (!bCaseSensitive && GetAppCharClass().lower(pBkmk->GetName()) == String(sNameLc)) 75 ) 76 { 77 return pBkmk; 78 } 79 } 80 } 81 return NULL; 82 } 83 } 84 85 struct _FindItem 86 { 87 const String m_Item; 88 SwTableNode* pTblNd; 89 SwSectionNode* pSectNd; 90 91 _FindItem(const String& rS) 92 : m_Item(rS), pTblNd(0), pSectNd(0) 93 {} 94 }; 95 96 sal_Bool lcl_FindSection( const SwSectionFmtPtr& rpSectFmt, void* pArgs, bool bCaseSensitive ) 97 { 98 _FindItem * const pItem( static_cast<_FindItem*>(pArgs) ); 99 SwSection* pSect = rpSectFmt->GetSection(); 100 if( pSect ) 101 { 102 String sNm( (bCaseSensitive) 103 ? pSect->GetSectionName() 104 : GetAppCharClass().lower( pSect->GetSectionName() )); 105 String sCompare( (bCaseSensitive) 106 ? pItem->m_Item 107 : GetAppCharClass().lower( pItem->m_Item ) ); 108 if( sNm == sCompare ) 109 { 110 // gefunden, als erfrage die Daten 111 const SwNodeIndex* pIdx; 112 if( 0 != (pIdx = rpSectFmt->GetCntnt().GetCntntIdx() ) && 113 &rpSectFmt->GetDoc()->GetNodes() == &pIdx->GetNodes() ) 114 { 115 // eine Tabelle im normalen NodesArr 116 pItem->pSectNd = pIdx->GetNode().GetSectionNode(); 117 return sal_False; 118 } 119 //nein!! // sollte der Namen schon passen, der Rest aber nicht, dann haben wir 120 // sie nicht. Die Namen sind immer eindeutig. 121 } 122 } 123 return sal_True; // dann weiter 124 } 125 sal_Bool lcl_FindSectionCaseSensitive( const SwSectionFmtPtr& rpSectFmt, void* pArgs ) 126 { 127 return lcl_FindSection( rpSectFmt, pArgs, true ); 128 } 129 sal_Bool lcl_FindSectionCaseInsensitive( const SwSectionFmtPtr& rpSectFmt, void* pArgs ) 130 { 131 return lcl_FindSection( rpSectFmt, pArgs, false ); 132 } 133 134 135 136 sal_Bool lcl_FindTable( const SwFrmFmtPtr& rpTableFmt, void* pArgs ) 137 { 138 _FindItem * const pItem( static_cast<_FindItem*>(pArgs) ); 139 String sNm( GetAppCharClass().lower( rpTableFmt->GetName() )); 140 if (sNm.Equals( pItem->m_Item )) 141 { 142 SwTable* pTmpTbl; 143 SwTableBox* pFBox; 144 if( 0 != ( pTmpTbl = SwTable::FindTable( rpTableFmt ) ) && 145 0 != ( pFBox = pTmpTbl->GetTabSortBoxes()[0] ) && 146 pFBox->GetSttNd() && 147 &rpTableFmt->GetDoc()->GetNodes() == &pFBox->GetSttNd()->GetNodes() ) 148 { 149 // eine Tabelle im normalen NodesArr 150 pItem->pTblNd = (SwTableNode*) 151 pFBox->GetSttNd()->FindTableNode(); 152 return sal_False; 153 } 154 //nein! // sollte der Namen schon passen, der Rest aber nicht, dann haben wir 155 // sie nicht. Die Namen sind immer eindeutig. 156 } 157 return sal_True; // dann weiter 158 } 159 160 161 162 bool SwDoc::GetData( const String& rItem, const String& rMimeType, 163 uno::Any & rValue ) const 164 { 165 //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive 166 bool bCaseSensitive = true; 167 while( true ) 168 { 169 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, rItem, bCaseSensitive); 170 if(pBkmk) 171 return SwServerObject(*pBkmk).GetData(rValue, rMimeType); 172 173 // haben wir ueberhaupt das Item vorraetig? 174 String sItem( bCaseSensitive ? rItem : GetAppCharClass().lower(rItem)); 175 _FindItem aPara( sItem ); 176 ((SwSectionFmts&)*pSectionFmtTbl).ForEach( 0, pSectionFmtTbl->Count(), 177 bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara ); 178 if( aPara.pSectNd ) 179 { 180 // gefunden, als erfrage die Daten 181 return SwServerObject( *aPara.pSectNd ).GetData( rValue, rMimeType ); 182 } 183 if( !bCaseSensitive ) 184 break; 185 bCaseSensitive = false; 186 } 187 188 _FindItem aPara( GetAppCharClass().lower( rItem )); 189 ((SwFrmFmts*)pTblFrmFmtTbl)->ForEach( 0, pTblFrmFmtTbl->Count(), 190 lcl_FindTable, &aPara ); 191 if( aPara.pTblNd ) 192 { 193 return SwServerObject( *aPara.pTblNd ).GetData( rValue, rMimeType ); 194 } 195 196 return sal_False; 197 } 198 199 200 201 bool SwDoc::SetData( const String& rItem, const String& rMimeType, 202 const uno::Any & rValue ) 203 { 204 //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive 205 bool bCaseSensitive = true; 206 while( true ) 207 { 208 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, rItem, bCaseSensitive); 209 if(pBkmk) 210 return SwServerObject(*pBkmk).SetData(rMimeType, rValue); 211 212 // haben wir ueberhaupt das Item vorraetig? 213 String sItem( bCaseSensitive ? rItem : GetAppCharClass().lower(rItem)); 214 _FindItem aPara( sItem ); 215 pSectionFmtTbl->ForEach( 0, pSectionFmtTbl->Count(), bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara ); 216 if( aPara.pSectNd ) 217 { 218 // gefunden, als erfrage die Daten 219 return SwServerObject( *aPara.pSectNd ).SetData( rMimeType, rValue ); 220 } 221 if( !bCaseSensitive ) 222 break; 223 bCaseSensitive = false; 224 } 225 226 String sItem(GetAppCharClass().lower(rItem)); 227 _FindItem aPara( sItem ); 228 pTblFrmFmtTbl->ForEach( 0, pTblFrmFmtTbl->Count(), lcl_FindTable, &aPara ); 229 if( aPara.pTblNd ) 230 { 231 return SwServerObject( *aPara.pTblNd ).SetData( rMimeType, rValue ); 232 } 233 234 return sal_False; 235 } 236 237 238 239 ::sfx2::SvLinkSource* SwDoc::CreateLinkSource(const String& rItem) 240 { 241 SwServerObject* pObj = NULL; 242 243 //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive 244 bool bCaseSensitive = true; 245 while( true ) 246 { 247 // bookmarks 248 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, rItem, bCaseSensitive); 249 if(pBkmk && pBkmk->IsExpanded() 250 && (0 == (pObj = pBkmk->GetRefObject()))) 251 { 252 // mark found, but no link yet -> create hotlink 253 pObj = new SwServerObject(*pBkmk); 254 pBkmk->SetRefObject(pObj); 255 GetLinkManager().InsertServer(pObj); 256 } 257 if(pObj) 258 return pObj; 259 260 _FindItem aPara(bCaseSensitive ? rItem : GetAppCharClass().lower(rItem)); 261 // sections 262 ((SwSectionFmts&)*pSectionFmtTbl).ForEach(0, pSectionFmtTbl->Count(), bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara); 263 if(aPara.pSectNd 264 && (0 == (pObj = aPara.pSectNd->GetSection().GetObject()))) 265 { 266 // section found, but no link yet -> create hotlink 267 pObj = new SwServerObject( *aPara.pSectNd ); 268 aPara.pSectNd->GetSection().SetRefObject( pObj ); 269 GetLinkManager().InsertServer(pObj); 270 } 271 if(pObj) 272 return pObj; 273 if( !bCaseSensitive ) 274 break; 275 bCaseSensitive = false; 276 } 277 278 _FindItem aPara( GetAppCharClass().lower(rItem) ); 279 // tables 280 ((SwFrmFmts*)pTblFrmFmtTbl)->ForEach(0, pTblFrmFmtTbl->Count(), lcl_FindTable, &aPara); 281 if(aPara.pTblNd 282 && (0 == (pObj = aPara.pTblNd->GetTable().GetObject()))) 283 { 284 // table found, but no link yet -> create hotlink 285 pObj = new SwServerObject(*aPara.pTblNd); 286 aPara.pTblNd->GetTable().SetRefObject(pObj); 287 GetLinkManager().InsertServer(pObj); 288 } 289 return pObj; 290 } 291 292 sal_Bool SwDoc::SelectServerObj( const String& rStr, SwPaM*& rpPam, 293 SwNodeRange*& rpRange ) const 294 { 295 // haben wir ueberhaupt das Item vorraetig? 296 rpPam = 0; 297 rpRange = 0; 298 299 String sItem( INetURLObject::decode( rStr, INET_HEX_ESCAPE, 300 INetURLObject::DECODE_WITH_CHARSET, 301 RTL_TEXTENCODING_UTF8 )); 302 303 xub_StrLen nPos = sItem.Search( cMarkSeperator ); 304 305 const CharClass& rCC = GetAppCharClass(); 306 307 // Erweiterung fuer die Bereiche, nicht nur Bookmarks/Bereiche linken, 308 // sondern auch Rahmen(Text!), Tabellen, Gliederungen: 309 if( STRING_NOTFOUND != nPos ) 310 { 311 sal_Bool bWeiter = sal_False; 312 String sName( sItem.Copy( 0, nPos ) ); 313 String sCmp( sItem.Copy( nPos + 1 )); 314 rCC.toLower( sItem ); 315 316 _FindItem aPara( sName ); 317 318 if( sCmp.EqualsAscii( pMarkToTable ) ) 319 { 320 rCC.toLower( sName ); 321 ((SwFrmFmts*)pTblFrmFmtTbl)->ForEach( 0, pTblFrmFmtTbl->Count(), 322 lcl_FindTable, &aPara ); 323 if( aPara.pTblNd ) 324 { 325 rpRange = new SwNodeRange( *aPara.pTblNd, 0, 326 *aPara.pTblNd->EndOfSectionNode(), 1 ); 327 return sal_True; 328 } 329 } 330 else if( sCmp.EqualsAscii( pMarkToFrame ) ) 331 { 332 SwNodeIndex* pIdx; 333 SwNode* pNd; 334 const SwFlyFrmFmt* pFlyFmt = FindFlyByName( sName ); 335 if( pFlyFmt && 336 0 != ( pIdx = (SwNodeIndex*)pFlyFmt->GetCntnt().GetCntntIdx() ) && 337 !( pNd = &pIdx->GetNode())->IsNoTxtNode() ) 338 { 339 rpRange = new SwNodeRange( *pNd, 1, *pNd->EndOfSectionNode() ); 340 return sal_True; 341 } 342 } 343 else if( sCmp.EqualsAscii( pMarkToRegion ) ) 344 { 345 sItem = sName; // wird unten behandelt ! 346 bWeiter = sal_True; 347 } 348 else if( sCmp.EqualsAscii( pMarkToOutline ) ) 349 { 350 SwPosition aPos( SwNodeIndex( (SwNodes&)GetNodes() )); 351 if( GotoOutline( aPos, sName )) 352 { 353 SwNode* pNd = &aPos.nNode.GetNode(); 354 //sal_uInt8 nLvl = pNd->GetTxtNode()->GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei 355 const int nLvl = pNd->GetTxtNode()->GetAttrOutlineLevel()-1;//<-end,zhaojianwei 356 357 const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds(); 358 sal_uInt16 nTmpPos; 359 rOutlNds.Seek_Entry( pNd, &nTmpPos ); 360 rpRange = new SwNodeRange( aPos.nNode, 0, aPos.nNode ); 361 362 // dann suche jetzt noch das Ende vom Bereich 363 for( ++nTmpPos; 364 nTmpPos < rOutlNds.Count() && 365 nLvl < rOutlNds[ nTmpPos ]->GetTxtNode()-> 366 //GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei 367 GetAttrOutlineLevel()-1;//<-end,zhaojianwei 368 ++nTmpPos ) 369 ; // es gibt keinen Block 370 371 if( nTmpPos < rOutlNds.Count() ) 372 rpRange->aEnd = *rOutlNds[ nTmpPos ]; 373 else 374 rpRange->aEnd = GetNodes().GetEndOfContent(); 375 return sal_True; 376 } 377 } 378 379 if( !bWeiter ) 380 return sal_False; 381 } 382 383 //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive 384 bool bCaseSensitive = true; 385 while( true ) 386 { 387 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, sItem, bCaseSensitive); 388 if(pBkmk) 389 { 390 if(pBkmk->IsExpanded()) 391 rpPam = new SwPaM( 392 pBkmk->GetMarkPos(), 393 pBkmk->GetOtherMarkPos()); 394 return static_cast<bool>(rpPam); 395 } 396 397 // 398 _FindItem aPara( bCaseSensitive ? sItem : rCC.lower( sItem ) ); 399 400 if( pSectionFmtTbl->Count() ) 401 { 402 ((SwSectionFmts&)*pSectionFmtTbl).ForEach( 0, pSectionFmtTbl->Count(), 403 bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara ); 404 if( aPara.pSectNd ) 405 { 406 rpRange = new SwNodeRange( *aPara.pSectNd, 1, 407 *aPara.pSectNd->EndOfSectionNode() ); 408 return sal_True; 409 410 } 411 } 412 if( !bCaseSensitive ) 413 break; 414 bCaseSensitive = false; 415 } 416 return sal_False; 417 } 418 419