FreeCAD

Форк
0
/
Splashscreen.cpp 
915 строк · 31.9 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#ifndef _PreComp_
26
# include <cstdlib>
27
# include <QApplication>
28
# include <QClipboard>
29
# include <QFile>
30
# include <QFileInfo>
31
# include <QLocale>
32
# include <QMutex>
33
# include <QProcessEnvironment>
34
# include <QRegularExpression>
35
# include <QRegularExpressionMatch>
36
# include <QScreen>
37
# include <QSettings>
38
# include <QSysInfo>
39
# include <QTextBrowser>
40
# include <QTextStream>
41
# include <QWaitCondition>
42
# include <Inventor/C/basic.h>
43
#endif
44

45
#include <App/Application.h>
46
#include <App/Metadata.h>
47
#include <Base/Console.h>
48
#include <CXX/WrapPython.h>
49

50
#include <boost/filesystem.hpp>
51
#include <LibraryVersions.h>
52
#include <zlib.h>
53

54
#include "Splashscreen.h"
55
#include "ui_AboutApplication.h"
56
#include "MainWindow.h"
57

58

59
using namespace Gui;
60
using namespace Gui::Dialog;
61
namespace fs = boost::filesystem;
62

63
namespace Gui {
64

65
QString prettyProductInfoWrapper()
66
{
67
    auto productName = QSysInfo::prettyProductName();
68
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
69
#ifdef FC_OS_MACOSX
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);
84
                        break;
85
                    }
86
                }
87
            }
88
        }
89
    }
90
#endif
91
#endif
92
#ifdef FC_OS_WIN64
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);
99
            }
100
            else if (buildNumber < 10240) {
101
                productName = QString::fromUtf8("Windows 8 build %1").arg(buildNumber);
102
            }
103
            else if (buildNumber < 22000) {
104
                productName = QString::fromUtf8("Windows 10 build %1").arg(buildNumber);
105
            }
106
            else {
107
                productName = QString::fromUtf8("Windows 11 build %1").arg(buildNumber);
108
            }
109
        }
110
    }
111
#endif
112
    return productName;
113
}
114

115
/** Displays all messages at startup inside the splash screen.
116
 * \author Werner Mayer
117
 */
118
class SplashObserver : public Base::ILogger
119
{
120
public:
121
    SplashObserver(const SplashObserver&) = delete;
122
    SplashObserver(SplashObserver&&) = delete;
123
    SplashObserver& operator= (const SplashObserver&) = delete;
124
    SplashObserver& operator= (SplashObserver&&) = delete;
125

126
    explicit SplashObserver(QSplashScreen* splasher=nullptr)
127
      : splash(splasher)
128
      , alignment(Qt::AlignBottom|Qt::AlignLeft)
129
      , textColor(Qt::black)
130
    {
131
        Base::Console().AttachObserver(this);
132

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());
138
            int align=0;
139
            if (alt.startsWith(QLatin1String("VCenter"))) {
140
                align = Qt::AlignVCenter;
141
            }
142
            else if (alt.startsWith(QLatin1String("Top"))) {
143
                align = Qt::AlignTop;
144
            }
145
            else {
146
                align = Qt::AlignBottom;
147
            }
148

149
            if (alt.endsWith(QLatin1String("HCenter"))) {
150
                align += Qt::AlignHCenter;
151
            }
152
            else if (alt.endsWith(QLatin1String("Right"))) {
153
                align += Qt::AlignRight;
154
            }
155
            else {
156
                align += Qt::AlignLeft;
157
            }
158

159
            alignment = align;
160
        }
161

162
        // choose text color
163
        auto tc = cfg.find("SplashTextColor");
164
        if (tc != cfg.end()) {
165
            QColor col; col.setNamedColor(QString::fromLatin1(tc->second.c_str()));
166
            if (col.isValid()) {
167
                textColor = col;
168
            }
169
        }
170
    }
171
    ~SplashObserver() override
172
    {
173
        Base::Console().DetachObserver(this);
174
    }
175
    const char* Name() override
176
    {
177
        return "SplashObserver";
178
    }
179
    void SendLog(const std::string& notifiername, const std::string& msg, Base::LogStyle level,
180
                 Base::IntendedRecipient recipient, Base::ContentType content) override
