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