xref: /aoo41x/main/sw/source/core/doc/docdde.cxx (revision cdf0e10c)
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