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 136 SvStream& getStream() const { return mrStream; } 137 138 bool operator==( const Atom& rAtom ) const; 139 140 CompareStatus getCompareStatus() const { return meStatus; } 141 142 void compare( Atom* pAtom ); 143 bool compareContent( Atom& rAtom ); 144 145 Atom* getCompareAtom() const { return mpCompareAtom; } 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 164 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 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 207 inline bool Atom::hasChildAtom( sal_uInt16 nRecType ) const 208 { 209 return findFirstChildAtom( nRecType ) != NULL; 210 } 211 212 inline bool Atom::hasChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance ) const 213 { 214 return findFirstChildAtom( nRecType, nRecInstance ) != NULL; 215 } 216 217 inline const Atom* Atom::findFirstChildAtom( sal_uInt16 nRecType ) const 218 { 219 return findNextChildAtom( nRecType, NULL ); 220 } 221 222 inline const DffRecordHeader& Atom::getHeader() const 223 { 224 return maRecordHeader; 225 } 226 227 inline const Atom* Atom::findFirstChildAtom( sal_uInt16 nRecType, sal_uInt16 nRecInstance ) const 228 { 229 return findNextChildAtom( nRecType, nRecInstance, NULL ); 230 } 231 232 inline const Atom* Atom::findFirstChildAtom() const 233 { 234 return mpFirstChild; 235 } 236 237 inline const Atom* Atom::findNextChildAtom( const Atom* pLast ) const 238 { 239 return pLast ? pLast->mpNextAtom : pLast; 240 } 241 242 inline bool Atom::isContainer() const 243 { 244 return (bool)maRecordHeader.IsContainer(); 245 } 246 247 inline bool Atom::seekToContent() const 248 { 249 maRecordHeader.SeekToContent( mrStream ); 250 return mrStream.GetError() == 0; 251 } 252 253 inline sal_uInt16 Atom::getType() const 254 { 255 return maRecordHeader.nRecType; 256 } 257 258 inline sal_uInt16 Atom::getInstance() const 259 { 260 return maRecordHeader.nRecInstance; 261 } 262 263 inline sal_uInt32 Atom::getLength() const 264 { 265 return maRecordHeader.nRecLen; 266 } 267 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 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 */ 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 */ 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 */ 362 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 */ 374 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 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 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 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: 496 AtomBoxString( SvLBoxEntry* pEntry, const String& rStr ) 497 : SvLBoxString( pEntry, 0, rStr ) 498 { } 499 500 ~AtomBoxString() { } 501 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 571 void SetCollapsingHdl(const Link& rNewHdl){maCollapsingHdl=rNewHdl;} 572 const Link& GetCollapsingHdl() const { return maCollapsingHdl; } 573 574 void SetExpandingHdl(const Link& rNewHdl){maExpandingHdl=rNewHdl;} 575 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 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 615 AtomContainerTreeListBox::~AtomContainerTreeListBox() 616 { 617 } 618 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 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 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 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 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 689 void AtomContainerTreeListBox::SetRootAtom( const Atom* pAtom ) 690 { 691 mpRootAtom = pAtom; 692 InsertAtom( mpRootAtom ); 693 } 694 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 782 PPTDocument::PPTDocument(const rtl::OUString& rFilePath) 783 : mpAtom(0), mpDocStream(0) 784 { 785 Load( rFilePath ); 786 } 787 788 PPTDocument::~PPTDocument() 789 { 790 delete mpAtom; 791 delete mpDocStream; 792 } 793 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 810 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 850 void MSViewerWorkWindow::onView() 851 { 852 PPTDocumentPtr pDocument( Load() ); 853 if( pDocument.get() ) 854 { 855 onClose(); 856 View( pDocument, 0 ); 857 } 858 } 859 860 void MSViewerWorkWindow::onClose() 861 { 862 } 863 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 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 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 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 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 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 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 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 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 1067 IMPL_LINK(MSViewerWorkWindow, implCollapsingHdl, AtomContainerEntryPair*, pPair ) 1068 { 1069 Sync( pPair, 1 ); 1070 1071 return 0; 1072 } 1073 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 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 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 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