xref: /core/cui/source/dialogs/about.cxx (revision 28fc9860)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 #include <osl/process.h>
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <rtl/character.hxx>
25 #include <vcl/graphicfilter.hxx>
26 #include <vcl/settings.hxx>
27 #include <vcl/stdtext.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/weld.hxx>
31 
32 #include <unotools/configmgr.hxx>
33 #include <unotools/bootstrap.hxx>
34 #include <com/sun/star/uno/Any.h>
35 #include <svtools/langhelp.hxx>
36 #include <i18nlangtag/languagetag.hxx>
37 
38 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
39 #include <com/sun/star/system/SystemShellExecute.hpp>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/anytostring.hxx>
42 #include <cppuhelper/exc_hlp.hxx>
43 #include <svtools/optionsdrawinglayer.hxx>
44 
45 #include <about.hxx>
46 #include <dialmgr.hxx>
47 #include <strings.hrc>
48 #include <config_buildid.h>
49 #include <sfx2/app.hxx>
50 
51 #if HAVE_FEATURE_OPENCL
52 #include <opencl/openclwrapper.hxx>
53 #endif
54 #include <officecfg/Office/Common.hxx>
55 #include <officecfg/Office/Calc.hxx>
56 
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::beans;
59 using namespace ::com::sun::star;
60 
61 AboutDialog::AboutDialog(weld::Window* pParent)
62     : m_xBuilder(Application::CreateBuilder(pParent, "cui/ui/aboutdialog.ui"))
63     , m_xDialog(m_xBuilder->weld_about_dialog("AboutDialog"))
64     , m_xContentArea(m_xDialog->weld_content_area())
65 {
66     m_xDialog->add_button(GetStandardText(StandardButtonType::Close), RET_CLOSE);
67     m_xDialog->add_button(CuiResId(RID_SVXSTR_ABOUT_CREDITS), 101);
68     m_xDialog->add_button(CuiResId(RID_SVXSTR_ABOUT_WEBSITE), 102);
69     m_xDialog->add_button(CuiResId(RID_SVXSTR_ABOUT_RELEASE_NOTES), 103);
70 
71     m_xCreditsButton.reset(m_xDialog->weld_widget_for_response(101));
72     m_xCreditsButton->set_secondary(true);
73     m_xWebsiteButton.reset(m_xDialog->weld_widget_for_response(102));
74     m_xWebsiteButton->set_secondary(true);
75     m_xReleaseNotesButton.reset(m_xDialog->weld_widget_for_response(103));
76     m_xReleaseNotesButton->set_secondary(true);
77     m_xCloseButton.reset(m_xDialog->weld_widget_for_response(RET_CLOSE));
78 
79     m_buildIdLinkString = m_xDialog->get_website_label();
80 
81     m_xDialog->set_version(GetVersionString());
82     m_xDialog->set_copyright(GetCopyrightString());
83 
84     SetBuildIdLink();
85 
86     SetLogo();
87 
88     m_xDialog->connect_size_allocate(LINK(this, AboutDialog, SizeAllocHdl));
89 
90     // Connect all handlers
91     m_xCreditsButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) );
92     m_xWebsiteButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) );
93     m_xReleaseNotesButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) );
94     m_xCloseButton->grab_focus();
95 }
96 
97 AboutDialog::~AboutDialog()
98 {
99 }
100 
101 IMPL_LINK(AboutDialog, HandleClick, weld::Button&, rButton, void)
102 {
103     OUString sURL = "";
104 
105     // Find which button was pressed and from this, get the URL to be opened
106     if (&rButton == m_xCreditsButton.get())
107         sURL = CuiResId(RID_SVXSTR_ABOUT_CREDITS_URL);
108     else if (&rButton == m_xWebsiteButton.get())
109     {
110         sURL = officecfg::Office::Common::Help::StartCenter::InfoURL::get();
111         localizeWebserviceURI(sURL);
112     }
113     else if (&rButton == m_xReleaseNotesButton.get())
114     {
115         sURL = officecfg::Office::Common::Menus::ReleaseNotesURL::get() +
116                "?LOvers=" + utl::ConfigManager::getProductVersion() +
117                "&LOlocale=" + LanguageTag(utl::ConfigManager::getUILocale()).getLanguage();
118     }
119 
120     // If the URL is empty, don't do anything
121     if ( sURL.isEmpty() )
122         return;
123     try
124     {
125         Reference< css::system::XSystemShellExecute > xSystemShellExecute(
126             css::system::SystemShellExecute::create(::comphelper::getProcessComponentContext() ) );
127         xSystemShellExecute->execute( sURL, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY );
128     }
129     catch (const Exception&)
130     {
131         Any exc( ::cppu::getCaughtException() );
132         OUString msg( ::comphelper::anyToString( exc ) );
133         const SolarMutexGuard guard;
134         std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(getDialog(),
135                                                        VclMessageType::Warning, VclButtonsType::Ok, msg));
136         xErrorBox->set_title(m_xDialog->get_title());
137         xErrorBox->run();
138     }
139 }
140 
141 void AboutDialog::SetBuildIdLink()
142 {
143     const OUString buildId = GetBuildId();
144 
145     if (IsStringValidGitHash(buildId))
146     {
147         if (m_buildIdLinkString.indexOf("$GITHASH") == -1)
148         {
149             SAL_WARN( "cui.dialogs", "translated git hash string in translations doesn't contain $GITHASH placeholder" );
150             m_buildIdLinkString += " $GITHASH";
151         }
152 
153         m_xDialog->set_website_label(m_buildIdLinkString.replaceAll("$GITHASH", buildId));
154         m_xDialog->set_website("https://hub.libreoffice.org/git-core/" + buildId);
155     }
156     else
157     {
158         m_xDialog->set_website_label(OUString());
159         m_xDialog->set_website(OUString());
160     }
161 }
162 
163 void AboutDialog::SetLogo()
164 {
165     auto nWidth = m_xContentArea->get_preferred_size().Width();
166 
167     // fdo#67401 set AntiAliasing for SVG logo
168     SvtOptionsDrawinglayer aDrawOpt;
169     bool bOldAntiAliasSetting = aDrawOpt.IsAntiAliasing();
170     aDrawOpt.SetAntiAliasing(true);
171 
172     // load svg logo, specify desired width, scale height isotropically
173     SfxApplication::loadBrandSvg("flat_logo", aLogoBitmap, nWidth);
174 
175     aDrawOpt.SetAntiAliasing(bOldAntiAliasSetting);
176 
177     if (!aLogoBitmap)
178         m_xDialog->set_logo(nullptr);
179     else
180     {
181         Graphic aGraphic(aLogoBitmap);
182         m_xDialog->set_logo(aGraphic.GetXGraphic());
183     }
184 }
185 
186 IMPL_LINK(AboutDialog, SizeAllocHdl, const Size&, rSize, void)
187 {
188     if (rSize.Width() == aBackgroundBitmap.GetSizePixel().Width())
189         return;
190     // Load background image
191     if (!(Application::GetSettings().GetStyleSettings().GetHighContrastMode()))
192     {
193         SfxApplication::loadBrandSvg("shell/about", aBackgroundBitmap, rSize.Width());
194         Graphic aGraphic(aBackgroundBitmap);
195         m_xDialog->set_background(aGraphic.GetXGraphic());
196     }
197 }
198 
199 OUString AboutDialog::GetBuildId()
200 {
201     OUString sDefault;
202     OUString sBuildId(utl::Bootstrap::getBuildVersion(sDefault));
203     if (!sBuildId.isEmpty())
204         return sBuildId;
205 
206     sBuildId = utl::Bootstrap::getBuildIdData(sDefault);
207 
208     if (!sBuildId.isEmpty())
209     {
210         return sBuildId.getToken( 0, '-' );
211     }
212 
213     OSL_ENSURE( !sBuildId.isEmpty(), "No BUILDID in bootstrap file" );
214     return sBuildId;
215 }
216 
217 OUString AboutDialog::GetLocaleString()
218 {
219     OUString aLocaleStr;
220     rtl_Locale * pLocale;
221 
222     osl_getProcessLocale( &pLocale );
223 
224     if ( pLocale && pLocale->Language )
225     {
226         if (pLocale->Country && rtl_uString_getLength( pLocale->Country) > 0)
227             aLocaleStr = OUString(pLocale->Language) + "_" + OUString(pLocale->Country);
228         else
229             aLocaleStr = OUString(pLocale->Language);
230         if (pLocale->Variant && rtl_uString_getLength( pLocale->Variant) > 0)
231             aLocaleStr += OUString(pLocale->Variant);
232     }
233 
234     return aLocaleStr;
235 }
236 
237 bool AboutDialog::IsStringValidGitHash(const OUString& hash)
238 {
239     for (int i = 0; i < hash.getLength(); i++)
240     {
241         if (!rtl::isAsciiHexDigit(hash[i]))
242         {
243             return false;
244         }
245     }
246 
247     return true;
248 }
249 
250 OUString AboutDialog::GetVersionString()
251 {
252     OUString sVersion = CuiResId(RID_SVXSTR_ABOUT_VERSION);
253 
254 #ifdef _WIN64
255     sVersion += " (x64)";
256 #elif defined(_WIN32)
257     sVersion += " (x86)";
258 #endif
259 
260     OUString sBuildId = GetBuildId();
261 
262     OUString aLocaleStr = Application::GetSettings().GetLanguageTag().getBcp47() + " (" + GetLocaleString() + ")";
263     OUString aUILocaleStr = Application::GetSettings().GetUILanguageTag().getBcp47();
264 
265     if (!sBuildId.trim().isEmpty())
266     {
267         sVersion += "\n";
268         OUString sBuildStr = CuiResId(RID_SVXSTR_ABOUT_BUILDID);
269         if (sBuildStr.indexOf("$BUILDID") == -1)
270         {
271             SAL_WARN( "cui.dialogs", "translated Build Id string in translations doesn't contain $BUILDID placeholder" );
272             sBuildStr += " $BUILDID";
273         }
274         sVersion += sBuildStr.replaceAll("$BUILDID", sBuildId);
275     }
276 
277     sVersion += "\n" + Application::GetHWOSConfInfo();
278 
279     bool const extra = EXTRA_BUILDID[0] != '\0';
280         // extracted from the 'if' to avoid Clang -Wunreachable-code
281     if (extra)
282     {
283         sVersion += "\n" EXTRA_BUILDID;
284     }
285 
286     OUString sLocaleStr(CuiResId(RID_SVXSTR_ABOUT_LOCALE));
287     if (sLocaleStr.indexOf("$LOCALE") == -1)
288     {
289         SAL_WARN( "cui.dialogs", "translated locale string in translations doesn't contain $LOCALE placeholder" );
290         sLocaleStr += " $LOCALE";
291     }
292     sVersion += "\n" + sLocaleStr.replaceAll("$LOCALE", aLocaleStr);
293 
294     OUString sUILocaleStr(CuiResId(RID_SVXSTR_ABOUT_UILOCALE));
295     if (sUILocaleStr.indexOf("$LOCALE") == -1)
296     {
297         SAL_WARN( "cui.dialogs", "translated uilocale string in translations doesn't contain $LOCALE placeholder" );
298         sUILocaleStr += " $LOCALE";
299     }
300     sVersion += "; " + sUILocaleStr.replaceAll("$LOCALE", aUILocaleStr);
301 
302     OUString aCalcMode = "Calc: "; // Calc calculation mode
303 
304 #if HAVE_FEATURE_OPENCL
305     bool bOpenCL = openclwrapper::GPUEnv::isOpenCLEnabled();
306     if (bOpenCL)
307         aCalcMode += "CL";
308 #else
309     const bool bOpenCL = false;
310 #endif
311 
312     static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION");
313     bool bThreadedCalc = officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get();
314 
315     if (!bThreadingProhibited && !bOpenCL && bThreadedCalc)
316     {
317         if (!aCalcMode.endsWith(" "))
318             aCalcMode += " ";
319         aCalcMode += "threaded";
320     }
321 
322     sVersion += "\n" + aCalcMode;
323 
324     return sVersion;
325 }
326 
327 OUString AboutDialog::GetCopyrightString()
328 {
329     OUString sVendorTextStr(CuiResId(RID_SVXSTR_ABOUT_VENDOR));
330     OUString aCopyrightString  = sVendorTextStr + "\n"
331                                + CuiResId(RID_SVXSTR_ABOUT_COPYRIGHT) + "\n";
332 
333     if (utl::ConfigManager::getProductName() == "LibreOffice")
334         aCopyrightString += CuiResId(RID_SVXSTR_ABOUT_BASED_ON);
335     else
336         aCopyrightString += CuiResId(RID_SVXSTR_ABOUT_DERIVED);
337 
338     return aCopyrightString;
339 }
340 
341 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
342