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_cui.hxx" 26 27 #include <comphelper/processfactory.hxx> 28 #include <dialmgr.hxx> 29 #include <osl/file.hxx> 30 #include <rtl/bootstrap.hxx> 31 #include <sfx2/sfxcommands.h> 32 #include <sfx2/sfxdefs.hxx> 33 #include <sfx2/sfxuno.hxx> 34 #include <svtools/filter.hxx> 35 #include <svtools/svtools.hrc> 36 #include <tools/stream.hxx> 37 #include <tools/urlobj.hxx> 38 #include <unotools/bootstrap.hxx> 39 #include <unotools/configmgr.hxx> 40 #include <vcl/graph.hxx> 41 #include <vcl/imagerepository.hxx> 42 #include <vcl/msgbox.hxx> 43 #include <vcl/svapp.hxx> 44 #include <vcl/tabctrl.hxx> 45 #include <vcl/tabdlg.hxx> 46 #include <vcl/tabpage.hxx> 47 48 #include <com/sun/star/system/SystemShellExecuteFlags.hpp> 49 #include <com/sun/star/system/XSystemShellExecute.hpp> 50 #include <com/sun/star/uno/Any.h> 51 52 #include "about.hxx" 53 #include "about.hrc" 54 55 #define _STRINGIFY(x) #x 56 #define STRINGIFY(x) _STRINGIFY(x) 57 58 /* On Windows/OS2, all the three files have .txt extension 59 and the README file name is in lowercase 60 Readme files are localized and have the locale in their file name: 61 README_de README_en-US 62 */ 63 #if defined(WNT) || defined(OS2) 64 #define FILE_EXTENSION ".txt" 65 #define README_FILE "readme" 66 #else 67 #define FILE_EXTENSION 68 #define README_FILE "README" 69 #endif 70 #define LICENSE_FILE "LICENSE" FILE_EXTENSION 71 #define NOTICE_FILE "NOTICE" FILE_EXTENSION 72 73 // Dir where the files are located 74 #define BRAND_DIR_SHARE_README "${BRAND_BASE_DIR}/share/readme/" 75 76 using namespace com::sun::star; 77 78 namespace 79 { 80 81 static void lcl_layoutFixedText( FixedText &rControl, 82 const Point& aPos, 83 Size &aSize, 84 const long nTextWidth ) 85 { 86 aSize = rControl.GetSizePixel(); 87 // change the width 88 aSize.Width() = nTextWidth; 89 // set Position and Size, to calculate the minimum size 90 // this will update the Height 91 rControl.SetPosSizePixel( aPos, aSize ); 92 aSize = rControl.CalcMinimumSize(); 93 // update the size with the right Height 94 rControl.SetSizePixel( aSize ); 95 } 96 97 static void lcl_layoutEdit( Edit &rControl, 98 const Point& aPos, 99 Size &aSize, 100 const long nTextWidth ) 101 { 102 aSize = rControl.GetSizePixel(); 103 // change the width 104 aSize.Width() = nTextWidth; 105 // set Position and Size, to calculate the minimum size 106 // this will update the Height 107 rControl.SetPosSizePixel( aPos, aSize ); 108 aSize = rControl.CalcMinimumSize(); 109 // update the size with the right Height 110 rControl.SetSizePixel( aSize ); 111 } 112 113 static void lcl_readTxtFile( const rtl::OUString &rFile, rtl::OUString &sText ) 114 { 115 rtl::OUString sFile( rFile ); 116 rtl::Bootstrap::expandMacros( sFile ); 117 osl::File aFile(sFile); 118 if ( aFile.open(OpenFlag_Read) == osl::FileBase::E_None ) 119 { 120 osl::DirectoryItem aItem; 121 osl::DirectoryItem::get(sFile, aItem); 122 123 osl::FileStatus aStatus(FileStatusMask_FileSize); 124 aItem.getFileStatus(aStatus); 125 126 sal_uInt64 nBytesRead = 0; 127 sal_uInt64 nPosition = 0; 128 sal_uInt32 nBytes = (sal_uInt32)aStatus.getFileSize(); 129 130 sal_Char *pBuffer = new sal_Char[nBytes]; 131 132 while ( aFile.read( pBuffer + nPosition, 133 nBytes-nPosition, 134 nBytesRead ) == osl::FileBase::E_None 135 && nPosition + nBytesRead < nBytes) 136 { 137 nPosition += nBytesRead; 138 } 139 140 OSL_ENSURE( nBytes < STRING_MAXLEN, "Text file has too much bytes!" ); 141 if ( nBytes > STRING_MAXLEN ) 142 nBytes = STRING_MAXLEN - 1; 143 144 sText = rtl::OUString( pBuffer, 145 nBytes, 146 RTL_TEXTENCODING_UTF8, 147 OSTRING_TO_OUSTRING_CVTFLAGS 148 | RTL_TEXTTOUNICODE_FLAGS_GLOBAL_SIGNATURE); 149 delete[] pBuffer; 150 } 151 } 152 153 class ReadmeDialog; 154 155 class ReadmeTabPage : public TabPage 156 { 157 private: 158 MultiLineEdit maText; 159 String msText; 160 161 public: 162 ReadmeTabPage(Window *pParent, const String &sText); 163 ~ReadmeTabPage(); 164 165 void Adjust(const Size &aSz, const Size &a6Size); 166 }; 167 168 ReadmeTabPage::ReadmeTabPage(Window *pParent, const String &sText) 169 : TabPage(pParent, CUI_RES( RID_CUI_README_TBPAGE)) 170 ,maText( this, CUI_RES( RID_CUI_README_TBPAGE_EDIT )) 171 ,msText( sText ) 172 { 173 FreeResource(); 174 175 maText.SetText(msText); 176 maText.Show(); 177 } 178 179 ReadmeTabPage::~ReadmeTabPage() 180 { 181 } 182 183 void ReadmeTabPage::Adjust(const Size &aSz, const Size &a6Size) 184 { 185 long nDlgMargin = a6Size.Width() * 2; 186 long nCtrlMargin = a6Size.Height() * 2; 187 maText.SetPosPixel( Point(a6Size.Width(), a6Size.Height()) ); 188 maText.SetSizePixel( Size(aSz.Width() - nDlgMargin, aSz.Height() - nCtrlMargin) ); 189 } 190 191 class ReadmeDialog : public ModalDialog 192 { 193 private: 194 TabControl maTabCtrl; 195 OKButton maBtnOK; 196 197 ReadmeTabPage *maReadmeTabPage; 198 ReadmeTabPage *maLicenseTabPage; 199 ReadmeTabPage *maNoticeTabPage; 200 201 DECL_LINK( ActivatePageHdl, TabControl * ); 202 DECL_LINK( DeactivatePageHdl, TabControl * ); 203 204 public: 205 ReadmeDialog( Window* ); 206 ~ReadmeDialog(); 207 }; 208 209 ReadmeDialog::ReadmeDialog( Window * pParent ) 210 : ModalDialog( pParent, CUI_RES( RID_CUI_README_DLG ) ) 211 , maTabCtrl( this, CUI_RES(RID_CUI_README_TBCTL) ) 212 , maBtnOK( this, CUI_RES(RID_CUI_README_OKBTN) ) 213 , maReadmeTabPage(0) 214 , maLicenseTabPage(0) 215 , maNoticeTabPage(0) 216 { 217 FreeResource(); 218 219 maTabCtrl.Show(); 220 221 // Notice and License are not localized 222 const rtl::OUString sLicense( RTL_CONSTASCII_USTRINGPARAM( BRAND_DIR_SHARE_README LICENSE_FILE ) ); 223 const rtl::OUString sNotice( RTL_CONSTASCII_USTRINGPARAM( BRAND_DIR_SHARE_README NOTICE_FILE ) ); 224 225 // get localized README 226 rtl::OUStringBuffer aBuff; 227 lang::Locale aLocale = Application::GetSettings().GetUILocale(); 228 aBuff.appendAscii( RTL_CONSTASCII_STRINGPARAM( BRAND_DIR_SHARE_README README_FILE "_" ) ); 229 aBuff.append( aLocale.Language ); 230 if ( aLocale.Country.getLength() ) 231 { 232 aBuff.append( sal_Unicode( '-') ); 233 aBuff.append( aLocale.Country ); 234 if ( aLocale.Variant.getLength() ) 235 { 236 aBuff.append( sal_Unicode( '-' ) ); 237 aBuff.append( aLocale.Variant ); 238 } 239 } 240 #if defined(WNT) || defined(OS2) 241 aBuff.appendAscii( RTL_CONSTASCII_STRINGPARAM( FILE_EXTENSION ) ); 242 #endif 243 244 rtl::OUString sReadmeTxt, sLicenseTxt, sNoticeTxt; 245 lcl_readTxtFile( aBuff.makeStringAndClear(), sReadmeTxt ); 246 lcl_readTxtFile( sLicense, sLicenseTxt ); 247 lcl_readTxtFile( sNotice, sNoticeTxt ); 248 249 maReadmeTabPage = new ReadmeTabPage( &maTabCtrl, sReadmeTxt ); 250 maLicenseTabPage = new ReadmeTabPage( &maTabCtrl, sLicenseTxt ); 251 maNoticeTabPage = new ReadmeTabPage( &maTabCtrl, sNoticeTxt ); 252 253 maTabCtrl.SetTabPage( RID_CUI_READMEPAGE, maReadmeTabPage ); 254 maTabCtrl.SetTabPage( RID_CUI_LICENSEPAGE, maLicenseTabPage ); 255 maTabCtrl.SetTabPage( RID_CUI_NOTICEPAGE, maNoticeTabPage ); 256 257 maTabCtrl.SelectTabPage( RID_CUI_READMEPAGE ); 258 259 Size aTpSz = maReadmeTabPage->GetOutputSizePixel(); 260 Size a6Size = maReadmeTabPage->LogicToPixel( Size( 6, 6 ), MAP_APPFONT ); 261 262 maReadmeTabPage->Adjust( aTpSz, a6Size ); 263 maLicenseTabPage->Adjust( aTpSz, a6Size ); 264 maNoticeTabPage->Adjust( aTpSz, a6Size ); 265 266 Size aDlgSize = GetOutputSizePixel(); 267 Size aOkBtnSz = maBtnOK.GetSizePixel(); 268 Point aOKPnt( aDlgSize.Width() / 2 - aOkBtnSz.Width() / 2 , maBtnOK.GetPosPixel().Y() ); 269 maBtnOK.SetPosPixel( aOKPnt ); 270 } 271 272 ReadmeDialog::~ReadmeDialog() 273 { 274 delete maReadmeTabPage; 275 delete maLicenseTabPage; 276 delete maNoticeTabPage; 277 } 278 } 279 280 // ----------------------------------------------------------------------- 281 282 AboutDialog::AboutDialog( Window* pParent, const ResId& rId ) : 283 SfxModalDialog( pParent, rId ), 284 maOKButton( this, ResId( RID_CUI_ABOUT_BTN_OK, *rId.GetResMgr() ) ), 285 maReadmeButton( this, ResId( RID_CUI_ABOUT_BTN_README, *rId.GetResMgr() ) ), 286 maVersionText( this, ResId( RID_CUI_ABOUT_FTXT_VERSION, *rId.GetResMgr() ) ), 287 maBuildInfoEdit( this, ResId( RID_CUI_ABOUT_FTXT_BUILDDATA, *rId.GetResMgr() ) ), 288 maCopyrightEdit( this, ResId( RID_CUI_ABOUT_FTXT_COPYRIGHT, *rId.GetResMgr() ) ), 289 maCreditsLink( this, ResId( RID_CUI_ABOUT_FTXT_WELCOME_LINK, *rId.GetResMgr() ) ), 290 maCopyrightTextStr( ResId( RID_CUI_ABOUT_STR_COPYRIGHT, *rId.GetResMgr() ) ) 291 { 292 bool bLoad = vcl::ImageRepository::loadBrandingImage( 293 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("about")), 294 maAppLogo ); 295 OSL_ENSURE( bLoad, "Can't load about image"); 296 297 bLoad = vcl::ImageRepository::loadBrandingImage( 298 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("logo")), 299 maMainLogo ); 300 OSL_ENSURE( bLoad, "Can't load logo image"); 301 302 InitControls(); 303 304 // set links 305 maReadmeButton.SetClickHdl( LINK( this, AboutDialog, ShowReadme_Impl ) ); 306 maCreditsLink.SetClickHdl( LINK( this, AboutDialog, OpenLinkHdl_Impl ) ); 307 308 FreeResource(); 309 310 SetHelpId( CMD_SID_ABOUT ); 311 } 312 313 // ----------------------------------------------------------------------- 314 315 AboutDialog::~AboutDialog() 316 { 317 } 318 319 // ----------------------------------------------------------------------- 320 321 void AboutDialog::InitControls() 322 { 323 // apply font, background et al. 324 ApplyStyleSettings(); 325 326 // set strings 327 maCopyrightEdit.SetText( maCopyrightTextStr ); 328 maBuildInfoEdit.SetText( GetBuildVersionString() ); 329 maCreditsLink.SetURL( maCreditsLink.GetText() ); 330 331 // determine size and position of the dialog & elements 332 Size aDlgSize; 333 LayoutControls( aDlgSize ); 334 335 // Change the width of the dialog 336 SetOutputSizePixel( aDlgSize ); 337 } 338 339 // ----------------------------------------------------------------------- 340 341 void AboutDialog::ApplyStyleSettings() 342 { 343 // Transparenter Font 344 Font aFont = GetFont(); 345 aFont.SetTransparent( sal_True ); 346 SetFont( aFont ); 347 348 // set for background and text the correct system color 349 const StyleSettings& rSettings = GetSettings().GetStyleSettings(); 350 Color aWindowColor( rSettings.GetWindowColor() ); 351 Wallpaper aWall( aWindowColor ); 352 SetBackground( aWall ); 353 Font aNewFont( maCopyrightEdit.GetFont() ); 354 aNewFont.SetTransparent( sal_True ); 355 356 maVersionText.SetFont( aNewFont ); 357 maCopyrightEdit.SetFont( aNewFont ); 358 359 maVersionText.SetBackground(aWall); 360 maCopyrightEdit.SetBackground(aWall); 361 maBuildInfoEdit.SetBackground(aWall); 362 maCreditsLink.SetBackground(aWall); 363 364 Color aTextColor( rSettings.GetWindowTextColor() ); 365 maVersionText.SetControlForeground( aTextColor ); 366 maCopyrightEdit.SetControlForeground( aTextColor ); 367 maBuildInfoEdit.SetControlForeground( aTextColor ); 368 maCreditsLink.SetControlForeground(); 369 370 Size aSmaller = aNewFont.GetSize(); 371 aSmaller.Width() = (long) (aSmaller.Width() * 0.75); 372 aSmaller.Height() = (long) (aSmaller.Height() * 0.75); 373 aNewFont.SetSize( aSmaller ); 374 375 maBuildInfoEdit.SetFont( aNewFont ); 376 377 // the following is a hack to force the MultiLineEdit update its settings 378 // in order to reflect the Font 379 // See 380 // Window::SetControlFont 381 // MultiLineEdit::StateChanged 382 // MultiLineEdit::ImplInitSettings 383 // TODO Override SetFont in MultiLineEdit and do the following, 384 // otherwise SetFont has no effect at all! 385 aSmaller = PixelToLogic( aSmaller, MAP_POINT ); 386 aNewFont.SetSize( aSmaller ); 387 maBuildInfoEdit.SetControlFont( aNewFont ); 388 } 389 390 // ----------------------------------------------------------------------- 391 392 void AboutDialog::LayoutControls( Size& aDlgSize ) 393 { 394 Size aMainLogoSz = maMainLogo.GetSizePixel(); 395 Size aAppLogoSiz = maAppLogo.GetSizePixel(); 396 397 long nLeftOffset = aMainLogoSz.Width(); 398 399 aDlgSize = GetOutputSizePixel(); 400 401 Size a6Size = maVersionText.LogicToPixel( Size( 6, 6 ), MAP_APPFONT ); 402 long nDlgMargin = a6Size.Width() * 2; 403 long nCtrlMargin = a6Size.Height() * 2; 404 long nTextWidth = aAppLogoSiz.Width() - nDlgMargin; 405 long nY = aAppLogoSiz.Height() + a6Size.Height(); 406 407 aDlgSize.Width() = nLeftOffset + a6Size.Width() + aAppLogoSiz.Width(); 408 409 Point aPos( nLeftOffset + a6Size.Width(), nY ); 410 Size aSize; 411 // layout fixed text control 412 lcl_layoutFixedText( maVersionText, aPos, aSize, nTextWidth ); 413 nY += aSize.Height() + a6Size.Height(); 414 415 // Multiline edit with Build info 416 aPos.Y() = nY; 417 lcl_layoutEdit( maBuildInfoEdit, aPos, aSize, nTextWidth ); 418 nY += aSize.Height() + a6Size.Height(); 419 420 // Multiline edit with Copyright-Text 421 aPos.Y() = nY; 422 lcl_layoutEdit( maCopyrightEdit, aPos, aSize, nTextWidth ); 423 nY += aSize.Height() + a6Size.Height(); 424 425 // Hyperlink 426 aPos.Y() = nY; 427 lcl_layoutFixedText( maCreditsLink, aPos, aSize, nTextWidth ); 428 nY += aSize.Height(); 429 430 nY = std::max( nY, aMainLogoSz.Height() ); 431 nY += nCtrlMargin; 432 433 // logos position 434 maMainLogoPos = Point( 0, nY / 2 - aMainLogoSz.Height() / 2 ); 435 maAppLogoPos = Point( nLeftOffset + a6Size.Width(), 0 ); 436 437 // OK-Button-Position (at the bottom and centered) 438 Size aOKSiz = maOKButton.GetSizePixel(); 439 Point aOKPnt( ( aDlgSize.Width() - aOKSiz.Width() ) - a6Size.Width(), nY ); 440 maOKButton.SetPosPixel( aOKPnt ); 441 442 maReadmeButton.SetPosPixel( Point(a6Size.Width(), nY) ); 443 444 aDlgSize.Height() = aOKPnt.Y() + aOKSiz.Height() + a6Size.Width(); 445 } 446 447 // ----------------------------------------------------------------------- 448 449 const rtl::OUString AboutDialog::GetBuildId() const 450 { 451 rtl::OUString sDefault; 452 453 // Get buildid from version[rc|.ini] 454 rtl::OUString sBuildId( utl::Bootstrap::getBuildIdData( sDefault ) ); 455 OSL_ENSURE( sBuildId.getLength() > 0, "No BUILDID in bootstrap file" ); 456 rtl::OUStringBuffer sBuildIdBuff( sBuildId ); 457 458 // Get ProductSource from version[rc|.ini] 459 rtl::OUString sProductSource( utl::Bootstrap::getProductSource( sDefault ) ); 460 OSL_ENSURE( sProductSource.getLength() > 0, "No ProductSource in bootstrap file" ); 461 462 // the product source is something like "AOO340", 463 // while the build id is something like "340m1(Build:9590)" 464 // For better readability, strip the duplicate ProductMajor ("340"). 465 if ( sProductSource.getLength() ) 466 { 467 bool bMatchingUPD = 468 ( sProductSource.getLength() >= 3 ) 469 && ( sBuildId.getLength() >= 3 ) 470 && ( sProductSource.copy( sProductSource.getLength() - 3 ) == sBuildId.copy( 0, 3 ) ); 471 OSL_ENSURE( bMatchingUPD, "BUILDID and ProductSource do not match in their UPD" ); 472 if ( bMatchingUPD ) 473 sProductSource = sProductSource.copy( 0, sProductSource.getLength() - 3 ); 474 475 // prepend the product source 476 sBuildIdBuff.insert( 0, sProductSource ); 477 } 478 479 return sBuildIdBuff.makeStringAndClear(); 480 } 481 482 // ----------------------------------------------------------------------- 483 484 const rtl::OUString AboutDialog::GetBuildVersionString() const 485 { 486 rtl::OUStringBuffer aBuildString( GetBuildId() ); 487 rtl::OUString sRevision( utl::Bootstrap::getRevisionInfo() ); 488 489 if ( sRevision.getLength() > 0 ) 490 { 491 aBuildString.appendAscii( RTL_CONSTASCII_STRINGPARAM( " - Rev. " ) ); 492 aBuildString.append( sRevision ); 493 } 494 495 #ifdef BUILD_VER_STRING 496 rtl::OUString sBuildVer( RTL_CONSTASCII_USTRINGPARAM( STRINGIFY( BUILD_VER_STRING ) ) ); 497 if ( sBuildVer.getLength() > 0 ) 498 { 499 aBuildString.append( sal_Unicode( '\n' ) ); 500 aBuildString.append( sBuildVer ); 501 } 502 #endif 503 504 return aBuildString.makeStringAndClear(); 505 } 506 507 // ----------------------------------------------------------------------- 508 509 sal_Bool AboutDialog::Close() 510 { 511 EndDialog( RET_OK ); 512 return( sal_False ); 513 } 514 515 // ----------------------------------------------------------------------- 516 517 void AboutDialog::Paint( const Rectangle& rRect ) 518 { 519 SetClipRegion( rRect ); 520 DrawImage( maMainLogoPos, maMainLogo ); 521 DrawImage( maAppLogoPos, maAppLogo ); 522 523 return; 524 } 525 526 // ----------------------------------------------------------------------- 527 528 IMPL_LINK ( AboutDialog, OpenLinkHdl_Impl, svt::FixedHyperlink*, EMPTYARG ) 529 { 530 ::rtl::OUString sURL( maCreditsLink.GetURL() ); 531 if ( sURL.getLength() > 0 ) 532 { 533 try 534 { 535 uno::Reference< uno::XComponentContext > xContext = 536 ::comphelper::getProcessComponentContext(); 537 uno::Reference< system::XSystemShellExecute > xSystemShell( 538 xContext->getServiceManager()->createInstanceWithContext( 539 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SystemShellExecute" ) ), 540 xContext ), 541 uno::UNO_QUERY_THROW ); 542 if ( xSystemShell.is() ) 543 xSystemShell->execute( sURL, rtl::OUString(), system::SystemShellExecuteFlags::DEFAULTS ); 544 } 545 catch( const uno::Exception& e ) 546 { 547 OSL_TRACE( "Caught exception: %s\n thread terminated.\n", 548 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 549 } 550 } 551 552 return 0; 553 } 554 555 IMPL_LINK ( AboutDialog, ShowReadme_Impl, PushButton*, EMPTYARG ) 556 { 557 ReadmeDialog aDlg( this ); 558 aDlg.Execute(); 559 560 return 0; 561 } 562