xref: /AOO41X/main/svx/workben/msview/msview.cxx (revision f6e50924346d0b8c0b07c91832a97665dd718b0c)
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_svx.hxx"
26 
27 #include <vector>
28 #include <map>
29 #include <algorithm>
30 #include <boost/shared_ptr.hpp>
31 #include <sot/storage.hxx>
32 #ifndef _SVTOOLS_HRC
33 #include <svtools/svtools.hrc>
34 #endif
35 
36 #include <sal/main.h>
37 #include <vcl/event.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/wrkwin.hxx>
40 #include <vcl/msgbox.hxx>
41 #include <vcl/fixed.hxx>
42 #include <vcl/edit.hxx>
43 #include <vcl/button.hxx>
44 #include <vcl/lstbox.hxx>
45 #include <svtools/filectrl.hxx>
46 #include <tools/urlobj.hxx>
47 #include <osl/file.hxx>
48 #include <vcl/unohelp2.hxx>
49 #include <svtools/svtreebx.hxx>
50 #include <svtools/svmedit.hxx>
51 #include <sfx2/filedlghelper.hxx>
52 
53 #include <toolkit/unohlp.hxx>
54 
55 #include <tools/stream.hxx>
56 #include <tools/resmgr.hxx>
57 
58 #include <comphelper/processfactory.hxx>
59 #include <cppuhelper/servicefactory.hxx>
60 #include <cppuhelper/bootstrap.hxx>
61 
62 #include <ucbhelper/contentbroker.hxx>
63 #include <ucbhelper/configurationkeys.hxx>
64 
65 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
66 
67 #include <com/sun/star/awt/XWindowPeer.hpp>
68 #include <com/sun/star/awt/XToolkit.hpp>
69 #include <com/sun/star/awt/WindowDescriptor.hpp>
70 #include <com/sun/star/awt/WindowAttribute.hpp>
71 #include <svx/msdffdef.hxx>
72 
73 #include <unotools/localfilehelper.hxx>
74 
75 #include "xmlconfig.hxx"
76 
77 using ::rtl::OUString;
78 
79 using namespace ::com::sun::star;
80 
81 ///////////////////////////////////////////////////////////////////////
82 
83 enum CompareStatus           { CMP_NOTYET = 0, CMP_EQUAL = 1, CMP_NOTEQUAL = 2, CMP_NOTAVAILABLE = 3 };
84 static ColorData gColors[] = { COL_BLACK,      COL_GREEN,     COL_RED,          COL_CYAN };
85 
86 class Atom
87 {
88 public:
89     ~Atom();
90 
91     /** imports this atom and its child atoms */
92     static Atom* import( const DffRecordHeader& rRootRecordHeader, SvStream& rStCtrl );
93     static Atom* import( UINT16 nRecType, SvStream& rStCtrl );
94 
95     inline const DffRecordHeader& getHeader() const;
96 
97     /** returns true if at least one atim with the given nRecType is found */
98     inline bool hasChildAtom( sal_uInt16 nRecType ) const;
99 
100     /** returns true if at least one atim with the given nRecType and nRecInstnace is found */
101     inline bool hasChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance ) const;
102 
103     /** returns the first child atom with nRecType or NULL */
104     inline const Atom* findFirstChildAtom( sal_uInt16 nRecType ) const;
105 
106     /** returns the next child atom after pLast with nRecType or NULL */
107     const Atom* findNextChildAtom( sal_uInt16 nRecType, const Atom* pLast ) const;
108 
109     /** returns the first child atom with nRecType and nRecInstance or NULL */
110     inline const Atom* findFirstChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance ) const;
111 
112     /** returns the next child atom after pLast with nRecType and nRecInstance or NULL */
113     const Atom* findNextChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance, const Atom* pLast ) const;
114 
115     /** returns the first child atom or NULL */
116     inline const Atom* findFirstChildAtom() const;
117 
118     /** returns the next child atom after pLast or NULL */
119     inline const Atom* findNextChildAtom( const Atom* pLast ) const;
120 
121     /** returns true if this atom is a container */
122     inline bool isContainer() const;
123 
124     /** seeks to the contents of this atom */
125     inline bool seekToContent() const;
126 
127     /** returns the record type */
128     inline sal_uInt16 getType() const;
129 
130     /** returns the record instance */
131     inline sal_uInt16 getInstance() const;
132 
133     /** returns the record length */
134     inline sal_uInt32 getLength() const;
135 
getStream() const136     SvStream& getStream() const { return mrStream; }
137 
138     bool operator==( const Atom& rAtom ) const;
139 
getCompareStatus() const140     CompareStatus getCompareStatus() const { return meStatus; }
141 
142     void compare( Atom* pAtom );
143     bool compareContent( Atom& rAtom );
144 
getCompareAtom() const145     Atom* getCompareAtom() const { return mpCompareAtom; }
setCompareAtom(Atom * pAtom)146     void setCompareAtom( Atom* pAtom ) { mpCompareAtom = pAtom; }
147 
148 private:
149     Atom( const DffRecordHeader& rRecordHeader, SvStream& rStCtrl );
150 
151     // statics for compare
152     static Atom* skipAtoms( Atom* pContainer, Atom* pAtom, Atom* pSkipTo );
153     static Atom* findFirstEqualAtom( Atom* pCompare, Atom* pContainer, Atom* pSearch, int& nDistance );
154 
155     SvStream& mrStream;
156     DffRecordHeader maRecordHeader;
157     Atom* mpFirstChild;
158     Atom* mpNextAtom;
159 
160     CompareStatus meStatus;
161     Atom* mpCompareAtom;
162 };
163 
operator ==(const Atom & rAtom) const164 bool Atom::operator==( const Atom& rAtom ) const
165 {
166     return ( maRecordHeader.nRecType == rAtom.maRecordHeader.nRecType ) &&
167             ( maRecordHeader.nRecVer == rAtom.maRecordHeader.nRecVer ) &&
168            ( maRecordHeader.nRecInstance == rAtom.maRecordHeader.nRecInstance );
169 }
170 
compareContent(Atom & rAtom)171 bool Atom::compareContent( Atom& rAtom )
172 {
173     if( maRecordHeader.nRecLen == rAtom.maRecordHeader.nRecLen )
174     {
175         seekToContent();
176         rAtom.seekToContent();
177 
178         SvStream& rStream1 = getStream();
179         SvStream& rStream2 = rAtom.getStream();
180 
181         const int nBufferSize = 1024;
182         boost::shared_ptr< char > buffer1( new char[nBufferSize] );
183         boost::shared_ptr< char > buffer2( new char[nBufferSize] );
184 
185         sal_uInt32 nLength = maRecordHeader.nRecLen;
186         sal_Size nRead = 0;
187         while( nLength )
188         {
189             sal_Size nRead = (nBufferSize < nLength) ? nBufferSize : nLength;
190             nRead = rStream1.Read( (void*)buffer1.get(), nRead );
191             if( nRead == 0 )
192                 break;
193             if( rStream2.Read( (void*)buffer2.get(), nRead ) != nRead )
194                 break;
195             if( memcmp( (void*)buffer1.get(), (void*)buffer2.get(), nRead ) != 0 )
196                 break;
197 
198             nLength -= nRead;
199         }
200 
201         return nLength == 0;
202     }
203 
204     return false;
205 }
206 
hasChildAtom(sal_uInt16 nRecType) const207 inline bool Atom::hasChildAtom( sal_uInt16 nRecType ) const
208 {
209     return findFirstChildAtom( nRecType ) != NULL;
210 }
211 
hasChildAtom(sal_uInt16 nRecType,sal_uInt16 nRecInstance) const212 inline bool Atom::hasChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance ) const
213 {
214     return findFirstChildAtom( nRecType, nRecInstance ) != NULL;
215 }
216 
findFirstChildAtom(sal_uInt16 nRecType) const217 inline const Atom* Atom::findFirstChildAtom( sal_uInt16 nRecType ) const
218 {
219     return findNextChildAtom( nRecType, NULL );
220 }
221 
getHeader() const222 inline const DffRecordHeader& Atom::getHeader() const
223 {
224     return maRecordHeader;
225 }
226 
findFirstChildAtom(sal_uInt16 nRecType,sal_uInt16 nRecInstance) const227 inline const Atom* Atom::findFirstChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance ) const
228 {
229     return findNextChildAtom( nRecType, nRecInstance, NULL );
230 }
231 
findFirstChildAtom() const232 inline const Atom* Atom::findFirstChildAtom() const
233 {
234     return mpFirstChild;
235 }
236 
findNextChildAtom(const Atom * pLast) const237 inline const Atom* Atom::findNextChildAtom( const Atom* pLast ) const
238 {
239     return pLast ? pLast->mpNextAtom : pLast;
240 }
241 
isContainer() const242 inline bool Atom::isContainer() const
243 {
244     return (bool)maRecordHeader.IsContainer();
245 }
246 
seekToContent() const247 inline bool Atom::seekToContent() const
248 {
249     maRecordHeader.SeekToContent( mrStream );
250     return mrStream.GetError() == 0;
251 }
252 
getType() const253 inline sal_uInt16 Atom::getType() const
254 {
255     return maRecordHeader.nRecType;
256 }
257 
getInstance() const258 inline sal_uInt16 Atom::getInstance() const
259 {
260     return maRecordHeader.nRecInstance;
261 }
262 
getLength() const263 inline sal_uInt32 Atom::getLength() const
264 {
265     return maRecordHeader.nRecLen;
266 }
267 
Atom(const DffRecordHeader & rRecordHeader,SvStream & rStream)268 Atom::Atom( const DffRecordHeader& rRecordHeader, SvStream& rStream )
269 : maRecordHeader( rRecordHeader ),
270   mrStream( rStream ),
271   mpFirstChild( 0 ),
272   mpNextAtom( 0 ),
273   meStatus( CMP_NOTYET ),
274   mpCompareAtom( 0 )
275 {
276     // check if we need to force this to a container
277     if( maRecordHeader.nRecVer != DFF_PSFLAG_CONTAINER )
278     {
279         AtomConfig* pAtomConfig = dynamic_cast< AtomConfig* >( gAtomConfigMap[ maRecordHeader.nRecType ].get() );
280         if( pAtomConfig && pAtomConfig->isContainer() )
281         {
282             maRecordHeader.nRecVer = DFF_PSFLAG_CONTAINER;
283         }
284     }
285 
286     if( isContainer() )
287     {
288         if( seekToContent() )
289         {
290             DffRecordHeader aChildHeader;
291 
292             Atom* pLastAtom = NULL;
293 
294             while( (mrStream.GetError() == 0 ) && ( mrStream.Tell() < maRecordHeader.GetRecEndFilePos() ) )
295             {
296                 mrStream >> aChildHeader;
297 
298                 if( mrStream.GetError() == 0 )
299                 {
300                     Atom* pAtom = new Atom( aChildHeader, mrStream );
301 
302                     if( pLastAtom )
303                         pLastAtom->mpNextAtom = pAtom;
304                     if( mpFirstChild == NULL )
305                         mpFirstChild = pAtom;
306 
307                     pLastAtom = pAtom;
308                 }
309             }
310         }
311     }
312 
313     maRecordHeader.SeekToEndOfRecord( mrStream );
314 }
315 
~Atom()316 Atom::~Atom()
317 {
318     Atom* pChild = mpFirstChild;
319     while( pChild )
320     {
321         Atom* pNextChild = pChild->mpNextAtom;
322         delete pChild;
323         pChild = pNextChild;
324     }
325 }
326 
327 /** imports this atom and its child atoms */
import(const DffRecordHeader & rRootRecordHeader,SvStream & rStCtrl)328 Atom* Atom::import( const DffRecordHeader& rRootRecordHeader, SvStream& rStCtrl )
329 {
330     Atom* pRootAtom = new Atom( rRootRecordHeader, rStCtrl );
331 
332     if( rStCtrl.GetError() == 0 )
333     {
334         return pRootAtom;
335     }
336     else
337     {
338         delete pRootAtom;
339         return NULL;
340     }
341 }
342 
343 /** imports this atom and its child atoms */
import(UINT16 nRecType,SvStream & rStCtrl)344 Atom* Atom::import( UINT16 nRecType, SvStream& rStCtrl )
345 {
346     rStCtrl.Seek( STREAM_SEEK_TO_END );
347     sal_Size nStreamLength = rStCtrl.Tell();
348     rStCtrl.Seek( STREAM_SEEK_TO_BEGIN );
349 
350     DffRecordHeader aRootRecordHeader;
351     aRootRecordHeader.nRecVer = DFF_PSFLAG_CONTAINER;
352     aRootRecordHeader.nRecInstance = 0;
353     aRootRecordHeader.nImpVerInst = 0;
354     aRootRecordHeader.nRecType = nRecType;
355     aRootRecordHeader.nRecLen = nStreamLength;
356     aRootRecordHeader.nFilePos = 0;
357 
358     return import( aRootRecordHeader, rStCtrl );
359 }
360 
361 /** returns the next child atom after pLast with nRecType or NULL */
findNextChildAtom(sal_uInt16 nRecType,const Atom * pLast) const362 const Atom* Atom::findNextChildAtom( sal_uInt16 nRecType, const Atom* pLast ) const
363 {
364     Atom* pChild = pLast != NULL ? pLast->mpNextAtom : mpFirstChild;
365     while( pChild && pChild->maRecordHeader.nRecType != nRecType )
366     {
367         pChild = pChild->mpNextAtom;
368     }
369 
370     return pChild;
371 }
372 
373 /** returns the next child atom after pLast with nRecType and nRecInstance or NULL */
findNextChildAtom(sal_uInt16 nRecType,sal_uInt16 nRecInstance,const Atom * pLast) const374 const Atom* Atom::findNextChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance, const Atom* pLast ) const
375 {
376     const Atom* pChild = pLast != NULL ? pLast->mpNextAtom : mpFirstChild;
377     while( pChild && (pChild->maRecordHeader.nRecType != nRecType) && (pChild->maRecordHeader.nRecInstance != nRecInstance) )
378     {
379         pChild = findNextChildAtom( pChild );
380     }
381 
382     return pChild;
383 }
384 
findFirstEqualAtom(Atom * pCompare,Atom * pContainer,Atom * pSearch,int & nDistance)385 Atom* Atom::findFirstEqualAtom( Atom* pCompare, Atom* pContainer, Atom* pSearch, int& nDistance )
386 {
387     nDistance = 0;
388     Atom* pRet = 0;
389 
390     while( pSearch )
391     {
392         if( *pSearch == *pCompare )
393             return pSearch;
394 
395         pSearch = const_cast< Atom* >( pContainer->findNextChildAtom( pSearch ) );
396         nDistance++;
397     }
398 
399     return 0;
400 }
401 
skipAtoms(Atom * pContainer,Atom * pAtom,Atom * pSkipTo)402 Atom* Atom::skipAtoms( Atom* pContainer, Atom* pAtom, Atom* pSkipTo )
403 {
404     while( pAtom && (pAtom != pSkipTo) )
405     {
406         pAtom->meStatus = CMP_NOTAVAILABLE;
407         pAtom = const_cast< Atom* >( pContainer->findNextChildAtom( pAtom ) );
408     }
409 
410     return pAtom;
411 }
412 
compare(Atom * pAtom)413 void Atom::compare( Atom* pAtom )
414 {
415     if( pAtom )
416     {
417         if( meStatus == CMP_NOTYET )
418         {
419             mpCompareAtom = pAtom;
420             pAtom->mpCompareAtom = this;
421 
422             mpCompareAtom = pAtom;
423             pAtom->mpCompareAtom = this;
424 
425             meStatus = pAtom->meStatus = ( *this == *pAtom ) ? CMP_EQUAL : CMP_NOTEQUAL;
426         }
427 
428         if(meStatus == CMP_EQUAL)
429         {
430             if( isContainer() )
431             {
432                 /** returns the first child atom or NULL */
433                 Atom* pChildAtom1 = const_cast< Atom* >( findFirstChildAtom() );
434 
435                 if( pChildAtom1 && (pChildAtom1->meStatus == CMP_NOTYET) )
436                 {
437                     Atom* pChildAtom2 = const_cast< Atom* >( pAtom->findFirstChildAtom() );
438                     while( pChildAtom1 && pChildAtom2 )
439                     {
440                         if( !(*pChildAtom1 == *pChildAtom2) )
441                         {
442                             int nDistance1;
443                             int nDistance2;
444 
445                             Atom* pFind1 = findFirstEqualAtom( pChildAtom1, pAtom, const_cast< Atom* >( pAtom->findNextChildAtom( pChildAtom2 )), nDistance1 );
446                             Atom* pFind2 = findFirstEqualAtom( pChildAtom2, this, const_cast< Atom* >(findNextChildAtom( pChildAtom1 )), nDistance2 );
447 
448                             if( pFind1 && (!pFind2 || (nDistance1 < nDistance2) ) )
449                             {
450                                 pChildAtom2 = skipAtoms( pAtom, pChildAtom2, pFind1 );
451                             }
452                             else if( pFind2 )
453                             {
454                                 pChildAtom1 = skipAtoms( this, pChildAtom1, pFind2 );
455                             }
456                             else
457                             {
458                                 pChildAtom1 = skipAtoms( this, pChildAtom1, 0 );
459                                 pChildAtom2 = skipAtoms( pAtom, pChildAtom2, 0 );
460                             }
461                         }
462 
463                         if( pChildAtom1 && pChildAtom2 )
464                         {
465                             pChildAtom1->mpCompareAtom = pChildAtom2;
466                             pChildAtom2->mpCompareAtom = pChildAtom1;
467 
468                             pChildAtom1->meStatus = pChildAtom2->meStatus =
469                                 (pChildAtom1->isContainer() || pChildAtom1->compareContent( *pChildAtom2 )) ?
470                                     CMP_EQUAL : CMP_NOTEQUAL;
471 
472                             pChildAtom1 = const_cast< Atom* >( findNextChildAtom( pChildAtom1 ) );
473                             pChildAtom2 = const_cast< Atom* >( pAtom->findNextChildAtom( pChildAtom2 ) );
474                         }
475                     }
476                 }
477             }
478             else
479             {
480                 if( !compareContent( *pAtom ) )
481                 {
482                     meStatus = pAtom->meStatus = CMP_NOTEQUAL;
483                 }
484             }
485         }
486     }
487 }
488 
489 //////////////////////////////////////////////////////////////////////
490 
491 //////////////////////////////////////////////////////////////////////
492 
493 class AtomBoxString : public SvLBoxString
494 {
495 public:
AtomBoxString(SvLBoxEntry * pEntry,const String & rStr)496     AtomBoxString( SvLBoxEntry* pEntry, const String& rStr )
497         : SvLBoxString( pEntry, 0, rStr )
498     { }
499 
~AtomBoxString()500     ~AtomBoxString() { }
501 
Paint(const Point & rPos,SvLBox & rOutDev,USHORT nViewDataEntryFlags,SvLBoxEntry * pEntry)502     void Paint( const Point& rPos, SvLBox& rOutDev, USHORT nViewDataEntryFlags, SvLBoxEntry* pEntry )
503     {
504         Color aOldTextColor = rOutDev.GetTextColor();
505 
506         if( pEntry && pEntry->GetUserData() )
507         {
508             Atom* pAtom = static_cast<Atom*>( pEntry->GetUserData() );
509             rOutDev.SetTextColor( Color( gColors[ pAtom->getCompareStatus() ] ) );
510         }
511 
512         SvLBoxString::Paint( rPos, rOutDev, nViewDataEntryFlags, pEntry );
513 
514         rOutDev.SetTextColor( aOldTextColor );
515 
516 /*
517         Color aOldFillColor = rOutDev.GetFillColor();
518 
519         SvTreeListBox* pTreeBox = static_cast< SvTreeListBox* >( &rOutDev );
520         long nX = pTreeBox->GetSizePixel().Width();
521 
522         ScrollBar* pVScroll = pTreeBox->GetVScroll();
523         if ( pVScroll->IsVisible() )
524         {
525             nX -= pVScroll->GetSizePixel().Width();
526         }
527 
528         SvViewDataItem* pItem = rOutDev.GetViewDataItem( pEntry, this );
529         nX -= pItem->aSize.Height();
530 
531         long nSize = pItem->aSize.Height() / 2;
532         long nHalfSize = nSize / 2;
533         long nY = rPos.Y() + nHalfSize;
534 
535         if ( aOldFillColor == COL_WHITE )
536         {
537             rOutDev.SetFillColor( Color( COL_BLACK ) );
538         }
539         else
540         {
541             rOutDev.SetFillColor( Color( COL_WHITE ) );
542         }
543 
544         long n = 0;
545         while ( n <= nHalfSize )
546         {
547             rOutDev.DrawRect( Rectangle( nX+n, nY+n, nX+n, nY+nSize-n ) );
548             n++;
549         }
550 
551         rOutDev.SetFillColor( aOldFillColor );
552 */
553     }
554 
555 private:
556     Image* mpImage;
557 };
558 
559 
560 //////////////////////////////////////////////////////////////////////
561 
562 class AtomContainerTreeListBox : public SvTreeListBox
563 {
564 public:
565     AtomContainerTreeListBox( Window* pParent );
566     ~AtomContainerTreeListBox();
567 
568     void SetRootAtom( const Atom* pAtom );
569 
570 
SetCollapsingHdl(const Link & rNewHdl)571     void            SetCollapsingHdl(const Link& rNewHdl){maCollapsingHdl=rNewHdl;}
GetCollapsingHdl() const572     const Link&     GetCollapsingHdl() const { return maCollapsingHdl; }
573 
SetExpandingHdl(const Link & rNewHdl)574     void            SetExpandingHdl(const Link& rNewHdl){maExpandingHdl=rNewHdl;}
GetExpandingHdl() const575     const Link&     GetExpandingHdl() const { return maExpandingHdl; }
576 
577     virtual BOOL    Expand( SvLBoxEntry* pParent );
578     virtual BOOL    Collapse( SvLBoxEntry* pParent );
579 
580     SvLBoxEntry*    findAtom( Atom* pAtom );
581 
582     virtual void InitEntry(SvLBoxEntry*,const XubString&,const Image&,const Image&);
583     virtual void SetTabs();
584 
585 private:
586     void InsertAtom( const Atom* pAtom, SvLBoxEntry* pParent = 0 );
587     const Atom* mpRootAtom;
588     ResMgr* mpResMgr;
589     Image maImgFolder;
590     Image maImgAtom;
591     Image maImgExpanded;
592     Image maImgCollapsed;
593     bool mbRecursiveGuard;
594     Link maCollapsingHdl;
595     Link maExpandingHdl;
596 };
597 
598 typedef std::pair< AtomContainerTreeListBox*, SvLBoxEntry* > AtomContainerEntryPair;
599 
AtomContainerTreeListBox(Window * pParent)600 AtomContainerTreeListBox::AtomContainerTreeListBox( Window* pParent )
601 : SvTreeListBox( pParent, WB_HASBUTTONS|WB_HASLINES|WB_HASBUTTONSATROOT|WB_3DLOOK|WB_BORDER ),
602     mpRootAtom( 0 ), mbRecursiveGuard( false )
603 {
604     mpResMgr = ResMgr::CreateResMgr( "svt" );
605     maImgCollapsed = Image( ResId( RID_IMG_TREENODE_COLLAPSED, mpResMgr ) );
606     maImgExpanded = Image( ResId( RID_IMG_TREENODE_EXPANDED, mpResMgr ) );
607 
608 //  SetDefaultExpandedEntryBmp( aExpanded );
609 //  SetDefaultCollapsedEntryBmp(aCollapsed );
610 
611     maImgFolder = Image( ResId( IMG_SVT_FOLDER, mpResMgr ) );
612     maImgAtom = Image( ResId( IMG_SVT_DOCTEMPLATE_DOCINFO_SMALL, mpResMgr ) );
613 }
614 
~AtomContainerTreeListBox()615 AtomContainerTreeListBox::~AtomContainerTreeListBox()
616 {
617 }
618 
SetTabs()619 void AtomContainerTreeListBox::SetTabs()
620 {
621     if( IsEditingActive() )
622         EndEditing( TRUE );
623 
624     ClearTabList();
625 
626     short nIndent = 0; GetIndent();
627     long nNodeWidthPixel = maImgCollapsed.GetSizePixel().Width();
628     long nContextWidthDIV2 = nNodeWidthPixel >> 1;
629 
630     long nStartPos = 2 + ( nIndent + nContextWidthDIV2 );
631     AddTab( nStartPos, SV_LBOXTAB_DYNAMIC | SV_LBOXTAB_ADJUST_CENTER );
632     nStartPos += nNodeWidthPixel + 5;
633     AddTab( nStartPos, SV_LBOXTAB_DYNAMIC | SV_LBOXTAB_ADJUST_CENTER | SV_LBOXTAB_SHOW_SELECTION );
634     nStartPos += nContextWidthDIV2 + 5;
635     AddTab( nStartPos, SV_LBOXTAB_DYNAMIC|SV_LBOXTAB_ADJUST_LEFT | SV_LBOXTAB_SHOW_SELECTION );
636 }
637 
InitEntry(SvLBoxEntry * pEntry,const XubString & aStr,const Image & aCollEntryBmp,const Image & aExpEntryBmp)638 void AtomContainerTreeListBox::InitEntry(SvLBoxEntry* pEntry,const XubString& aStr,const Image& aCollEntryBmp,const Image& aExpEntryBmp)
639 {
640     pEntry->AddItem( new SvLBoxContextBmp( pEntry,0, aCollEntryBmp,aExpEntryBmp, SVLISTENTRYFLAG_EXPANDED ) );
641     pEntry->AddItem( new SvLBoxContextBmp( pEntry,0, maImgAtom, maImgAtom, SVLISTENTRYFLAG_EXPANDED ) );
642     pEntry->AddItem( new AtomBoxString( pEntry, aStr ) );
643 }
644 
findAtom(Atom * pAtom)645 SvLBoxEntry* AtomContainerTreeListBox::findAtom( Atom* pAtom )
646 {
647     SvLBoxEntry* pEntry = First();
648     while( pEntry )
649     {
650         if( pEntry->GetUserData() == pAtom )
651             return pEntry;
652 
653         pEntry = Next( pEntry );
654     }
655 
656     return 0;
657 }
658 
Expand(SvLBoxEntry * pParent)659 BOOL AtomContainerTreeListBox::Expand( SvLBoxEntry* pParent )
660 {
661     BOOL bRet = FALSE;
662     if( !mbRecursiveGuard )
663     {
664         mbRecursiveGuard = true;
665         AtomContainerEntryPair aPair( this, pParent );
666         maExpandingHdl.Call( &aPair);
667 
668         bRet = SvTreeListBox::Expand( pParent );
669         mbRecursiveGuard = false;
670     }
671     return bRet;
672 }
673 
Collapse(SvLBoxEntry * pParent)674 BOOL AtomContainerTreeListBox::Collapse( SvLBoxEntry* pParent )
675 {
676     BOOL bRet = FALSE;
677     if( !mbRecursiveGuard )
678     {
679         mbRecursiveGuard = true;
680         AtomContainerEntryPair aPair( this, pParent );
681         maCollapsingHdl.Call( &aPair);
682 
683         bRet = SvTreeListBox::Collapse( pParent );
684         mbRecursiveGuard = false;
685     }
686     return bRet;
687 }
688 
SetRootAtom(const Atom * pAtom)689 void AtomContainerTreeListBox::SetRootAtom( const Atom* pAtom )
690 {
691     mpRootAtom = pAtom;
692     InsertAtom( mpRootAtom );
693 }
694 
InsertAtom(const Atom * pAtom,SvLBoxEntry * pParent)695 void AtomContainerTreeListBox::InsertAtom( const Atom* pAtom, SvLBoxEntry* pParent /* = 0 */ )
696 {
697     if( pAtom )
698     {
699         const DffRecordHeader& rHeader = pAtom->getHeader();
700 
701         char buffer[1024];
702 
703         rtl::OUString aText;
704         AtomConfig* pAtomConfig = dynamic_cast< AtomConfig*>( gAtomConfigMap[rHeader.nRecType].get() );
705 
706         if( pAtomConfig )
707             aText = pAtomConfig->getName();
708 
709         if( !aText.getLength() )
710         {
711             sprintf( buffer, "unknown_0x%04x", rHeader.nRecType );
712             aText += rtl::OUString::createFromAscii( buffer );
713         }
714 
715         sprintf( buffer, " (I: %lu L: %lu)", (UINT32)rHeader.nRecVer, (UINT32)rHeader.nRecLen );
716         aText += String( rtl::OUString::createFromAscii( buffer ) );
717 
718         SvLBoxEntry* pEntry = 0;
719         if( pAtom->isContainer() && pAtom->findFirstChildAtom() )
720         {
721             pEntry = InsertEntry( aText, maImgExpanded, maImgCollapsed, pParent );
722 
723             /** returns the first child atom or NULL */
724             const Atom* pChildAtom = pAtom->findFirstChildAtom();
725 
726             while( pChildAtom )
727             {
728                 InsertAtom( pChildAtom, pEntry );
729                 pChildAtom = pAtom->findNextChildAtom( pChildAtom );
730             }
731         }
732         else
733         {
734             pEntry = InsertEntry( aText, pParent );
735         }
736 
737         if( pEntry )
738         {
739             pEntry->SetUserData( (void*)pAtom );
740 
741             if( pAtom->isContainer() )
742             {
743                 SvLBoxContextBmp* pBoxBmp = dynamic_cast< SvLBoxContextBmp* >( pEntry->GetItem( pEntry->ItemCount() - 2 ) );
744                 if( pBoxBmp )
745                 {
746                     pBoxBmp->SetBitmap1( pEntry, maImgFolder );
747                     pBoxBmp->SetBitmap2( pEntry, maImgFolder );
748                 }
749             }
750 
751 /*
752             pEntry->ReplaceItem(
753                 new AtomBoxString( pEntry, aText, pImage ),
754                 pEntry->ItemCount() - 1 );
755 */
756         }
757     }
758 }
759 
760 ///////////////////////////////////////////////////////////////////////
761 
762 extern void load_config( const OUString& rPath );
763 
764 class PPTDocument
765 {
766 public:
767     PPTDocument( const rtl::OUString& rFilePath );
768     ~PPTDocument();
769 
770     Atom* getRootAtom() const;
771 
772 private:
773     void Load( const rtl::OUString& rFilePath );
774 
775     Atom* mpAtom;
776     SvStream* mpDocStream;
777     SotStorageRef maStorage;
778 };
779 
780 typedef boost::shared_ptr< PPTDocument > PPTDocumentPtr;
781 
PPTDocument(const rtl::OUString & rFilePath)782 PPTDocument::PPTDocument(const rtl::OUString& rFilePath)
783 : mpAtom(0), mpDocStream(0)
784 {
785     Load( rFilePath );
786 }
787 
~PPTDocument()788 PPTDocument::~PPTDocument()
789 {
790     delete mpAtom;
791     delete mpDocStream;
792 }
793 
Load(const rtl::OUString & rFilePath)794 void PPTDocument::Load( const rtl::OUString& rFilePath )
795 {
796     maStorage = new SotStorage( rFilePath, STREAM_STD_READ );
797     if( !maStorage->GetError() )
798     {
799         mpDocStream = maStorage->OpenSotStream( String( RTL_CONSTASCII_USTRINGPARAM("PowerPoint Document") ), STREAM_STD_READ );
800         if( mpDocStream )
801         {
802             DffRecordHeader aRecordHeader;
803             *mpDocStream >> aRecordHeader;
804 
805             mpAtom = Atom::import( 65530, *mpDocStream );
806         }
807     }
808 }
809 
getRootAtom() const810 Atom* PPTDocument::getRootAtom() const
811 {
812     return mpAtom;
813 }
814 
815 ///////////////////////////////////////////////////////////////////////
816 
817 class MSViewerWorkWindow : public WorkWindow
818 {
819 public:
820     MSViewerWorkWindow();
821     ~MSViewerWorkWindow();
822 
823     PPTDocumentPtr Load();
824     void onView();
825     void onCompare();
826     void onClose();
827 
828     void View( const PPTDocumentPtr& pDocument, int nPane );
829     void Compare( const PPTDocumentPtr& pDocument1, const PPTDocumentPtr& pDocument2 );
830 
831     virtual void Resize();
832 
833 private:
834     void Sync( AtomContainerEntryPair* pPair, int nAction );
835 
836     AtomContainerTreeListBox*   mpListBox[2];
837     MultiLineEdit*              mpEdit[2];
838     PPTDocumentPtr              mpDocument[2];
839     MenuBar*                    mpMenuBar;
840     PopupMenu*                  mpFileMenu;
841     bool mbSelectHdlGuard;
842     DECL_LINK( implSelectHdl, AtomContainerTreeListBox* );
843     DECL_LINK( implExpandingHdl, AtomContainerEntryPair* );
844     DECL_LINK( implCollapsingHdl, AtomContainerEntryPair* );
845     DECL_LINK( implMenuHdl, Menu* );
846 };
847 
848 // -----------------------------------------------------------------------
849 
onView()850 void MSViewerWorkWindow::onView()
851 {
852     PPTDocumentPtr pDocument( Load() );
853     if( pDocument.get() )
854     {
855         onClose();
856         View( pDocument, 0 );
857     }
858 }
859 
onClose()860 void MSViewerWorkWindow::onClose()
861 {
862 }
863 
onCompare()864 void MSViewerWorkWindow::onCompare()
865 {
866     PPTDocumentPtr pDocument1( Load() );
867     if( pDocument1.get() )
868     {
869         PPTDocumentPtr pDocument2( Load() );
870         if( pDocument2.get() )
871         {
872             onClose();
873             Compare( pDocument1, pDocument2 );
874         }
875     }
876 }
877 
Compare(const PPTDocumentPtr & pDocument1,const PPTDocumentPtr & pDocument2)878 void MSViewerWorkWindow::Compare( const PPTDocumentPtr& pDocument1, const PPTDocumentPtr& pDocument2 )
879 {
880     if( pDocument1.get() && pDocument2.get() )
881     {
882         Atom* pAtom1 = pDocument1->getRootAtom();
883         Atom* pAtom2 = pDocument2->getRootAtom();
884         pAtom1->setCompareAtom( pAtom2 );
885         pAtom2->setCompareAtom( pAtom1 );
886     }
887 
888     View( pDocument1, 0 );
889     View( pDocument2, 1 );
890 }
891 
View(const PPTDocumentPtr & pDocument,int nPane)892 void MSViewerWorkWindow::View( const PPTDocumentPtr& pDocument, int nPane )
893 {
894     if( ((nPane != 0) && (nPane != 1)) || (pDocument.get() == 0) )
895         return;
896 
897     mpDocument[nPane] = pDocument;
898 
899     mpListBox[nPane]->SetRootAtom( pDocument->getRootAtom() );
900     mpListBox[nPane]->Expand( mpListBox[nPane]->GetEntry(0) );
901     mpListBox[nPane]->Show();
902     mpEdit[nPane]->Show();
903     Resize();
904 }
905 
906 
Load()907 PPTDocumentPtr MSViewerWorkWindow::Load()
908 {
909     ::sfx2::FileDialogHelper aDlg( ::sfx2::FILEOPEN_SIMPLE, 0 );
910     String aStrFilterType( RTL_CONSTASCII_USTRINGPARAM( "*.ppt" ) );
911     aDlg.AddFilter( aStrFilterType, aStrFilterType );
912 //  INetURLObject aFile( SvtPathOptions().GetPalettePath() );
913 //  aDlg.SetDisplayDirectory( aFile.GetMainURL( INetURLObject::NO_DECODE ) );
914 
915     PPTDocumentPtr pDocument;
916     if ( aDlg.Execute() == ERRCODE_NONE )
917     {
918         pDocument.reset( new PPTDocument( aDlg.GetPath() ) );
919     }
920 
921     return pDocument;
922 }
923 
924 // -----------------------------------------------------------------------
925 
MSViewerWorkWindow()926 MSViewerWorkWindow::MSViewerWorkWindow() :
927     WorkWindow( 0, WB_APP | WB_STDWORK | WB_3DLOOK ),mbSelectHdlGuard(false)
928 {
929     Size aOutputSize( 400, 600 );
930     SetOutputSizePixel( aOutputSize );
931     SetText( String( RTL_CONSTASCII_USTRINGPARAM( "MSViewer" ) ) );
932 
933     Size aOutSize( GetOutputSizePixel() );
934 
935     Font aFont( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ), GetFont().GetSize() );
936 
937     mpMenuBar = new MenuBar();
938     mpMenuBar->InsertItem( 1, String( RTL_CONSTASCII_USTRINGPARAM("~File" ) ) );
939     mpFileMenu = new PopupMenu();
940     mpFileMenu->InsertItem( 2, String( RTL_CONSTASCII_USTRINGPARAM("~View" ) ) );
941     mpFileMenu->InsertItem( 3, String( RTL_CONSTASCII_USTRINGPARAM("~Compare" ) ) );
942     mpFileMenu->InsertSeparator();
943     mpFileMenu->InsertItem( 4, String( RTL_CONSTASCII_USTRINGPARAM("~Quit" ) ) );
944     mpFileMenu->SetSelectHdl( LINK( this, MSViewerWorkWindow, implMenuHdl ) );
945 
946     mpMenuBar->SetPopupMenu( 1, mpFileMenu );
947     SetMenuBar( mpMenuBar );
948     int nPane;
949     for( nPane = 0; nPane < 2; nPane++ )
950     {
951         mpListBox[nPane] = new AtomContainerTreeListBox( this );
952         mpListBox[nPane]->SetSelectHdl( LINK( this, MSViewerWorkWindow, implSelectHdl ) );
953         mpListBox[nPane]->SetExpandingHdl( LINK( this, MSViewerWorkWindow, implExpandingHdl ) );
954         mpListBox[nPane]->SetCollapsingHdl( LINK( this, MSViewerWorkWindow, implCollapsingHdl ) );
955 
956         mpEdit[nPane] = new MultiLineEdit(this, WB_3DLOOK | WB_BORDER | WB_LEFT | WB_TOP | WB_READONLY | WB_HSCROLL | WB_VSCROLL );
957         mpEdit[nPane]->SetReadOnly( TRUE );
958         mpEdit[nPane]->SetReadOnly( TRUE );
959         mpEdit[nPane]->SetControlFont( aFont );
960     }
961 }
962 
963 // -----------------------------------------------------------------------
964 
GetAtomText(const Atom * pAtom)965 static String GetAtomText( const Atom* pAtom )
966 {
967     String aText;
968     if( pAtom )
969     {
970         const DffRecordHeader& rHeader = pAtom->getHeader();
971         char buffer[512];
972         sprintf( buffer, "Version = %lu\n\rInstance = %lu\n\rVersionInstance = %lu\n\rLength = %lu\n\r",
973         (UINT32)rHeader.nRecVer,
974         (UINT32)rHeader.nRecInstance,
975         (UINT32)rHeader.nImpVerInst,
976         (UINT32)rHeader.nRecLen );
977         aText = rtl::OUString::createFromAscii( buffer );
978         if( pAtom->isContainer() )
979         {
980 
981         }
982         else
983         {
984             pAtom->seekToContent();
985             AtomConfig* pAtomConfig = dynamic_cast< AtomConfig* >( gAtomConfigMap[pAtom->getType()].get() );
986             if( pAtomConfig )
987             {
988                 sal_Size nLength = pAtom->getLength();
989                 aText += String( pAtomConfig->format( pAtom->getStream(), nLength ) );
990             }
991             else
992             {
993                 sal_Size nLength = pAtom->getLength();
994                 aText += String( ElementConfig::dump_hex( pAtom->getStream(), nLength ) );
995             }
996         }
997     }
998 
999     return aText;
1000 }
1001 
IMPL_LINK(MSViewerWorkWindow,implSelectHdl,AtomContainerTreeListBox *,pListBox)1002 IMPL_LINK(MSViewerWorkWindow,implSelectHdl, AtomContainerTreeListBox*, pListBox )
1003 {
1004     int nPane = (pListBox == mpListBox[1]) ? 1 : 0;
1005     SvLBoxEntry* pEntry = mpListBox[nPane]->FirstSelected();
1006     if( pEntry && pEntry->GetUserData() )
1007     {
1008         Atom* pAtom = static_cast<Atom*>( pEntry->GetUserData() );
1009         mpEdit[nPane]->SetText( GetAtomText( pAtom ) );
1010 
1011         if(!mbSelectHdlGuard)
1012         {
1013             mbSelectHdlGuard = true;
1014             // select other
1015             AtomContainerEntryPair aPair( pListBox, pEntry );
1016             Sync( &aPair, 2 );
1017             mbSelectHdlGuard = false;
1018         }
1019     }
1020     return 0;
1021 }
1022 
Sync(AtomContainerEntryPair * pPair,int nAction)1023 void MSViewerWorkWindow::Sync( AtomContainerEntryPair* pPair, int nAction )
1024 {
1025     if( mpDocument[0].get() && mpDocument[1].get() && pPair->first && pPair->second )
1026     {
1027         AtomContainerTreeListBox* pDestinationListBox = (pPair->first == mpListBox[0]) ? mpListBox[1] : mpListBox[0];
1028 
1029         Atom* pAtom = static_cast<Atom*>(pPair->second->GetUserData());
1030         if( pAtom && pAtom->getCompareAtom() )
1031         {
1032             SvLBoxEntry* pEntry = pDestinationListBox->findAtom( pAtom->getCompareAtom() );
1033 
1034             if(pEntry )
1035             {
1036                 if( nAction == 0 )
1037                 {
1038                     pDestinationListBox->Expand( pEntry );
1039                 }
1040                 else if( nAction == 1 )
1041                 {
1042                     pDestinationListBox->Collapse( pEntry );
1043                 }
1044                 else
1045                 {
1046                     pDestinationListBox->Select( pEntry );
1047                 }
1048             }
1049         }
1050     }
1051 }
1052 
IMPL_LINK(MSViewerWorkWindow,implExpandingHdl,AtomContainerEntryPair *,pPair)1053 IMPL_LINK(MSViewerWorkWindow, implExpandingHdl, AtomContainerEntryPair*, pPair )
1054 {
1055     SvLBoxEntry* pEntry = pPair->second;
1056     if( pEntry && pEntry->GetUserData() )
1057     {
1058         Atom* pAtom = static_cast<Atom*>( pEntry->GetUserData() );
1059         pAtom->compare( pAtom->getCompareAtom() );
1060     }
1061 
1062     Sync( pPair, 0 );
1063 
1064     return 0;
1065 }
1066 
IMPL_LINK(MSViewerWorkWindow,implCollapsingHdl,AtomContainerEntryPair *,pPair)1067 IMPL_LINK(MSViewerWorkWindow, implCollapsingHdl, AtomContainerEntryPair*, pPair )
1068 {
1069     Sync( pPair, 1 );
1070 
1071     return 0;
1072 }
1073 
IMPL_LINK(MSViewerWorkWindow,implMenuHdl,Menu *,pMenu)1074 IMPL_LINK( MSViewerWorkWindow, implMenuHdl, Menu*, pMenu )
1075 {
1076     if( pMenu )
1077     {
1078         USHORT nId = pMenu->GetCurItemId();
1079         switch( nId )
1080         {
1081         case 2: onView(); break;
1082         case 3: onCompare(); break;
1083         case 4: Application::Quit(); break;
1084         }
1085     }
1086     return 0;
1087 }
1088 
1089 // -----------------------------------------------------------------------
1090 
~MSViewerWorkWindow()1091 MSViewerWorkWindow::~MSViewerWorkWindow()
1092 {
1093     int nPane;
1094     for( nPane = 0; nPane < 2; nPane++ )
1095     {
1096         delete mpListBox[nPane];
1097         delete mpEdit[nPane];
1098     }
1099 
1100     delete mpFileMenu;
1101     delete mpMenuBar;
1102 }
1103 
1104 // -----------------------------------------------------------------------
1105 
Resize()1106 void MSViewerWorkWindow::Resize()
1107 {
1108     int nPaneCount = ((mpDocument[0].get() != 0) ? 1 : 0) + ((mpDocument[1].get() != 0) ? 1 : 0);
1109 
1110     Size aOutputSize( GetOutputSizePixel() );
1111     int nHeight = aOutputSize.Height() >> 1;
1112     if( nPaneCount )
1113     {
1114         int nWidth = aOutputSize.Width();
1115         if( nPaneCount == 2 )
1116             nWidth >>= 1;
1117 
1118         int nPosX = 0;
1119 
1120         int nPane;
1121         for( nPane = 0; nPane < 2; nPane++ )
1122         {
1123             mpListBox[nPane]->SetPosSizePixel( nPosX,0, nWidth, nHeight );
1124             mpEdit[nPane]->SetPosSizePixel( nPosX, nHeight, nWidth, aOutputSize.Height() - nHeight );
1125             nPosX += nWidth;
1126         }
1127     }
1128 }
1129 
1130 // -----------------------------------------------------------------------
1131 
1132 // -----------------------------------------------------------------------
1133 
SAL_IMPLEMENT_MAIN()1134     SAL_IMPLEMENT_MAIN()
1135 {
1136     if( argc > 3 )
1137         return 0;
1138 
1139     uno::Reference< lang::XMultiServiceFactory > xMSF;
1140     try
1141     {
1142         uno::Reference< uno::XComponentContext > xCtx( cppu::defaultBootstrap_InitialComponentContext() );
1143         if ( !xCtx.is() )
1144         {
1145             DBG_ERROR( "Error creating initial component context!" );
1146             return -1;
1147         }
1148 
1149         xMSF = uno::Reference< lang::XMultiServiceFactory >(xCtx->getServiceManager(), uno::UNO_QUERY );
1150 
1151         if ( !xMSF.is() )
1152         {
1153             DBG_ERROR( "No service manager!" );
1154             return -1;
1155         }
1156 
1157         // Init UCB
1158         uno::Sequence< uno::Any > aArgs( 2 );
1159         aArgs[ 0 ] <<= rtl::OUString::createFromAscii( UCB_CONFIGURATION_KEY1_LOCAL );
1160         aArgs[ 1 ] <<= rtl::OUString::createFromAscii( UCB_CONFIGURATION_KEY2_OFFICE );
1161         sal_Bool bSuccess = ::ucb::ContentBroker::initialize( xMSF, aArgs );
1162         if ( !bSuccess )
1163         {
1164             DBG_ERROR( "Error creating UCB!" );
1165             return -1;
1166         }
1167 
1168     }
1169     catch ( uno::Exception const & )
1170     {
1171         DBG_ERROR( "Exception during creation of initial component context!" );
1172         return -1;
1173     }
1174     comphelper::setProcessServiceFactory( xMSF );
1175 
1176     InitVCL( xMSF );
1177 
1178     String aConfigURL;
1179     if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( Application::GetAppFileName(), aConfigURL ) )
1180     {
1181         INetURLObject aURL( aConfigURL );
1182 
1183         aURL.removeSegment();
1184         aURL.removeFinalSlash();
1185         aURL.Append( String(  RTL_CONSTASCII_USTRINGPARAM( "msview.xml" )  ) );
1186 
1187         load_config( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
1188     }
1189 
1190     {
1191         MSViewerWorkWindow aMainWindow;
1192 
1193         if( argc >= 2 )
1194         {
1195             const rtl::OUString aFile1( rtl::OUString::createFromAscii(argv[1]) );
1196             PPTDocumentPtr pDocument1( new PPTDocument(  aFile1 ) );
1197 
1198             if( argc == 3 )
1199             {
1200                 const rtl::OUString aFile2( rtl::OUString::createFromAscii(argv[2]) );
1201 
1202                 PPTDocumentPtr pDocument2;
1203                 pDocument2.reset( new PPTDocument( aFile2 ) );
1204                 aMainWindow.Compare( pDocument1, pDocument2 );
1205             }
1206             else
1207             {
1208                 aMainWindow.View( pDocument1, 0 );
1209             }
1210         }
1211 
1212         aMainWindow.Show();
1213 
1214         Application::Execute();
1215     }
1216 
1217     DeInitVCL();
1218 
1219     return 0;
1220 }
1221