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