/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_cui.hxx" #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "about.hxx" #include "about.hrc" #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) /* On Windows/OS2, all the three files have .txt extension and the README file name is in lowercase Readme files are localized and have the locale in their file name: README_de README_en-US */ #if defined(WNT) || defined(OS2) #define FILE_EXTENSION ".txt" #define README_FILE "readme" #else #define FILE_EXTENSION #define README_FILE "README" #endif #define LICENSE_FILE "LICENSE" FILE_EXTENSION #define NOTICE_FILE "NOTICE" FILE_EXTENSION // Dir where the files are located #define OOO_DIR_SHARE_README "${OOO_BASE_DIR}/share/readme/" using namespace com::sun::star; namespace { static void lcl_layoutFixedText( FixedText &rControl, const Point& aPos, Size &aSize, const long nTextWidth ) { aSize = rControl.GetSizePixel(); // change the width aSize.Width() = nTextWidth; // set Position and Size, to calculate the minimum size // this will update the Height rControl.SetPosSizePixel( aPos, aSize ); aSize = rControl.CalcMinimumSize(); // update the size with the right Height rControl.SetSizePixel( aSize ); } static void lcl_layoutEdit( Edit &rControl, const Point& aPos, Size &aSize, const long nTextWidth ) { aSize = rControl.GetSizePixel(); // change the width aSize.Width() = nTextWidth; // set Position and Size, to calculate the minimum size // this will update the Height rControl.SetPosSizePixel( aPos, aSize ); aSize = rControl.CalcMinimumSize(); // update the size with the right Height rControl.SetSizePixel( aSize ); } static void lcl_readTxtFile( const rtl::OUString &rFile, rtl::OUString &sText ) { rtl::OUString sFile( rFile ); rtl::Bootstrap::expandMacros( sFile ); osl::File aFile(sFile); if ( aFile.open(OpenFlag_Read) == osl::FileBase::E_None ) { osl::DirectoryItem aItem; osl::DirectoryItem::get(sFile, aItem); osl::FileStatus aStatus(FileStatusMask_FileSize); aItem.getFileStatus(aStatus); sal_uInt64 nBytesRead = 0; sal_uInt64 nPosition = 0; sal_uInt32 nBytes = (sal_uInt32)aStatus.getFileSize(); sal_Char *pBuffer = new sal_Char[nBytes]; while ( aFile.read( pBuffer + nPosition, nBytes-nPosition, nBytesRead ) == osl::FileBase::E_None && nPosition + nBytesRead < nBytes) { nPosition += nBytesRead; } OSL_ENSURE( nBytes < STRING_MAXLEN, "Text file has too much bytes!" ); if ( nBytes > STRING_MAXLEN ) nBytes = STRING_MAXLEN - 1; sText = rtl::OUString( pBuffer, nBytes, RTL_TEXTENCODING_UTF8, OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_GLOBAL_SIGNATURE); delete[] pBuffer; } } class ReadmeDialog; class ReadmeTabPage : public TabPage { private: MultiLineEdit maText; String msText; public: ReadmeTabPage(Window *pParent, const String &sText); ~ReadmeTabPage(); void Adjust(const Size &aSz, const Size &a6Size); }; ReadmeTabPage::ReadmeTabPage(Window *pParent, const String &sText) : TabPage(pParent, CUI_RES( RID_CUI_README_TBPAGE)) ,maText( this, CUI_RES( RID_CUI_README_TBPAGE_EDIT )) ,msText( sText ) { FreeResource(); maText.SetText(msText); maText.Show(); } ReadmeTabPage::~ReadmeTabPage() { } void ReadmeTabPage::Adjust(const Size &aSz, const Size &a6Size) { long nDlgMargin = a6Size.Width() * 2; long nCtrlMargin = a6Size.Height() * 2; maText.SetPosPixel( Point(a6Size.Width(), a6Size.Height()) ); maText.SetSizePixel( Size(aSz.Width() - nDlgMargin, aSz.Height() - nCtrlMargin) ); } class ReadmeDialog : public ModalDialog { private: TabControl maTabCtrl; OKButton maBtnOK; ReadmeTabPage *maReadmeTabPage; ReadmeTabPage *maLicenseTabPage; ReadmeTabPage *maNoticeTabPage; DECL_LINK( ActivatePageHdl, TabControl * ); DECL_LINK( DeactivatePageHdl, TabControl * ); public: ReadmeDialog( Window* ); ~ReadmeDialog(); }; ReadmeDialog::ReadmeDialog( Window * pParent ) : ModalDialog( pParent, CUI_RES( RID_CUI_README_DLG ) ) , maTabCtrl( this, CUI_RES(RID_CUI_README_TBCTL) ) , maBtnOK( this, CUI_RES(RID_CUI_README_OKBTN) ) , maReadmeTabPage(0) , maLicenseTabPage(0) , maNoticeTabPage(0) { FreeResource(); maTabCtrl.Show(); // Notice and License are not localized const rtl::OUString sLicense( RTL_CONSTASCII_USTRINGPARAM( OOO_DIR_SHARE_README LICENSE_FILE ) ); const rtl::OUString sNotice( RTL_CONSTASCII_USTRINGPARAM( OOO_DIR_SHARE_README NOTICE_FILE ) ); // get localized README rtl::OUStringBuffer aBuff; lang::Locale aLocale = Application::GetSettings().GetUILocale(); aBuff.appendAscii( RTL_CONSTASCII_STRINGPARAM( OOO_DIR_SHARE_README README_FILE "_" ) ); aBuff.append( aLocale.Language ); if ( aLocale.Country.getLength() ) { aBuff.append( sal_Unicode( '-') ); aBuff.append( aLocale.Country ); if ( aLocale.Variant.getLength() ) { aBuff.append( sal_Unicode( '-' ) ); aBuff.append( aLocale.Variant ); } } #if defined(WNT) || defined(OS2) aBuff.appendAscii( RTL_CONSTASCII_STRINGPARAM( FILE_EXTENSION ) ); #endif rtl::OUString sReadmeTxt, sLicenseTxt, sNoticeTxt; lcl_readTxtFile( aBuff.makeStringAndClear(), sReadmeTxt ); lcl_readTxtFile( sLicense, sLicenseTxt ); lcl_readTxtFile( sNotice, sNoticeTxt ); maReadmeTabPage = new ReadmeTabPage( &maTabCtrl, sReadmeTxt ); maLicenseTabPage = new ReadmeTabPage( &maTabCtrl, sLicenseTxt ); maNoticeTabPage = new ReadmeTabPage( &maTabCtrl, sNoticeTxt ); maTabCtrl.SetTabPage( RID_CUI_READMEPAGE, maReadmeTabPage ); maTabCtrl.SetTabPage( RID_CUI_LICENSEPAGE, maLicenseTabPage ); maTabCtrl.SetTabPage( RID_CUI_NOTICEPAGE, maNoticeTabPage ); maTabCtrl.SelectTabPage( RID_CUI_READMEPAGE ); Size aTpSz = maReadmeTabPage->GetOutputSizePixel(); Size a6Size = maReadmeTabPage->LogicToPixel( Size( 6, 6 ), MAP_APPFONT ); maReadmeTabPage->Adjust( aTpSz, a6Size ); maLicenseTabPage->Adjust( aTpSz, a6Size ); maNoticeTabPage->Adjust( aTpSz, a6Size ); Size aDlgSize = GetOutputSizePixel(); Size aOkBtnSz = maBtnOK.GetSizePixel(); Point aOKPnt( aDlgSize.Width() / 2 - aOkBtnSz.Width() / 2 , maBtnOK.GetPosPixel().Y() ); maBtnOK.SetPosPixel( aOKPnt ); } ReadmeDialog::~ReadmeDialog() { delete maReadmeTabPage; delete maLicenseTabPage; delete maNoticeTabPage; } } // ----------------------------------------------------------------------- AboutDialog::AboutDialog( Window* pParent, const ResId & rId ) : SfxModalDialog( pParent, rId ), maOKButton( this, ResId( RID_CUI_ABOUT_BTN_OK, *rId.GetResMgr() ) ), maReadmeButton( this, ResId( RID_CUI_ABOUT_BTN_README, *rId.GetResMgr() ) ), maVersionText( this, ResId( RID_CUI_ABOUT_FTXT_VERSION, *rId.GetResMgr() ) ), maBuildInfoEdit( this, ResId( RID_CUI_ABOUT_FTXT_BUILDDATA, *rId.GetResMgr() ) ), maCopyrightEdit( this, ResId( RID_CUI_ABOUT_FTXT_COPYRIGHT, *rId.GetResMgr() ) ), maCreditsLink( this, ResId( RID_CUI_ABOUT_FTXT_WELCOME_LINK, *rId.GetResMgr() ) ) // maCopyrightTextStr( ResId( RID_CUI_ABOUT_STR_COPYRIGHT, *rId.GetResMgr() ) ) { bool bLoad = vcl::ImageRepository::loadBrandingImage( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("about")), maAppLogo ); OSL_ENSURE( bLoad, "Can't load about image"); bLoad = vcl::ImageRepository::loadBrandingImage( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("logo")), maMainLogo ); OSL_ENSURE( bLoad, "Can't load logo image"); const String vendor( ResId( RID_CUI_ABOUT_STR_COPYRIGHT_VENDOR, *rId.GetResMgr() ) ); String createdRes( ResId( RID_CUI_ABOUT_STR_CREATED, *rId.GetResMgr() ) ); if ( !vendor.EqualsAscii("Apache Software Foundation") ) { createdRes = String( ResId( RID_CUI_ABOUT_STR_CREATED_VENDOR, *rId.GetResMgr() )); } const String copyrightAcknowledge( ResId( RID_CUI_ABOUT_STR_ACKNOWLEDGE, *rId.GetResMgr() ) ); rtl::OUStringBuffer sbcopyright(250); sbcopyright.appendAscii("Copyright "); sbcopyright.append((sal_Unicode)0x00a9); sbcopyright.appendAscii(" "); rtl::OUString sYear( RTL_CONSTASCII_USTRINGPARAM("2023") ); if (vendor.EqualsAscii("Apache Software Foundation")) { sbcopyright.append(sYear); sbcopyright.appendAscii(" The Apache Software Foundation.\n\n"); } else { #ifdef COPYRIGHT_YEAR const rtl::OUString sDefYear( RTL_CONSTASCII_USTRINGPARAM( STRINGIFY( COPYRIGHT_YEAR ) ) ); if ( sDefYear.getLength() > 0 ) { sYear = sDefYear; } #endif sbcopyright.append(sYear); sbcopyright.appendAscii(" "); sbcopyright.append(vendor); sbcopyright.appendAscii(".\nPortion copyright The Apache Software Foundation.\n\n"); } sbcopyright.append( createdRes ); sbcopyright.appendAscii("\n\n"); sbcopyright.append( copyrightAcknowledge ); maCopyrightTextStr = sbcopyright.makeStringAndClear(); InitControls(); // set links maReadmeButton.SetClickHdl( LINK( this, AboutDialog, ShowReadme_Impl ) ); maCreditsLink.SetClickHdl( LINK( this, AboutDialog, OpenLinkHdl_Impl ) ); FreeResource(); SetHelpId( CMD_SID_ABOUT ); } // ----------------------------------------------------------------------- AboutDialog::~AboutDialog() { } // ----------------------------------------------------------------------- void AboutDialog::InitControls() { // apply font, background et al. ApplyStyleSettings(); // set strings maCopyrightEdit.SetText( maCopyrightTextStr ); maBuildInfoEdit.SetText( GetBuildVersionString() ); maCreditsLink.SetURL( maCreditsLink.GetText() ); // determine size and position of the dialog & elements Size aDlgSize; LayoutControls( aDlgSize ); // Change the width of the dialog SetOutputSizePixel( aDlgSize ); } // ----------------------------------------------------------------------- void AboutDialog::ApplyStyleSettings() { // Transparenter Font Font aFont = GetFont(); aFont.SetTransparent( sal_True ); SetFont( aFont ); // set for background and text the correct system color const StyleSettings& rSettings = GetSettings().GetStyleSettings(); Color aWindowColor( rSettings.GetWindowColor() ); Wallpaper aWall( aWindowColor ); SetBackground( aWall ); Font aNewFont( maCopyrightEdit.GetFont() ); aNewFont.SetTransparent( sal_True ); maVersionText.SetFont( aNewFont ); maCopyrightEdit.SetFont( aNewFont ); maVersionText.SetBackground(aWall); maCopyrightEdit.SetBackground(aWall); maBuildInfoEdit.SetBackground(aWall); maCreditsLink.SetBackground(aWall); Color aTextColor( rSettings.GetWindowTextColor() ); maVersionText.SetControlForeground( aTextColor ); maCopyrightEdit.SetControlForeground( aTextColor ); maBuildInfoEdit.SetControlForeground( aTextColor ); maCreditsLink.SetControlForeground(); Size aSmaller = aNewFont.GetSize(); aSmaller.Width() = (long) (aSmaller.Width() * 0.75); aSmaller.Height() = (long) (aSmaller.Height() * 0.75); aNewFont.SetSize( aSmaller ); maBuildInfoEdit.SetFont( aNewFont ); // the following is a hack to force the MultiLineEdit update its settings // in order to reflect the Font // See // Window::SetControlFont // MultiLineEdit::StateChanged // MultiLineEdit::ImplInitSettings // TODO Override SetFont in MultiLineEdit and do the following, // otherwise SetFont has no effect at all! aSmaller = PixelToLogic( aSmaller, MAP_POINT ); aNewFont.SetSize( aSmaller ); maBuildInfoEdit.SetControlFont( aNewFont ); } // ----------------------------------------------------------------------- void AboutDialog::LayoutControls( Size& aDlgSize ) { Size aMainLogoSz = maMainLogo.GetSizePixel(); Size aAppLogoSiz = maAppLogo.GetSizePixel(); aDlgSize = GetOutputSizePixel(); long nCol1 = aMainLogoSz.Width(); long nCol2 = aAppLogoSiz.Width() ? aAppLogoSiz.Width() : aDlgSize.Width(); Size a6Size = maVersionText.LogicToPixel( Size( 6, 6 ), MAP_APPFONT ); long nDlgMargin = a6Size.Width() * 2; long nCtrlMargin = a6Size.Height() * 2; long nTextWidth = nCol2 - nDlgMargin; long nY = aAppLogoSiz.Height() + a6Size.Height(); aDlgSize.Width() = nCol1 + a6Size.Width() + nCol2; Point aPos( nCol1 + a6Size.Width(), nY ); Size aSize; // layout fixed text control lcl_layoutFixedText( maVersionText, aPos, aSize, nTextWidth ); nY += aSize.Height() + a6Size.Height(); // Multiline edit with Build info aPos.Y() = nY; lcl_layoutEdit( maBuildInfoEdit, aPos, aSize, nTextWidth ); nY += aSize.Height() + a6Size.Height(); // Multiline edit with Copyright-Text aPos.Y() = nY; lcl_layoutEdit( maCopyrightEdit, aPos, aSize, nTextWidth ); nY += aSize.Height() + a6Size.Height(); // Hyperlink aPos.Y() = nY; lcl_layoutFixedText( maCreditsLink, aPos, aSize, nTextWidth ); nY += aSize.Height(); nY = std::max( nY, aMainLogoSz.Height() ); nY += nCtrlMargin; // logos position maMainLogoPos = Point( 0, nY / 2 - aMainLogoSz.Height() / 2 ); maAppLogoPos = Point( nCol1 + a6Size.Width(), 0 ); // OK-Button-Position (at the bottom and centered) Size aOKSiz = maOKButton.GetSizePixel(); Point aOKPnt( ( aDlgSize.Width() - aOKSiz.Width() ) - a6Size.Width(), nY ); maOKButton.SetPosPixel( aOKPnt ); maReadmeButton.SetPosPixel( Point(a6Size.Width(), nY) ); aDlgSize.Height() = aOKPnt.Y() + aOKSiz.Height() + a6Size.Width(); } // ----------------------------------------------------------------------- const rtl::OUString AboutDialog::GetBuildId() const { rtl::OUString sDefault; // Get buildid from version[rc|.ini] rtl::OUString sBuildId( utl::Bootstrap::getBuildIdData( sDefault ) ); OSL_ENSURE( sBuildId.getLength() > 0, "No BUILDID in bootstrap file" ); rtl::OUStringBuffer sBuildIdBuff( sBuildId ); // Get ProductSource from version[rc|.ini] rtl::OUString sProductSource( utl::Bootstrap::getProductSource( sDefault ) ); OSL_ENSURE( sProductSource.getLength() > 0, "No ProductSource in bootstrap file" ); // the product source is something like "AOO340", // while the build id is something like "340m1(Build:9590)" // For better readability, strip the duplicate ProductMajor ("340"). if ( sProductSource.getLength() ) { sal_Int32 nMajorLength = sProductSource.getLength() - 3; bool bMatchingUPD = ( sProductSource.getLength() >= 3 ) && ( sBuildId.getLength() >= nMajorLength ) && ( sProductSource.copy( 3 ) == sBuildId.copy( 0, nMajorLength ) ); OSL_ENSURE( bMatchingUPD, "BUILDID and ProductSource do not match in their UPD" ); if ( bMatchingUPD ) sProductSource = sProductSource.copy( 0, sProductSource.getLength() - nMajorLength ); // prepend the product source sBuildIdBuff.insert( 0, sProductSource ); } return sBuildIdBuff.makeStringAndClear(); } // ----------------------------------------------------------------------- const rtl::OUString AboutDialog::GetBuildVersionString() const { rtl::OUStringBuffer aBuildString( GetBuildId() ); rtl::OUString sRevision( utl::Bootstrap::getRevisionInfo() ); if ( sRevision.getLength() > 0 ) { aBuildString.appendAscii( RTL_CONSTASCII_STRINGPARAM( " - Rev. " ) ); aBuildString.append( sRevision ); } #ifdef BUILD_VER_STRING rtl::OUString sBuildVer( RTL_CONSTASCII_USTRINGPARAM( STRINGIFY( BUILD_VER_STRING ) ) ); if ( sBuildVer.getLength() > 0 ) { aBuildString.append( sal_Unicode( '\n' ) ); aBuildString.append( sBuildVer ); } #endif return aBuildString.makeStringAndClear(); } // ----------------------------------------------------------------------- sal_Bool AboutDialog::Close() { EndDialog( RET_OK ); return( sal_False ); } // ----------------------------------------------------------------------- void AboutDialog::Paint( const Rectangle& rRect ) { SetClipRegion( rRect ); // workaround to ensure that the background is painted correct // on MacOS for example the background was grey and the image and other controls white SetFillColor(GetSettings().GetStyleSettings().GetWindowColor()); SetLineColor(); DrawRect(rRect); DrawImage( maMainLogoPos, maMainLogo ); DrawImage( maAppLogoPos, maAppLogo ); return; } // ----------------------------------------------------------------------- IMPL_LINK ( AboutDialog, OpenLinkHdl_Impl, svt::FixedHyperlink*, EMPTYARG ) { ::rtl::OUString sURL( maCreditsLink.GetURL() ); if ( sURL.getLength() > 0 ) { try { uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShell( com::sun::star::system::SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) ); if ( xSystemShell.is() ) xSystemShell->execute( sURL, rtl::OUString(), com::sun::star::system::SystemShellExecuteFlags::DEFAULTS ); } catch( const uno::Exception& e ) { OSL_TRACE( "Caught exception: %s\n thread terminated.\n", rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); } } return 0; } IMPL_LINK ( AboutDialog, ShowReadme_Impl, PushButton*, EMPTYARG ) { ReadmeDialog aDlg( this ); aDlg.Execute(); return 0; }