181
    {
182
        Q_UNUSED(notifiername)
183
        Q_UNUSED(recipient)
184
        Q_UNUSED(content)
185

186
#ifdef FC_DEBUG
187
        Log(msg.c_str());
188
        Q_UNUSED(level)
189
#else
190
        if (level == Base::LogStyle::Log) {
191
            Log(msg.c_str());
192
        }
193
#endif
194
    }
195
    void Log (const char * text)
196
    {
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());
204
        }
205
        else {
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)
210
                return;
211
        }
212

213
        splash->showMessage(msg.replace(QLatin1String("\n"), QString()), alignment, textColor);
214
        QMutex mutex;
215
        QMutexLocker ml(&mutex);
216
        QWaitCondition().wait(&mutex, 50);
217
    }
218

219
private:
220
    QSplashScreen* splash;
221
    int alignment;
222
    QColor textColor;
223
};
224
} // namespace Gui
225

226
// ------------------------------------------------------------------------------
227

228
/**
229
 * Constructs a splash screen that will display the pixmap.
230
 */
231
SplashScreen::SplashScreen(  const QPixmap & pixmap , Qt::WindowFlags f )
232
    : QSplashScreen(pixmap, f)
233
{
234
    // write the messages to splasher
235
    messages = new SplashObserver(this);
236
}
237

238
/** Destruction. */
239
SplashScreen::~SplashScreen()
240
{
241
    delete messages;
242
}
243

244
/**
245
 * Draws the contents of the splash screen using painter \a painter. The default
246
 * implementation draws the message passed by message().
247
 */
248
void SplashScreen::drawContents ( QPainter * painter )
249
{
250
    QSplashScreen::drawContents(painter);
251
}
252

253
void SplashScreen::setShowMessages(bool on)
254
{
255
    messages->bErr = on;
256
    messages->bMsg = on;
257
    messages->bLog = on;
258
    messages->bWrn = on;
259
}
260

261
// ------------------------------------------------------------------------------
262

263
AboutDialogFactory* AboutDialogFactory::factory = nullptr;
264

265
AboutDialogFactory::~AboutDialogFactory() = default;
266

267
QDialog *AboutDialogFactory::create(QWidget *parent) const
268
{
269
#ifdef _USE_3DCONNEXION_SDK
270
    return new AboutDialog(true, parent);
271
#else
272
    return new AboutDialog(false, parent);
273
#endif
274
}
275

276
const AboutDialogFactory *AboutDialogFactory::defaultFactory()
277
{
278
    static const AboutDialogFactory this_factory;
279
    if (factory)
280
        return factory;
281
    return &this_factory;
282
}
283

284
void AboutDialogFactory::setDefaultFactory(AboutDialogFactory *f)
285
{
286
    if (factory != f)
287
        delete factory;
288
    factory = f;
289
}
290

291
// ------------------------------------------------------------------------------
292

293
/* TRANSLATOR Gui::Dialog::AboutDialog */
294

295
/**
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'
298
 *
299
 *  The dialog will be modal.
300
 */
301
AboutDialog::AboutDialog(bool showLic, QWidget* parent)
302
  : QDialog(parent), ui(new Ui_AboutApplication)
303
{
304
    Q_UNUSED(showLic);
305

306
    setModal(true);
307
    ui->setupUi(this);
308
    connect(ui->copyButton, &QPushButton::clicked,
309
            this, &AboutDialog::copyToClipboard);
310

311
    // remove the automatic help button in dialog title since we don't use it
312
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
313

314
    layout()->setSizeConstraint(QLayout::SetFixedSize);
315
    QRect rect = QApplication::primaryScreen()->availableGeometry();
316

317
    // See if we have a custom About screen image set
318
    QPixmap image = getMainWindow()->aboutImage();
319

320
    // Fallback to the splashscreen image
321
    if (image.isNull()) {
322
        image = getMainWindow()->splashImage();
323
    }
324

325
    // Make sure the image is not too big
326
    int denom = 2;
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);
333

334
        image = image.scaled(width, height);
335
    }
336
    ui->labelSplashPicture->setPixmap(image);
337
    ui->tabWidget->setCurrentIndex(0); // always start on the About tab
338

339
    setupLabels();
340
    showCredits();
341
    showLicenseInformation();
342
    showLibraryInformation();
343
    showCollectionInformation();
