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/SystemShellExecute.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 OOO_DIR_SHARE_README "${OOO_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( OOO_DIR_SHARE_README LICENSE_FILE ) ); 223 const rtl::OUString sNotice( RTL_CONSTASCII_USTRINGPARAM( OOO_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( OOO_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 354 Font aNewFont( maCopyrightEdit.GetFont() ); 355 aNewFont.SetTransparent( sal_True ); 356 357 maVersionText.SetFont( aNewFont ); 358 maCopyrightEdit.SetFont( aNewFont ); 359 360 maVersionText.SetBackground(aWall); 361 maCopyrightEdit.SetBackground(aWall); 362 maBuildInfoEdit.SetBackground(aWall); 363 maCreditsLink.SetBackground(aWall); 364 365 Color aTextColor( rSettings.GetWindowTextColor() ); 366 maVersionText.SetControlForeground( aTextColor ); 367 maCopyrightEdit.SetControlForeground( aTextColor ); 368 maBuildInfoEdit.SetControlForeground( aTextColor ); 369 maCreditsLink.SetControlForeground(); 370 371 Size aSmaller = aNewFont.GetSize(); 372 aSmaller.Width() = (long) (aSmaller.Width() * 0.75); 373 aSmaller.Height() = (long) (aSmaller.Height() * 0.75); 374 aNewFont.SetSize( aSmaller ); 375 376 maBuildInfoEdit.SetFont( aNewFont ); 377 378 // the following is a hack to force the MultiLineEdit update its settings 379 // in order to reflect the Font 380 // See 381 // Window::SetControlFont 382 // MultiLineEdit::StateChanged 383 // MultiLineEdit::ImplInitSettings 384 // TODO Override SetFont in MultiLineEdit and do the following, 385 // otherwise SetFont has no effect at all! 386 aSmaller = PixelToLogic( aSmaller, MAP_POINT ); 387 aNewFont.SetSize( aSmaller ); 388 maBuildInfoEdit.SetControlFont( aNewFont ); 389 } 390 391 // ----------------------------------------------------------------------- 392 393 void AboutDialog::LayoutControls( Size& aDlgSize ) 394 { 395 Size aMainLogoSz = maMainLogo.GetSizePixel(); 396 Size aAppLogoSiz = maAppLogo.GetSizePixel(); 397 398 aDlgSize = GetOutputSizePixel(); 399 long nCol1 = aMainLogoSz.Width(); 400 long nCol2 = aAppLogoSiz.Width() ? aAppLogoSiz.Width() : aDlgSize.Width(); 401 402 Size a6Size = maVersionText.LogicToPixel( Size( 6, 6 ), MAP_APPFONT ); 403 long nDlgMargin = a6Size.Width() * 2; 404 long nCtrlMargin = a6Size.Height() * 2; 405 long nTextWidth = nCol2 - nDlgMargin; 406 long nY = aAppLogoSiz.Height() + a6Size.Height(); 407 408 aDlgSize.Width() = nCol1 + a6Size.Width() + nCol2; 409 410 Point aPos( nCol1 + a6Size.Width(), nY ); 411 Size aSize; 412 // layout fixed text control 413 lcl_layoutFixedText( maVersionText, aPos, aSize, nTextWidth ); 414 nY += aSize.Height() + a6Size.Height(); 415 416 // Multiline edit with Build info 417 aPos.Y() = nY; 418 lcl_layoutEdit( maBuildInfoEdit, aPos, aSize, nTextWidth ); 419 nY += aSize.Height() + a6Size.Height(); 420 421 // Multiline edit with Copyright-Text 422 aPos.Y() = nY; 423 lcl_layoutEdit( maCopyrightEdit, aPos, aSize, nTextWidth ); 424 nY += aSize.Height() + a6Size.Height(); 425 426 // Hyperlink 427 aPos.Y() = nY; 428 lcl_layoutFixedText( maCreditsLink, aPos, aSize, nTextWidth ); 429 nY += aSize.Height(); 430 431 nY = std::max( nY, aMainLogoSz.Height() ); 432 nY += nCtrlMargin; 433 434 // logos position 435 maMainLogoPos = Point( 0, nY / 2 - aMainLogoSz.Height() / 2 ); 436 maAppLogoPos = Point( nCol1 + a6Size.Width(), 0 ); 437 438 // OK-Button-Position (at the bottom and centered) 439 Size aOKSiz = maOKButton.GetSizePixel(); 440 Point aOKPnt( ( aDlgSize.Width() - aOKSiz.Width() ) - a6Size.Width(), nY ); 441 maOKButton.SetPosPixel( aOKPnt ); 442 443 maReadmeButton.SetPosPixel( Point(a6Size.Width(), nY) ); 444 445 aDlgSize.Height() = aOKPnt.Y() + aOKSiz.Height() + a6Size.Width(); 446 } 447 448 // ----------------------------------------------------------------------- 449 450 const rtl::OUString AboutDialog::GetBuildId() const 451 { 452 rtl::OUString sDefault; 453 454 // Get buildid from version[rc|.ini] 455 rtl::OUString sBuildId( utl::Bootstrap::getBuildIdData( sDefault ) ); 456 OSL_ENSURE( sBuildId.getLength() > 0, "No BUILDID in bootstrap file" ); 457 rtl::OUStringBuffer sBuildIdBuff( sBuildId ); 458 459 // Get ProductSource from version[rc|.ini] 460 rtl::OUString sProductSource( utl::Bootstrap::getProductSource( sDefault ) ); 461 OSL_ENSURE( sProductSource.getLength() > 0, "No ProductSource in bootstrap file" ); 462 463 // the product source is something like "AOO340", 464 // while the build id is something like "340m1(Build:9590)" 465 // For better readability, strip the duplicate ProductMajor ("340"). 466 if ( sProductSource.getLength() ) 467 { 468 bool bMatchingUPD = 469 ( sProductSource.getLength() >= 3 ) 470 && ( sBuildId.getLength() >= 3 ) 471 && ( sProductSource.copy( sProductSource.getLength() - 3 ) == sBuildId.copy( 0, 3 ) ); 472 OSL_ENSURE( bMatchingUPD, "BUILDID and ProductSource do not match in their UPD" ); 473 if ( bMatchingUPD ) 474 sProductSource = sProductSource.copy( 0, sProductSource.getLength() - 3 ); 475 476 // prepend the product source 477 sBuildIdBuff.insert( 0, sProductSource ); 478 } 479 480 return sBuildIdBuff.makeStringAndClear(); 481 } 482 483 // ----------------------------------------------------------------------- 484 485 const rtl::OUString AboutDialog::GetBuildVersionString() const 486 { 487 rtl::OUStringBuffer aBuildString( GetBuildId() ); 488 rtl::OUString sRevision( utl::Bootstrap::getRevisionInfo() ); 489 490 if ( sRevision.getLength() > 0 ) 491 { 492 aBuildString.appendAscii( RTL_CONSTASCII_STRINGPARAM( " - Rev. " ) ); 493 aBuildString.append( sRevision ); 494 } 495 496 #ifdef BUILD_VER_STRING 497 rtl::OUString sBuildVer( RTL_CONSTASCII_USTRINGPARAM( STRINGIFY( BUILD_VER_STRING ) ) ); 498 if ( sBuildVer.getLength() > 0 ) 499 { 500 aBuildString.append( sal_Unicode( '\n' ) ); 501 aBuildString.append( sBuildVer ); 502 } 503 #endif 504 505 return aBuildString.makeStringAndClear(); 506 } 507 508 // ----------------------------------------------------------------------- 509 510 sal_Bool AboutDialog::Close() 511 { 512 EndDialog( RET_OK ); 513 return( sal_False ); 514 } 515 516 // ----------------------------------------------------------------------- 517 518 void AboutDialog::Paint( const Rectangle& rRect ) 519 { 520 SetClipRegion( rRect ); 521 522 // workaround to ensure that the background is painted correct 523 // on MacOS for exmaple the background was grey and the image and other controls white 524 SetFillColor(GetSettings().GetStyleSettings().GetWindowColor()); 525 SetLineColor(); 526 DrawRect(rRect); 527 528 DrawImage( maMainLogoPos, maMainLogo ); 529 DrawImage( maAppLogoPos, maAppLogo ); 530 531 return; 532 } 533 534 // ----------------------------------------------------------------------- 535 536 IMPL_LINK ( AboutDialog, OpenLinkHdl_Impl, svt::FixedHyperlink*, EMPTYARG ) 537 { 538 ::rtl::OUString sURL( maCreditsLink.GetURL() ); 539 if ( sURL.getLength() > 0 ) 540 { 541 try 542 { 543 uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShell( 544 com::sun::star::system::SystemShellExecute::create( 545 ::comphelper::getProcessComponentContext() ) ); 546 if ( xSystemShell.is() ) 547 xSystemShell->execute( sURL, rtl::OUString(), com::sun::star::system::SystemShellExecuteFlags::DEFAULTS ); 548 } 549 catch( const uno::Exception& e ) 550 { 551 OSL_TRACE( "Caught exception: %s\n thread terminated.\n", 552 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 553 } 554 } 555 556 return 0; 557 } 558 559 IMPL_LINK ( AboutDialog, ShowReadme_Impl, PushButton*, EMPTYARG ) 560 { 561 ReadmeDialog aDlg( this ); 562 aDlg.Execute(); 563 564 return 0; 565 } 566