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