344
    showOrHideImage(rect);
345
}
346

347
/**
348
 *  Destroys the object and frees any allocated resources
349
 */
350
AboutDialog::~AboutDialog()
351
{
352
    // no need to delete child widgets, Qt does it all for us
353
    delete ui;
354
}
355

356
void AboutDialog::showOrHideImage(const QRect& rect)
357
{
358
    adjustSize();
359
    if (height() > rect.height()) {
360
        ui->labelSplashPicture->hide();
361
    }
362
}
363

364
void AboutDialog::setupLabels()
365
{
366
    //fonts are rendered smaller on Mac so point size can't be the same for all platforms
367
    int fontSize = 8;
368
#ifdef Q_OS_MAC
369
    fontSize = 11;
370
#endif
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));
374
    }
375

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());
388

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
391

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);
397

398
    if (qApp->styleSheet().isEmpty()) {
399
        ui->labelAuthor->setStyleSheet(QString::fromLatin1("Gui--UrlLabel {color: #0000FF;text-decoration: underline;font-weight: 600;}"));
400
    }
401

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);
405

406
    QString revision = ui->labelBuildRevision->text();
407
    revision.replace(QString::fromLatin1("Unknown"), build);
408
    ui->labelBuildRevision->setText(revision);
409

410
    QString date = ui->labelBuildDate->text();
411
    date.replace(QString::fromLatin1("Unknown"), disda);
412
    ui->labelBuildDate->setText(date);
413

414
    QString os = ui->labelBuildOS->text();
415
    os.replace(QString::fromLatin1("Unknown"), prettyProductInfoWrapper());
416
    ui->labelBuildOS->setText(os);
417

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);
422

423
    // branch name
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);
429
    }
430
    else {
431
        ui->labelBranch->hide();
432
        ui->labelBuildBranch->hide();
433
    }
434

435
    // hash id
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);
443

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
446

447
            if (url == QString::fromUtf8("Unknown"))
448
                url = QString::fromUtf8("https://github.com/FreeCAD/FreeCAD"); // Just take a guess
449

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));
454
        }
455
    }
456
    else {
457
        ui->labelHash->hide();
458
        ui->labelBuildHash->hide();
459
    }
460
}
461

462
class AboutDialog::LibraryInfo {
463
public:
464
    QString name;
465
    QString href;
466
    QString url;
467
    QString version;
468
};
469

470
void AboutDialog::showCredits()
471
{
472
    auto creditsFileURL = QLatin1String(":/doc/CONTRIBUTORS");
473
    QFile creditsFile(creditsFileURL);
474

475
    if (!creditsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
476
        return;
477
    }
478

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);
487

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>");
497

498
    QTextStream stream(&creditsFile);
499
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
500
    stream.setCodec("UTF-8");
501
#endif
502
    QString line;
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>");
510
            }
511
            else {
512
                creditsHTML += QString::fromLatin1("<li>") + line + QString::fromLatin1("</li>");
513
            }
514
        }
515
    }
516
    creditsHTML += QString::fromLatin1("</ul></body></html>");
517
    textField->setHtml(creditsHTML);
518
}
519

520
void AboutDialog::showLicenseInformation()
521
{
522
    QString licenseFileURL = QString::fromLatin1("%1/LICENSE.html")
523
        .arg(QString::fromUtf8(App::Application::getHelpDir().c_str()));
524
    QFile licenseFile(licenseFileURL);
525

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());
530

531
        ui->tabWidget->removeTab(1); // Hide the license placeholder widget
532

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);
541

542
        textField->setHtml(licenseHTML);
543
    }
544
    else {
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);
550
    }
551
}
552

553
QString AboutDialog::getAdditionalLicenseInformation() const
554
{
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
558
    QString info;
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 &#169; 1992&ndash;2012 3Dconnexion. All rights reserved.</p>"
564
        "<hr/>"
565
    );
566
#endif
567
    return info;
568
}
569

570
void AboutDialog::showLibraryInformation()
571
{
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);
580

581
    QList<LibraryInfo> libInfo;
582
    QString baseurl = QString::fromLatin1("file:///%1/ThirdPartyLibraries.html")
583
            .arg(QString::fromUtf8(App::Application::getHelpDir().c_str()));
584

585
    // Boost
