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