xref: /aoo41x/main/svx/workben/msview/msview.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_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