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
29 #include <stdlib.h>
30
31 #ifndef _APP_HXX
32 #include <vcl/svapp.hxx>
33 #endif
34 #include <tools/urlobj.hxx>
35
36 #define _SVSTDARR_STRINGS
37 #include <svl/svstdarr.hxx>
38 #include <sfx2/linkmgr.hxx> // LinkManager
39 #include <unotools/charclass.hxx>
40 #include <fmtcntnt.hxx>
41 #include <doc.hxx>
42 #include <swserv.hxx> // fuer Server-Funktionalitaet
43 #include <IMark.hxx>
44 #include <bookmrk.hxx>
45 #include <section.hxx> // fuer SwSectionFmt
46 #include <swtable.hxx> // fuer SwTable
47 #include <node.hxx>
48 #include <ndtxt.hxx>
49 #include <pam.hxx>
50 #include <docary.hxx>
51 #include <MarkManager.hxx>
52
53 using namespace ::com::sun::star;
54
55 namespace
56 {
57
lcl_FindDdeBookmark(const IDocumentMarkAccess & rMarkAccess,const String & rName,const bool bCaseSensitive)58 static ::sw::mark::DdeBookmark* lcl_FindDdeBookmark(
59 const IDocumentMarkAccess& rMarkAccess,
60 const String& rName,
61 const bool bCaseSensitive )
62 {
63 //Iterating over all bookmarks, checking DdeBookmarks
64 const ::rtl::OUString sNameLc = bCaseSensitive ? rName : GetAppCharClass().lower(rName);
65 for(IDocumentMarkAccess::const_iterator_t ppMark = rMarkAccess.getAllMarksBegin();
66 ppMark != rMarkAccess.getAllMarksEnd();
67 ppMark++)
68 {
69 if ( IDocumentMarkAccess::GetType( *(ppMark->get()) ) == IDocumentMarkAccess::DDE_BOOKMARK)
70 {
71 ::sw::mark::DdeBookmark* const pBkmk = dynamic_cast< ::sw::mark::DdeBookmark*>(ppMark->get());
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
_FindItem_FindItem91 _FindItem(const String& rS)
92 : m_Item(rS), pTblNd(0), pSectNd(0)
93 {}
94 };
95
lcl_FindSection(const SwSectionFmtPtr & rpSectFmt,void * pArgs,bool bCaseSensitive)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 }
lcl_FindSectionCaseSensitive(const SwSectionFmtPtr & rpSectFmt,void * pArgs)125 sal_Bool lcl_FindSectionCaseSensitive( const SwSectionFmtPtr& rpSectFmt, void* pArgs )
126 {
127 return lcl_FindSection( rpSectFmt, pArgs, true );
128 }
lcl_FindSectionCaseInsensitive(const SwSectionFmtPtr & rpSectFmt,void * pArgs)129 sal_Bool lcl_FindSectionCaseInsensitive( const SwSectionFmtPtr& rpSectFmt, void* pArgs )
130 {
131 return lcl_FindSection( rpSectFmt, pArgs, false );
132 }
133
134
135
lcl_FindTable(const SwFrmFmtPtr & rpTableFmt,void * pArgs)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
GetData(const String & rItem,const String & rMimeType,uno::Any & rValue) const162 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
SetData(const String & rItem,const String & rMimeType,const uno::Any & rValue)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
CreateLinkSource(const String & rItem)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
SelectServerObj(const String & rStr,SwPaM * & rpPam,SwNodeRange * & rpRange) const292 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