586
    libInfo << LibraryInfo {
587
        QLatin1String("Boost"),
588
        baseurl + QLatin1String("#_TocBoost"),
589
        QLatin1String("https://www.boost.org"),
590
        QLatin1String(BOOST_LIB_VERSION)
591
    };
592

593
    // Coin3D
594
    libInfo << LibraryInfo {
595
        QLatin1String("Coin3D"),
596
        baseurl + QLatin1String("#_TocCoin3D"),
597
        QLatin1String("https://coin3d.github.io"),
598
        QLatin1String(COIN_VERSION)
599
    };
600

601
    // Eigen3
602
    libInfo << LibraryInfo {
603
        QLatin1String("Eigen"),
604
        baseurl + QLatin1String("#_TocEigen"),
605
        QLatin1String("https://eigen.tuxfamily.org"),
606
        QString::fromLatin1(fcEigen3Version)
607
    };
608

609
    // FreeType
610
    libInfo << LibraryInfo {
611
        QLatin1String("FreeType"),
612
        baseurl + QLatin1String("#_TocFreeType"),
613
        QLatin1String("https://freetype.org"),
614
        QString::fromLatin1(fcFreetypeVersion)
615
    };
616

617
    // KDL
618
    libInfo << LibraryInfo {
619
        QLatin1String("KDL"),
620
        baseurl + QLatin1String("#_TocKDL"),
621
        QLatin1String("https://www.orocos.org/kdl"),
622
        QString()
623
    };
624

625
    // libarea
626
    libInfo << LibraryInfo {
627
        QLatin1String("libarea"),
628
        baseurl + QLatin1String("#_TocLibArea"),
629
        QLatin1String("https://github.com/danielfalck/libarea"),
630
        QString()
631
    };
632

633
    // OCCT
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)
640
    };
641
#endif
642

643
    // pcl
644
    libInfo << LibraryInfo {
645
        QLatin1String("Point Cloud Library"),
646
        baseurl + QLatin1String("#_TocPcl"),
647
        QLatin1String("https://www.pointclouds.org"),
648
        QString::fromLatin1(fcPclVersion)
649
    };
650

651
    // PyCXX
652
    libInfo << LibraryInfo {
653
        QLatin1String("PyCXX"),
654
        baseurl + QLatin1String("#_TocPyCXX"),
655
        QLatin1String("http://cxx.sourceforge.net"),
656
        QString::fromLatin1(fcPycxxVersion)
657
    };
658

659
    // Python
660
    libInfo << LibraryInfo {
661
        QLatin1String("Python"),
662
        baseurl + QLatin1String("#_TocPython"),
663
        QLatin1String("https://www.python.org"),
664
        QLatin1String(PY_VERSION)
665
    };
666

667
    // PySide
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)
673
    };
674

675
    // Qt
676
    libInfo << LibraryInfo {
677
        QLatin1String("Qt"),
678
        baseurl + QLatin1String("#_TocQt"),
679
        QLatin1String("https://www.qt.io"),
680
        QLatin1String(QT_VERSION_STR)
681
    };
682

683
    // Salome SMESH
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)
690
#else
691
        QString()
692
#endif
693
    };
694

695
    // Shiboken
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)
701
    };
702

703
    // vtk
704
    libInfo << LibraryInfo {
705
        QLatin1String("vtk"),
706
        baseurl + QLatin1String("#_TocVtk"),
707
        QLatin1String("https://www.vtk.org"),
708
        QString::fromLatin1(fcVtkVersion)
709
    };
710

711
    // Xerces-C
712
    libInfo << LibraryInfo {
713
        QLatin1String("Xerces-C"),
714
        baseurl + QLatin1String("#_TocXercesC"),
715
        QLatin1String("https://xerces.apache.org/xerces-c"),
716
        QString::fromLatin1(fcXercescVersion)
717
    };
718

719
    // Zipios++
720
    libInfo << LibraryInfo {
721
        QLatin1String("Zipios++"),
722
        baseurl + QLatin1String("#_TocZipios"),
723
        QLatin1String("http://zipios.sourceforge.net"),
724
        QString()
725
    };
726

727
    // zlib
728
    libInfo << LibraryInfo {
729
        QLatin1String("zlib"),
730
        baseurl + QLatin1String("#_TocZlib"),
731
        QLatin1String("https://zlib.net"),
732
        QLatin1String(ZLIB_VERSION)
733
    };
