blob: 7b5c40855d9c0d9ae34ebbc5c026786932d58a53 [file] [log] [blame]
/**************************************************************
*
* 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 <comphelper/processfactory.hxx>
#include <dialmgr.hxx>
#include <osl/file.hxx>
#include <rtl/bootstrap.hxx>
//#include <rtl/ustrbuf.hxx>
#include <sfx2/sfxcommands.h>
#include <sfx2/sfxdefs.hxx>
#include <sfx2/sfxuno.hxx>
#include <svtools/filter.hxx>
#include <svtools/svtools.hrc>
#include <tools/stream.hxx>
#include <tools/urlobj.hxx>
#include <unotools/bootstrap.hxx>
#include <unotools/configmgr.hxx>
#include <vcl/graph.hxx>
#include <vcl/imagerepository.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/svapp.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabdlg.hxx>
#include <vcl/tabpage.hxx>
#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
#include <com/sun/star/system/SystemShellExecute.hpp>
#include <com/sun/star/uno/Any.h>
#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("2014") );
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() )
{
bool bMatchingUPD =
( sProductSource.getLength() >= 3 )
&& ( sBuildId.getLength() >= 3 )
&& ( sProductSource.copy( sProductSource.getLength() - 3 ) == sBuildId.copy( 0, 3 ) );
OSL_ENSURE( bMatchingUPD, "BUILDID and ProductSource do not match in their UPD" );
if ( bMatchingUPD )
sProductSource = sProductSource.copy( 0, sProductSource.getLength() - 3 );
// 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 exmaple 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;
}