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