1
/***************************************************************************
2
* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
27
# include <QApplication>
33
# include <QProcessEnvironment>
34
# include <QRegularExpression>
35
# include <QRegularExpressionMatch>
39
# include <QTextBrowser>
40
# include <QTextStream>
41
# include <QWaitCondition>
42
# include <Inventor/C/basic.h>
45
#include <App/Application.h>
46
#include <App/Metadata.h>
47
#include <Base/Console.h>
48
#include <CXX/WrapPython.h>
50
#include <boost/filesystem.hpp>
51
#include <LibraryVersions.h>
54
#include "Splashscreen.h"
55
#include "ui_AboutApplication.h"
56
#include "MainWindow.h"
60
using namespace Gui::Dialog;
61
namespace fs = boost::filesystem;
65
QString prettyProductInfoWrapper()
67
auto productName = QSysInfo::prettyProductName();
68
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
70
auto macosVersionFile = QString::fromUtf8("/System/Library/CoreServices/.SystemVersionPlatform.plist");
71
auto fi = QFileInfo (macosVersionFile);
72
if (fi.exists() && fi.isReadable()) {
73
auto plistFile = QFile(macosVersionFile);
74
plistFile.open(QIODevice::ReadOnly);
75
while (!plistFile.atEnd()) {
76
auto line = plistFile.readLine();
77
if (line.contains("ProductUserVisibleVersion")) {
78
auto nextLine = plistFile.readLine();
79
if (nextLine.contains("<string>")) {
80
QRegularExpression re(QString::fromUtf8("\\s*<string>(.*)</string>"));
81
auto matches = re.match(QString::fromUtf8(nextLine));
82
if (matches.hasMatch()) {
83
productName = QString::fromUtf8("macOS ") + matches.captured(1);
93
QSettings regKey {QString::fromUtf8("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), QSettings::NativeFormat};
94
if (regKey.contains(QString::fromUtf8("CurrentBuildNumber"))) {
95
auto buildNumber = regKey.value(QString::fromUtf8("CurrentBuildNumber")).toInt();
96
if (buildNumber > 0) {
97
if (buildNumber < 9200) {
98
productName = QString::fromUtf8("Windows 7 build %1").arg(buildNumber);
100
else if (buildNumber < 10240) {
101
productName = QString::fromUtf8("Windows 8 build %1").arg(buildNumber);
103
else if (buildNumber < 22000) {
104
productName = QString::fromUtf8("Windows 10 build %1").arg(buildNumber);
107
productName = QString::fromUtf8("Windows 11 build %1").arg(buildNumber);
115
/** Displays all messages at startup inside the splash screen.
116
* \author Werner Mayer
118
class SplashObserver : public Base::ILogger
121
SplashObserver(const SplashObserver&) = delete;
122
SplashObserver(SplashObserver&&) = delete;
123
SplashObserver& operator= (const SplashObserver&) = delete;
124
SplashObserver& operator= (SplashObserver&&) = delete;
126
explicit SplashObserver(QSplashScreen* splasher=nullptr)
128
, alignment(Qt::AlignBottom|Qt::AlignLeft)
129
, textColor(Qt::black)
131
Base::Console().AttachObserver(this);
133
// allow to customize text position and color
134
const std::map<std::string,std::string>& cfg = App::Application::Config();
135
auto al = cfg.find("SplashAlignment");
136
if (al != cfg.end()) {
137
QString alt = QString::fromLatin1(al->second.c_str());
139
if (alt.startsWith(QLatin1String("VCenter"))) {
140
align = Qt::AlignVCenter;
142
else if (alt.startsWith(QLatin1String("Top"))) {
143
align = Qt::AlignTop;
146
align = Qt::AlignBottom;
149
if (alt.endsWith(QLatin1String("HCenter"))) {
150
align += Qt::AlignHCenter;
152
else if (alt.endsWith(QLatin1String("Right"))) {
153
align += Qt::AlignRight;
156
align += Qt::AlignLeft;
163
auto tc = cfg.find("SplashTextColor");
164
if (tc != cfg.end()) {
165
QColor col; col.setNamedColor(QString::fromLatin1(tc->second.c_str()));
171
~SplashObserver() override
173
Base::Console().DetachObserver(this);
175
const char* Name() override
177
return "SplashObserver";
179
void SendLog(const std::string& notifiername, const std::string& msg, Base::LogStyle level,
180
Base::IntendedRecipient recipient, Base::ContentType content) override
182
Q_UNUSED(notifiername)
190
if (level == Base::LogStyle::Log) {
195
void Log (const char * text)
197
QString msg(QString::fromUtf8(text));
198
QRegularExpression rx;
199
// ignore 'Init:' and 'Mod:' prefixes
200
rx.setPattern(QLatin1String("^\\s*(Init:|Mod:)\\s*"));
201
auto match = rx.match(msg);
202
if (match.hasMatch()) {
203
msg = msg.mid(match.capturedLength());
206
// ignore activation of commands
207
rx.setPattern(QLatin1String(R"(^\s*(\+App::|Create|CmdC:|CmdG:|Act:)\s*)"));
208
match = rx.match(msg);
209
if (match.hasMatch() && match.capturedStart() == 0)
213
splash->showMessage(msg.replace(QLatin1String("\n"), QString()), alignment, textColor);
215
QMutexLocker ml(&mutex);
216
QWaitCondition().wait(&mutex, 50);
220
QSplashScreen* splash;
226
// ------------------------------------------------------------------------------
229
* Constructs a splash screen that will display the pixmap.
231
SplashScreen::SplashScreen( const QPixmap & pixmap , Qt::WindowFlags f )
232
: QSplashScreen(pixmap, f)
234
// write the messages to splasher
235
messages = new SplashObserver(this);
239
SplashScreen::~SplashScreen()
245
* Draws the contents of the splash screen using painter \a painter. The default
246
* implementation draws the message passed by message().
248
void SplashScreen::drawContents ( QPainter * painter )
250
QSplashScreen::drawContents(painter);
253
void SplashScreen::setShowMessages(bool on)
261
// ------------------------------------------------------------------------------
263
AboutDialogFactory* AboutDialogFactory::factory = nullptr;
265
AboutDialogFactory::~AboutDialogFactory() = default;
267
QDialog *AboutDialogFactory::create(QWidget *parent) const
269
#ifdef _USE_3DCONNEXION_SDK
270
return new AboutDialog(true, parent);
272
return new AboutDialog(false, parent);
276
const AboutDialogFactory *AboutDialogFactory::defaultFactory()
278
static const AboutDialogFactory this_factory;
281
return &this_factory;
284
void AboutDialogFactory::setDefaultFactory(AboutDialogFactory *f)
291
// ------------------------------------------------------------------------------
293
/* TRANSLATOR Gui::Dialog::AboutDialog */
296
* Constructs an AboutDialog which is a child of 'parent', with the
297
* name 'name' and widget flags set to 'WStyle_Customize|WStyle_NoBorder|WType_Modal'
299
* The dialog will be modal.
301
AboutDialog::AboutDialog(bool showLic, QWidget* parent)
302
: QDialog(parent), ui(new Ui_AboutApplication)
308
connect(ui->copyButton, &QPushButton::clicked,
309
this, &AboutDialog::copyToClipboard);
311
// remove the automatic help button in dialog title since we don't use it
312
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
314
layout()->setSizeConstraint(QLayout::SetFixedSize);
315
QRect rect = QApplication::primaryScreen()->availableGeometry();
317
// See if we have a custom About screen image set
318
QPixmap image = getMainWindow()->aboutImage();
320
// Fallback to the splashscreen image
321
if (image.isNull()) {
322
image = getMainWindow()->splashImage();
325
// Make sure the image is not too big
327
if (image.height() > rect.height()/denom || image.width() > rect.width()/denom) {
328
float scale = static_cast<float>(image.width()) / static_cast<float>(image.height());
329
int width = std::min(image.width(), rect.width()/denom);
330
int height = std::min(image.height(), rect.height()/denom);
331
height = std::min(height, static_cast<int>(width / scale));
332
width = static_cast<int>(scale * height);
334
image = image.scaled(width, height);
336
ui->labelSplashPicture->setPixmap(image);
337
ui->tabWidget->setCurrentIndex(0); // always start on the About tab
341
showLicenseInformation();
342
showLibraryInformation();
343
showCollectionInformation();
344
showOrHideImage(rect);
348
* Destroys the object and frees any allocated resources
350
AboutDialog::~AboutDialog()
352
// no need to delete child widgets, Qt does it all for us
356
void AboutDialog::showOrHideImage(const QRect& rect)
359
if (height() > rect.height()) {
360
ui->labelSplashPicture->hide();
364
void AboutDialog::setupLabels()
366
//fonts are rendered smaller on Mac so point size can't be the same for all platforms
371
//avoid overriding user set style sheet
372
if (qApp->styleSheet().isEmpty()) {
373
setStyleSheet(QString::fromLatin1("Gui--Dialog--AboutDialog QLabel {font-size: %1pt;}").arg(fontSize));
376
QString exeName = qApp->applicationName();
377
std::map<std::string, std::string>& config = App::Application::Config();
378
std::map<std::string,std::string>::iterator it;
379
QString banner = QString::fromUtf8(config["CopyrightInfo"].c_str());
380
banner = banner.left( banner.indexOf(QLatin1Char('\n')) );
381
QString major = QString::fromLatin1(config["BuildVersionMajor"].c_str());
382
QString minor = QString::fromLatin1(config["BuildVersionMinor"].c_str());
383
QString point = QString::fromLatin1(config["BuildVersionPoint"].c_str());
384
QString suffix = QString::fromLatin1(config["BuildVersionSuffix"].c_str());
385
QString build = QString::fromLatin1(config["BuildRevision"].c_str());
386
QString disda = QString::fromLatin1(config["BuildRevisionDate"].c_str());
387
QString mturl = QString::fromLatin1(config["MaintainerUrl"].c_str());
389
// we use replace() to keep label formatting, so a label with text "<b>Unknown</b>"
390
// gets replaced to "<b>FreeCAD</b>", for example
392
QString author = ui->labelAuthor->text();
393
author.replace(QString::fromLatin1("Unknown Application"), exeName);
394
author.replace(QString::fromLatin1("(c) Unknown Author"), banner);
395
ui->labelAuthor->setText(author);
396
ui->labelAuthor->setUrl(mturl);
398
if (qApp->styleSheet().isEmpty()) {
399
ui->labelAuthor->setStyleSheet(QString::fromLatin1("Gui--UrlLabel {color: #0000FF;text-decoration: underline;font-weight: 600;}"));
402
QString version = ui->labelBuildVersion->text();
403
version.replace(QString::fromLatin1("Unknown"), QString::fromLatin1("%1.%2.%3%4").arg(major, minor, point, suffix));
404
ui->labelBuildVersion->setText(version);
406
QString revision = ui->labelBuildRevision->text();
407
revision.replace(QString::fromLatin1("Unknown"), build);
408
ui->labelBuildRevision->setText(revision);
410
QString date = ui->labelBuildDate->text();
411
date.replace(QString::fromLatin1("Unknown"), disda);
412
ui->labelBuildDate->setText(date);
414
QString os = ui->labelBuildOS->text();
415
os.replace(QString::fromLatin1("Unknown"), prettyProductInfoWrapper());
416
ui->labelBuildOS->setText(os);
418
QString platform = ui->labelBuildPlatform->text();
419
platform.replace(QString::fromLatin1("Unknown"),
420
QString::fromLatin1("%1-bit").arg(QSysInfo::WordSize));
421
ui->labelBuildPlatform->setText(platform);
424
it = config.find("BuildRevisionBranch");
425
if (it != config.end()) {
426
QString branch = ui->labelBuildBranch->text();
427
branch.replace(QString::fromLatin1("Unknown"), QString::fromUtf8(it->second.c_str()));
428
ui->labelBuildBranch->setText(branch);
431
ui->labelBranch->hide();
432
ui->labelBuildBranch->hide();
436
it = config.find("BuildRevisionHash");
437
if (it != config.end()) {
438
QString hash = ui->labelBuildHash->text();
439
hash.replace(QString::fromLatin1("Unknown"), QString::fromLatin1(it->second.c_str()).left(7)); // Use the 7-char abbreviated hash
440
ui->labelBuildHash->setText(hash);
441
if (auto url_itr = config.find("BuildRepositoryURL"); url_itr != config.end()) {
442
auto url = QString::fromStdString(url_itr->second);
444
if (int space = url.indexOf(QChar::fromLatin1(' ')); space != -1)
445
url = url.left(space); // Strip off the branch information to get just the repo
447
if (url == QString::fromUtf8("Unknown"))
448
url = QString::fromUtf8("https://github.com/FreeCAD/FreeCAD"); // Just take a guess
450
// This may only create valid URLs for Github, but some other hosts use the same format so give it a shot...
451
auto https = url.replace(QString::fromUtf8("git://"), QString::fromUtf8("https://"));
452
https.replace(QString::fromUtf8(".git"), QString::fromUtf8(""));
453
ui->labelBuildHash->setUrl(https + QString::fromUtf8("/commit/") + QString::fromStdString(it->second));
457
ui->labelHash->hide();
458
ui->labelBuildHash->hide();
462
class AboutDialog::LibraryInfo {
470
void AboutDialog::showCredits()
472
auto creditsFileURL = QLatin1String(":/doc/CONTRIBUTORS");
473
QFile creditsFile(creditsFileURL);
475
if (!creditsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
479
auto tab_credits = new QWidget();
480
tab_credits->setObjectName(QString::fromLatin1("tab_credits"));
481
ui->tabWidget->addTab(tab_credits, tr("Credits"));
482
auto hlayout = new QVBoxLayout(tab_credits);
483
auto textField = new QTextBrowser(tab_credits);
484
textField->setOpenExternalLinks(false);
485
textField->setOpenLinks(false);
486
hlayout->addWidget(textField);
488
QString creditsHTML = QString::fromLatin1("<html><body><h1>");
489
//: Header for the Credits tab of the About screen
490
creditsHTML += tr("Credits");
491
creditsHTML += QString::fromLatin1("</h1><p>");
492
creditsHTML += tr("FreeCAD would not be possible without the contributions of");
493
creditsHTML += QString::fromLatin1(":</p><h2>");
494
//: Header for the list of individual people in the Credits list.
495
creditsHTML += tr("Individuals");
496
creditsHTML += QString::fromLatin1("</h2><ul>");
498
QTextStream stream(&creditsFile);
499
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
500
stream.setCodec("UTF-8");
503
while (stream.readLineInto(&line)) {
504
if (!line.isEmpty()) {
505
if (line == QString::fromLatin1("Firms")) {
506
creditsHTML += QString::fromLatin1("</ul><h2>");
507
//: Header for the list of companies/organizations in the Credits list.
508
creditsHTML += tr("Organizations");
509
creditsHTML += QString::fromLatin1("</h2><ul>");
512
creditsHTML += QString::fromLatin1("<li>") + line + QString::fromLatin1("</li>");
516
creditsHTML += QString::fromLatin1("</ul></body></html>");
517
textField->setHtml(creditsHTML);
520
void AboutDialog::showLicenseInformation()
522
QString licenseFileURL = QString::fromLatin1("%1/LICENSE.html")
523
.arg(QString::fromUtf8(App::Application::getHelpDir().c_str()));
524
QFile licenseFile(licenseFileURL);
526
if (licenseFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
527
QString licenseHTML = QString::fromUtf8(licenseFile.readAll());
528
const auto placeholder = QString::fromUtf8("<!--PLACEHOLDER_FOR_ADDITIONAL_LICENSE_INFORMATION-->");
529
licenseHTML.replace(placeholder, getAdditionalLicenseInformation());
531
ui->tabWidget->removeTab(1); // Hide the license placeholder widget
533
auto tab_license = new QWidget();
534
tab_license->setObjectName(QString::fromLatin1("tab_license"));
535
ui->tabWidget->addTab(tab_license, tr("License"));
536
auto hlayout = new QVBoxLayout(tab_license);
537
auto textField = new QTextBrowser(tab_license);
538
textField->setOpenExternalLinks(true);
539
textField->setOpenLinks(true);
540
hlayout->addWidget(textField);
542
textField->setHtml(licenseHTML);
545
QString info(QLatin1String("SUCH DAMAGES.<hr/>"));
546
info += getAdditionalLicenseInformation();
547
QString lictext = ui->textBrowserLicense->toHtml();
548
lictext.replace(QString::fromLatin1("SUCH DAMAGES.<hr/>"), info);
549
ui->textBrowserLicense->setHtml(lictext);
553
QString AboutDialog::getAdditionalLicenseInformation() const
555
// Any additional piece of text to be added after the main license text goes below.
556
// Please set title in <h2> tags, license text in <p> tags
557
// and add an <hr/> tag at the end to nicely separate license blocks
559
#ifdef _USE_3DCONNEXION_SDK
560
info += QString::fromUtf8(
561
"<h2>3D Mouse Support</h2>"
562
"<p>Development tools and related technology provided under license from 3Dconnexion.<br/>"
563
"Copyright © 1992–2012 3Dconnexion. All rights reserved.</p>"
570
void AboutDialog::showLibraryInformation()
572
auto tab_library = new QWidget();
573
tab_library->setObjectName(QString::fromLatin1("tab_library"));
574
ui->tabWidget->addTab(tab_library, tr("Libraries"));
575
auto hlayout = new QVBoxLayout(tab_library);
576
auto textField = new QTextBrowser(tab_library);
577
textField->setOpenExternalLinks(false);
578
textField->setOpenLinks(false);
579
hlayout->addWidget(textField);
581
QList<LibraryInfo> libInfo;
582
QString baseurl = QString::fromLatin1("file:///%1/ThirdPartyLibraries.html")
583
.arg(QString::fromUtf8(App::Application::getHelpDir().c_str()));
586
libInfo << LibraryInfo {
587
QLatin1String("Boost"),
588
baseurl + QLatin1String("#_TocBoost"),
589
QLatin1String("https://www.boost.org"),
590
QLatin1String(BOOST_LIB_VERSION)
594
libInfo << LibraryInfo {
595
QLatin1String("Coin3D"),
596
baseurl + QLatin1String("#_TocCoin3D"),
597
QLatin1String("https://coin3d.github.io"),
598
QLatin1String(COIN_VERSION)
602
libInfo << LibraryInfo {
603
QLatin1String("Eigen"),
604
baseurl + QLatin1String("#_TocEigen"),
605
QLatin1String("https://eigen.tuxfamily.org"),
606
QString::fromLatin1(fcEigen3Version)
610
libInfo << LibraryInfo {
611
QLatin1String("FreeType"),
612
baseurl + QLatin1String("#_TocFreeType"),
613
QLatin1String("https://freetype.org"),
614
QString::fromLatin1(fcFreetypeVersion)
618
libInfo << LibraryInfo {
619
QLatin1String("KDL"),
620
baseurl + QLatin1String("#_TocKDL"),
621
QLatin1String("https://www.orocos.org/kdl"),
626
libInfo << LibraryInfo {
627
QLatin1String("libarea"),
628
baseurl + QLatin1String("#_TocLibArea"),
629
QLatin1String("https://github.com/danielfalck/libarea"),
634
#if defined(HAVE_OCC_VERSION)
635
libInfo << LibraryInfo {
636
QLatin1String("Open CASCADE Technology"),
637
baseurl + QLatin1String("#_TocOCCT"),
638
QLatin1String("https://www.opencascade.com/open-cascade-technology/"),
639
QLatin1String(OCC_VERSION_STRING_EXT)
644
libInfo << LibraryInfo {
645
QLatin1String("Point Cloud Library"),
646
baseurl + QLatin1String("#_TocPcl"),
647
QLatin1String("https://www.pointclouds.org"),
648
QString::fromLatin1(fcPclVersion)
652
libInfo << LibraryInfo {
653
QLatin1String("PyCXX"),
654
baseurl + QLatin1String("#_TocPyCXX"),
655
QLatin1String("http://cxx.sourceforge.net"),
656
QString::fromLatin1(fcPycxxVersion)
660
libInfo << LibraryInfo {
661
QLatin1String("Python"),
662
baseurl + QLatin1String("#_TocPython"),
663
QLatin1String("https://www.python.org"),
664
QLatin1String(PY_VERSION)
668
libInfo << LibraryInfo {
669
QLatin1String("Qt for Python (PySide)"),
670
baseurl + QLatin1String("#_TocPySide"),
671
QLatin1String("https://wiki.qt.io/Qt_for_Python"),
672
QString::fromLatin1(fcPysideVersion)
676
libInfo << LibraryInfo {
678
baseurl + QLatin1String("#_TocQt"),
679
QLatin1String("https://www.qt.io"),
680
QLatin1String(QT_VERSION_STR)
684
libInfo << LibraryInfo {
685
QLatin1String("Salome SMESH"),
686
baseurl + QLatin1String("#_TocSalomeSMESH"),
687
QLatin1String("https://salome-platform.org"),
688
#ifdef SMESH_VERSION_STR
689
QLatin1String(SMESH_VERSION_STR)
696
libInfo << LibraryInfo {
697
QLatin1String("Qt for Python (Shiboken)"),
698
baseurl + QLatin1String("#_TocPySide"),
699
QLatin1String("https://wiki.qt.io/Qt_for_Python"),
700
QString::fromLatin1(fcShibokenVersion)
704
libInfo << LibraryInfo {
705
QLatin1String("vtk"),
706
baseurl + QLatin1String("#_TocVtk"),
707
QLatin1String("https://www.vtk.org"),
708
QString::fromLatin1(fcVtkVersion)
712
libInfo << LibraryInfo {
713
QLatin1String("Xerces-C"),
714
baseurl + QLatin1String("#_TocXercesC"),
715
QLatin1String("https://xerces.apache.org/xerces-c"),
716
QString::fromLatin1(fcXercescVersion)
720
libInfo << LibraryInfo {
721
QLatin1String("Zipios++"),
722
baseurl + QLatin1String("#_TocZipios"),
723
QLatin1String("http://zipios.sourceforge.net"),
728
libInfo << LibraryInfo {
729
QLatin1String("zlib"),
730
baseurl + QLatin1String("#_TocZlib"),
731
QLatin1String("https://zlib.net"),
732
QLatin1String(ZLIB_VERSION)
736
QString msg = tr("This software uses open source components whose copyright and other "
737
"proprietary rights belong to their respective owners:");
739
QTextStream out(&html);
740
out << "<html><head/><body style=\" font-size:8.25pt; font-weight:400; font-style:normal;\">"
741
<< "<p>" << msg << "<br/></p>\n<ul>\n";
742
for (const auto & it : libInfo) {
743
out << "<li><p>" << it.name << " " << it.version << "</p>"
744
"<p><a href=\"" << it.href << "\">" << it.url
745
<< "</a><br/></p></li>\n";
747
out << "</ul>\n</body>\n</html>";
748
textField->setHtml(html);
750
connect(textField, &QTextBrowser::anchorClicked, this, &AboutDialog::linkActivated);
753
void AboutDialog::showCollectionInformation()
755
QString doc = QString::fromUtf8(App::Application::getHelpDir().c_str());
756
QString path = doc + QLatin1String("Collection.html");
757
if (!QFile::exists(path))
760
auto tab_collection = new QWidget();
761
tab_collection->setObjectName(QString::fromLatin1("tab_collection"));
762
ui->tabWidget->addTab(tab_collection, tr("Collection"));
763
auto hlayout = new QVBoxLayout(tab_collection);
764
auto textField = new QTextBrowser(tab_collection);
765
textField->setOpenExternalLinks(true);
766
hlayout->addWidget(textField);
767
textField->setSource(path);
770
void AboutDialog::linkActivated(const QUrl& link)
772
auto licenseView = new LicenseView();
773
licenseView->setAttribute(Qt::WA_DeleteOnClose);
775
QString title = tr("License");
776
QString fragment = link.fragment();
777
if (fragment.startsWith(QLatin1String("_Toc"))) {
778
QString prefix = fragment.mid(4);
779
title = QString::fromLatin1("%1 %2").arg(prefix, title);
781
licenseView->setWindowTitle(title);
782
getMainWindow()->addWindow(licenseView);
783
licenseView->setSource(link);
786
void AboutDialog::copyToClipboard()
789
QTextStream str(&data);
790
std::map<std::string, std::string>& config = App::Application::Config();
791
std::map<std::string,std::string>::iterator it;
792
QString exe = QString::fromStdString(App::Application::getExecutableName());
794
QString major = QString::fromLatin1(config["BuildVersionMajor"].c_str());
795
QString minor = QString::fromLatin1(config["BuildVersionMinor"].c_str());
796
QString point = QString::fromLatin1(config["BuildVersionPoint"].c_str());
797
QString suffix = QString::fromLatin1(config["BuildVersionSuffix"].c_str());
798
QString build = QString::fromLatin1(config["BuildRevision"].c_str());
800
QString deskEnv = QProcessEnvironment::systemEnvironment().value(QStringLiteral("XDG_CURRENT_DESKTOP"), QString());
801
QString deskSess = QProcessEnvironment::systemEnvironment().value(QStringLiteral("DESKTOP_SESSION"), QString());
804
if ( !(deskEnv.isEmpty() && deskSess.isEmpty()) ) {
805
if ( deskEnv.isEmpty() || deskSess.isEmpty() )
806
deskInfo = QLatin1String(" (") + deskEnv + deskSess + QLatin1String(")");
808
deskInfo = QLatin1String(" (") + deskEnv + QLatin1String("/") + deskSess + QLatin1String(")");
811
str << "OS: " << prettyProductInfoWrapper() << deskInfo << '\n';
812
str << "Word size of " << exe << ": " << QSysInfo::WordSize << "-bit\n";
813
str << "Version: " << major << "." << minor << "." << point << suffix << "." << build;
814
char *appimage = getenv("APPIMAGE");
817
char* snap = getenv("SNAP_REVISION");
819
str << " Snap " << snap;
822
#if defined(_DEBUG) || defined(DEBUG)
823
str << "Build type: Debug\n";
825
str << "Build type: Release\n";
826
#elif defined(CMAKE_BUILD_TYPE)
827
str << "Build type: " << CMAKE_BUILD_TYPE << '\n';
829
str << "Build type: Unknown\n";
831
it = config.find("BuildRevisionBranch");
832
if (it != config.end())
833
str << "Branch: " << QString::fromUtf8(it->second.c_str()) << '\n';
834
it = config.find("BuildRevisionHash");
835
if (it != config.end())
836
str << "Hash: " << it->second.c_str() << '\n';
837
// report also the version numbers of the most important libraries in FreeCAD
838
str << "Python " << PY_VERSION << ", ";
839
str << "Qt " << QT_VERSION_STR << ", ";
840
str << "Coin " << COIN_VERSION << ", ";
841
str << "Vtk " << fcVtkVersion << ", ";
842
#if defined(HAVE_OCC_VERSION)
844
<< OCC_VERSION_MAJOR << "."
845
<< OCC_VERSION_MINOR << "."
846
<< OCC_VERSION_MAINTENANCE
847
#ifdef OCC_VERSION_DEVELOPMENT
848
<< "." OCC_VERSION_DEVELOPMENT
853
str << "Locale: " << loc.languageToString(loc.language()) << "/"
854
<< loc.countryToString(loc.country())
855
<< " (" << loc.name() << ")";
856
if (loc != QLocale::system()) {
857
loc = QLocale::system();
858
str << " [ OS: " << loc.languageToString(loc.language()) << "/"
859
<< loc.countryToString(loc.country())
860
<< " (" << loc.name() << ") ]";
864
// Add installed module information:
865
auto modDir = fs::path(App::Application::getUserAppDataDir()) / "Mod";
866
bool firstMod = true;
867
if (fs::exists(modDir) && fs::is_directory(modDir)) {
868
for (const auto& mod : fs::directory_iterator(modDir)) {
869
auto dirName = mod.path().filename().string();
870
if (dirName[0] == '.') // Ignore dot directories
874
str << "Installed mods: \n";
876
str << " * " << QString::fromStdString(mod.path().filename().string());
877
auto metadataFile = mod.path() / "package.xml";
878
if (fs::exists(metadataFile)) {
879
App::Metadata metadata(metadataFile);
880
if (metadata.version() != App::Meta::Version())
881
str << QLatin1String(" ") + QString::fromStdString(metadata.version().str());
883
auto disablingFile = mod.path() / "ADDON_DISABLED";
884
if (fs::exists(disablingFile))
885
str << " (Disabled)";
891
QClipboard* cb = QApplication::clipboard();
895
// ----------------------------------------------------------------------------
897
/* TRANSLATOR Gui::LicenseView */
899
LicenseView::LicenseView(QWidget* parent)
900
: MDIView(nullptr,parent,Qt::WindowFlags())
902
browser = new QTextBrowser(this);
903
browser->setOpenExternalLinks(true);
904
browser->setOpenLinks(true);
905
setCentralWidget(browser);
908
LicenseView::~LicenseView() = default;
910
void LicenseView::setSource(const QUrl& url)
912
browser->setSource(url);
915
#include "moc_Splashscreen.cpp"