xref: /trunk/main/sw/source/core/doc/docdde.cxx (revision 57e74413)
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 sensitive 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 sensitive 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 sensitive 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 sensitive 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