xref: /trunk/main/cui/source/dialogs/about.cxx (revision 910823ae)
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