734

735

736
    QString msg = tr("This software uses open source components whose copyright and other "
737
                     "proprietary rights belong to their respective owners:");
738
    QString html;
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";
746
    }
747
    out << "</ul>\n</body>\n</html>";
748
    textField->setHtml(html);
749

750
    connect(textField, &QTextBrowser::anchorClicked, this, &AboutDialog::linkActivated);
751
}
752

753
void AboutDialog::showCollectionInformation()
754
{
755
    QString doc = QString::fromUtf8(App::Application::getHelpDir().c_str());
756
    QString path = doc + QLatin1String("Collection.html");
757
    if (!QFile::exists(path))
758
        return;
759

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);
768
}
769

770
void AboutDialog::linkActivated(const QUrl& link)
771
{
772
    auto licenseView = new LicenseView();
773
    licenseView->setAttribute(Qt::WA_DeleteOnClose);
774
    licenseView->show();
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);
780
    }
781
    licenseView->setWindowTitle(title);
782
    getMainWindow()->addWindow(licenseView);
783
    licenseView->setSource(link);
784
}
785

786
void AboutDialog::copyToClipboard()
787
{
788
    QString data;
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());
793

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());
799

800
    QString deskEnv = QProcessEnvironment::systemEnvironment().value(QStringLiteral("XDG_CURRENT_DESKTOP"), QString());
801
    QString deskSess = QProcessEnvironment::systemEnvironment().value(QStringLiteral("DESKTOP_SESSION"), QString());
802
    QString deskInfo;
803

804
    if ( !(deskEnv.isEmpty() && deskSess.isEmpty()) ) {
805
        if ( deskEnv.isEmpty() || deskSess.isEmpty() )
806
            deskInfo = QLatin1String(" (") + deskEnv + deskSess + QLatin1String(")");
807
        else
808
            deskInfo = QLatin1String(" (") + deskEnv + QLatin1String("/") + deskSess + QLatin1String(")");
809
    }
810

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");
815
    if (appimage)
816
        str << " AppImage";
817
    char* snap = getenv("SNAP_REVISION");
818
    if (snap)
819
        str << " Snap " << snap;
820
    str << '\n';
821

822
#if defined(_DEBUG) || defined(DEBUG)
823
    str << "Build type: Debug\n";
824
#elif defined(NDEBUG)
825
    str << "Build type: Release\n";
826
#elif defined(CMAKE_BUILD_TYPE)
827
    str << "Build type: " << CMAKE_BUILD_TYPE << '\n';
828
#else
829
    str << "Build type: Unknown\n";
830
#endif
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)
843
    str << "OCC "
844
        << OCC_VERSION_MAJOR << "."
845
        << OCC_VERSION_MINOR << "."
846
        << OCC_VERSION_MAINTENANCE
847
#ifdef OCC_VERSION_DEVELOPMENT
848
        << "." OCC_VERSION_DEVELOPMENT
849
#endif
850
        << '\n';
851
#endif
852
    QLocale loc;
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() << ") ]";
861
    }
862
    str << "\n";
863

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
871
                continue;
872
            if (firstMod) {
873
                firstMod = false;
874
                str << "Installed mods: \n";
875
            }
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());
882
            }
883
            auto disablingFile = mod.path() / "ADDON_DISABLED";
884
            if (fs::exists(disablingFile))
885
                str << " (Disabled)";
886

887
            str << "\n";
888
        }
889
    }
890

891
    QClipboard* cb = QApplication::clipboard();
892
    cb->setText(data);
893
}
894

895
// ----------------------------------------------------------------------------
896

897
/* TRANSLATOR Gui::LicenseView */
898

899
LicenseView::LicenseView(QWidget* parent)
900
    : MDIView(nullptr,parent,Qt::WindowFlags())
901
{
902
    browser = new QTextBrowser(this);
903
    browser->setOpenExternalLinks(true);
904
    browser->setOpenLinks(true);
905
    setCentralWidget(browser);
906
}
907

908
LicenseView::~LicenseView() = default;
909

910
void LicenseView::setSource(const QUrl& url)
911
{
912
    browser->setSource(url);
913
}
914

915
#include "moc_Splashscreen.cpp"
916

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.