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