• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 3809845615

pending completion
3809845615

push

github

Georg Zotti
Ensured file paths are constant

2 of 2 new or added lines in 1 file covered. (100.0%)

14663 of 123658 relevant lines covered (11.86%)

25812.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/gui/HelpDialog.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2007 Matthew Gates
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18
 */
19

20
#include <QString>
21
#include <QTextBrowser>
22
#include <QScrollBar>
23
#include <QVBoxLayout>
24
#include <QWidget>
25
#include <QFrame>
26
#include <QResizeEvent>
27
#include <QSize>
28
#include <QMultiMap>
29
#include <QList>
30
#include <QSet>
31
#include <QPair>
32
#include <QtAlgorithms>
33
#include <QDebug>
34
#include <QFileInfo>
35
#include <QFile>
36
#include <QDir>
37
#include <QProcess>
38
#include <QSysInfo>
39
#include <QNetworkAccessManager>
40
#include <QNetworkReply>
41
#include <QRegularExpression>
42

43
#include "ui_helpDialogGui.h"
44
#include "HelpDialog.hpp"
45

46
#include "StelUtils.hpp"
47
#include "StelApp.hpp"
48
#include "StelFileMgr.hpp"
49
#include "StelGui.hpp"
50
#include "StelLogger.hpp"
51
#include "StelStyle.hpp"
52
#include "StelActionMgr.hpp"
53
#include "StelMovementMgr.hpp"
54
#include "StelModuleMgr.hpp"
55
#include "StelJsonParser.hpp"
56
#include "StelTranslator.hpp"
57
#include "ContributorsList.hpp"
58

59
HelpDialog::HelpDialog(QObject* parent)
×
60
        : StelDialog("Help", parent)
61
        , message("")
×
62
        , updateState(CompleteNoUpdates)
×
63
        , networkManager(nullptr)
×
64
        , downloadReply(nullptr)
×
65
{
66
        ui = new Ui_helpDialogForm;        
×
67
}
×
68

69
HelpDialog::~HelpDialog()
×
70
{
71
        delete ui;
×
72
        ui = nullptr;
×
73
}
×
74

75
void HelpDialog::retranslate()
×
76
{
77
        if (dialog)
×
78
        {
79
                ui->retranslateUi(dialog);
×
80
                updateHelpText();
×
81
                updateAboutText();
×
82
                updateTabBarListWidgetWidth();
×
83
        }
84
}
×
85

86
void HelpDialog::styleChanged(const QString &style)
×
87
{
88
        StelDialog::styleChanged(style);
×
89
        if (dialog)
×
90
        {
91
                updateHelpText();
×
92
                updateAboutText();
×
93
        }
94
}
×
95

96
void HelpDialog::createDialogContent()
×
97
{
98
        ui->setupUi(dialog);
×
99
        connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate()));
×
100
        ui->stackedWidget->setCurrentIndex(0);
×
101
        ui->stackListWidget->setCurrentRow(0);
×
102
        connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
×
103
        connect(ui->TitleBar, SIGNAL(movedTo(QPoint)), this, SLOT(handleMovedTo(QPoint)));
×
104

105
        // Kinetic scrolling
106
        kineticScrollingList << ui->helpBrowser << ui->aboutBrowser << ui->logBrowser;
×
107
        StelGui* gui= dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
×
108
        if (gui)
×
109
        {
110
                enableKineticScrolling(gui->getFlagUseKineticScrolling());
×
111
                connect(gui, SIGNAL(flagUseKineticScrollingChanged(bool)), this, SLOT(enableKineticScrolling(bool)));
×
112
        }
113

114

115
        // Help page
116
        StelMovementMgr* mmgr = GETSTELMODULE(StelMovementMgr);
×
117
        updateHelpText();
×
118
        setKeyButtonState(mmgr->getFlagEnableMoveKeys());
×
119
        connect(ui->editShortcutsButton, SIGNAL(clicked()), this, SLOT(showShortcutsWindow()));
×
120
        connect(StelApp::getInstance().getStelActionManager(), SIGNAL(shortcutsChanged()), this, SLOT(updateHelpText()));
×
121
        connect(mmgr, SIGNAL(flagEnableMoveKeysChanged(bool)), this, SLOT(setKeyButtonState(bool)));
×
122

123
        // About page
124
        updateAboutText();
×
125

126
        // Log page        
127
        ui->logPathLabel->setText(QString("%1:").arg(StelLogger::getLogFileName()));
×
128
        connect(ui->stackedWidget, SIGNAL(currentChanged(int)), this, SLOT(updateLog(int)));
×
129
        connect(ui->refreshButton, SIGNAL(clicked()), this, SLOT(refreshLog()));
×
130

131
        // Config page
132
        ui->configPathLabel->setText(QString("%1:").arg(StelApp::getInstance().getSettings()->fileName()));
×
133
        connect(ui->stackedWidget, SIGNAL(currentChanged(int)), this, SLOT(updateConfig(int)));
×
134
        connect(ui->refreshConfigButton, SIGNAL(clicked()), this, SLOT(refreshConfig()));
×
135

136
        // Set up download manager for checker of updates
137
        networkManager = StelApp::getInstance().getNetworkAccessManager();
×
138
        updateState = CompleteNoUpdates;
×
139
        connect(ui->checkUpdatesButton, SIGNAL(clicked()), this, SLOT(checkUpdates()));
×
140
        connect(this, SIGNAL(checkUpdatesComplete(void)), this, SLOT(updateAboutText()));
×
141

142
        connect(ui->stackListWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(changePage(QListWidgetItem *, QListWidgetItem*)));
×
143
        updateTabBarListWidgetWidth();
×
144

145
        connect((dynamic_cast<StelGui*>(StelApp::getInstance().getGui())), &StelGui::htmlStyleChanged, this, [=](const QString &style){
×
146
                ui->helpBrowser->document()->setDefaultStyleSheet(style);
×
147
                ui->aboutBrowser->document()->setDefaultStyleSheet(style);
×
148
        });
×
149
}
×
150

151
void HelpDialog::setKeyButtonState(bool state)
×
152
{
153
        ui->editShortcutsButton->setEnabled(state);
×
154
}
×
155

156
void HelpDialog::checkUpdates()
×
157
{
158
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
159
        // In Qt6 this is no longer available. Here we have to assume we are connected and test the reply.
160
        // There is QNetworkInformation in Qt6.1, but it may give wrong results under certain circumstances.
161
        // https://doc.qt.io/qt-6/qnetworkinformation.html
162
        if (networkManager->networkAccessible()==QNetworkAccessManager::Accessible)
×
163
#endif
164
        {
165
                if (updateState==HelpDialog::Updating)
×
166
                {
167
                        qWarning() << "Already checking updates...";
×
168
                        return;
×
169
                }
170

171
                QUrl API("https://api.github.com/repos/Stellarium/stellarium/releases/latest");
×
172
                connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
×
173
                QNetworkRequest request;
×
174
                request.setUrl(API);
×
175
                request.setRawHeader("User-Agent", StelUtils::getUserAgentString().toUtf8());
×
176
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
177
                request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
×
178
#endif
179
                downloadReply = networkManager->get(request);
×
180

181
                updateState = HelpDialog::Updating;
×
182
        }
×
183
}
184

185
void HelpDialog::downloadComplete(QNetworkReply *reply)
×
186
{
187
        if (reply == nullptr)
×
188
                return;
×
189

190
        disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
×
191

192
        if (reply->error() || reply->bytesAvailable()==0)
×
193
        {
194
                qWarning() << "Error: While trying to access"
×
195
                           << reply->url().toString()
×
196
                           << "the following error occurred:"
×
197
                           << reply->errorString();
×
198

199
                reply->deleteLater();
×
200
                downloadReply = nullptr;
×
201
                updateState = HelpDialog::DownloadError;
×
202
                message = q_("Cannot check updates...");
×
203
                return;
×
204
        }
205

206
        QVariantMap map;
×
207
        try
208
        {
209
                map = StelJsonParser::parse(reply->readAll()).toMap();
×
210
        }
211
        catch (std::runtime_error &e)
×
212
        {
213
                qDebug() << "Answer format is wrong! Error: " << e.what();
×
214
                message = q_("Cannot check updates...");
×
215
                return;
×
216
        }
×
217

218
        updateState = HelpDialog::CompleteUpdates;
×
219

220
        QString latestVersion = map["name"].toString();
×
221
        latestVersion.replace("v","", Qt::CaseInsensitive);
×
222
        QStringList v = latestVersion.split(".");
×
223

224
        QString appVersion;
×
225
        if (v.count()==3)
×
226
                appVersion = StelUtils::getApplicationVersion();
×
227
        else
228
                appVersion = StelUtils::getApplicationPublicVersion();
×
229

230
        QStringList c = appVersion.split(".");
×
231
        int r = StelUtils::compareVersions(latestVersion, appVersion);
×
232
        if (r==-1 || c.count()>v.count() || c.last().contains("-"))
×
233
                message = q_("Looks like you are using the development version of Stellarium.");
×
234
        else if (r==0)
×
235
                message = q_("This is latest stable version of Stellarium.");
×
236
        else
237
                message = QString("%1 <a href='%2'>%3</a>").arg(q_("This version of Stellarium is outdated!"), map["html_url"].toString(), q_("Download new version."));
×
238

239
        reply->deleteLater();
×
240
        downloadReply = nullptr;
×
241

242
        emit checkUpdatesComplete();
×
243
}
×
244

245
void HelpDialog::showShortcutsWindow()
×
246
{
247
        StelAction* action = StelApp::getInstance().getStelActionManager()->findAction("actionShow_Shortcuts_Window_Global");
×
248
        if (action)
×
249
                action->setChecked(true);
×
250
}
×
251

252
void HelpDialog::updateLog(int)
×
253
{
254
        if (ui->stackedWidget->currentWidget() == ui->pageLog)
×
255
                refreshLog();
×
256
}
×
257

258
void HelpDialog::updateConfig(int)
×
259
{
260
        if (ui->stackedWidget->currentWidget() == ui->pageConfig)
×
261
                refreshConfig();
×
262
}
×
263

264
void HelpDialog::refreshLog() const
×
265
{
266
        ui->logBrowser->setPlainText(StelLogger::getLog());
×
267
        QScrollBar *sb = ui->logBrowser->verticalScrollBar();
×
268
        sb->setValue(sb->maximum());
×
269
}
×
270

271
void HelpDialog::refreshConfig() const
×
272
{
273
        QFile config(StelApp::getInstance().getSettings()->fileName());
×
274
        if(config.open(QIODevice::ReadOnly))
×
275
        {
276
                ui->configBrowser->setPlainText(config.readAll());
×
277
                ui->configBrowser->setFont(QFont("Courier New"));
×
278
                config.close();
×
279
        }
280
}
×
281

282
void HelpDialog::updateHelpText(void) const
×
283
{
284
        QString htmlText = "<html><head><title>";
×
285
        htmlText += q_("Stellarium Help").toHtmlEscaped();
×
286
        htmlText += "</title></head><body>\n";
×
287

288
        // WARNING! Section titles are re-used below!
289
        htmlText += "<p align=\"center\"><a href=\"#keys\">" +
×
290
                    q_("Keys").toHtmlEscaped() +
×
291
                    "</a> &bull; <a href=\"#links\">" +
×
292
                    q_("Further Reading").toHtmlEscaped() +
×
293
                    "</a></p>\n";
×
294

295
        htmlText += "<h2 id='keys'>" + q_("Keys").toHtmlEscaped() + "</h2>\n";
×
296
        htmlText += "<table cellpadding='10%' width='100%'>\n";
×
297
        // Describe keys for those keys which do not have actions.
298
        // navigate
299
        htmlText += "<tr><td>" + q_("Pan view around the sky").toHtmlEscaped() + "</td>";
×
300
        htmlText += "<td><b>" + q_("Arrow keys & left mouse drag").toHtmlEscaped() + "</b></td></tr>\n";
×
301
        // zoom in/out
302
        htmlText += "<tr><td rowspan='2'>" + q_("Zoom in/out").toHtmlEscaped() + "</td>";
×
303
        htmlText += "<td><b>" + hotkeyTextWrapper("Page Up") + "/" + hotkeyTextWrapper("Page Down") + "</b></td></tr>\n";
×
304
        htmlText += "<tr><td><b>" + hotkeyTextWrapper("Ctrl+Up") + "/" + hotkeyTextWrapper("Ctrl+Down") + "</b></td></tr>\n";
×
305
        // time dragging/scrolling
306
        QString delimiter = "";
×
307
        #ifdef Q_OS_MACOS
308
        // TRANSLATORS: The char mean "and"
309
        delimiter = QString(" %1 ").arg(q_("&"));
310
        #endif
311
        htmlText += "<tr><td>" + q_("Time dragging").toHtmlEscaped() + "</td><td><b>" +
×
312
                        QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText) + delimiter + q_("left mouse drag").toHtmlEscaped() + "</b></td></tr>";
×
313
        htmlText += "<tr><td>" + q_("Time scrolling: minutes").toHtmlEscaped() + "</td><td><b>" +
×
314
                        QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText) + delimiter + q_("mouse wheel").toHtmlEscaped() + "</b></td></tr>";
×
315
        htmlText += "<tr><td>" + q_("Time scrolling: hours").toHtmlEscaped() + "</td><td><b>" +
×
316
        #if (QT_VERSION>=QT_VERSION_CHECK(6,0,0))
317
                        QKeySequence(Qt::CTRL | Qt::SHIFT).toString(QKeySequence::NativeText) + delimiter + q_("mouse wheel").toHtmlEscaped() + "</b></td></tr>";
318
        htmlText += "<tr><td>" + q_("Time scrolling: days").toHtmlEscaped() + "</td><td><b>" +
319
                        QKeySequence(Qt::CTRL | Qt::ALT).toString(QKeySequence::NativeText) + delimiter + q_("mouse wheel").toHtmlEscaped() + "</b></td></tr>";
320
        htmlText += "<tr><td>" + q_("Time scrolling: years").toHtmlEscaped() + "</td><td><b>" +
321
                        QKeySequence(Qt::CTRL | Qt::ALT | Qt::SHIFT).toString(QKeySequence::NativeText) + delimiter + q_("mouse wheel").toHtmlEscaped() + "</b></td></tr>";
322
        #else
323
                        QKeySequence(Qt::CTRL + Qt::SHIFT).toString(QKeySequence::NativeText) + delimiter + q_("mouse wheel").toHtmlEscaped() + "</b></td></tr>";
×
324
        htmlText += "<tr><td>" + q_("Time scrolling: days").toHtmlEscaped() + "</td><td><b>" +
×
325
                        QKeySequence(Qt::CTRL + Qt::ALT).toString(QKeySequence::NativeText) + delimiter + q_("mouse wheel").toHtmlEscaped() + "</b></td></tr>";
×
326
        htmlText += "<tr><td>" + q_("Time scrolling: years").toHtmlEscaped() + "</td><td><b>" +
×
327
                        QKeySequence(Qt::CTRL + Qt::ALT + Qt::SHIFT).toString(QKeySequence::NativeText) + delimiter + q_("mouse wheel").toHtmlEscaped() + "</b></td></tr>";
×
328
        #endif
329

330
        // select object
331
        htmlText += "<tr><td>" + q_("Select object").toHtmlEscaped() + "</td>";
×
332
        htmlText += "<td><b>" + q_("Left click").toHtmlEscaped() + "</b></td></tr>\n";
×
333
        // clear selection
334
        htmlText += "<tr><td>";
×
335
        htmlText += q_("Clear selection").toHtmlEscaped() + "</td>";
×
336
        #ifdef Q_OS_MACOS
337
        htmlText += "<td><b>" + QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText) + delimiter + q_("& left click").toHtmlEscaped() + "</b></td></tr>\n";
338
        #else
339
        htmlText += "<td><b>" + q_("Right click").toHtmlEscaped() + "</b></td></tr>\n";
×
340
        #endif
341
        // add custom marker
342
        htmlText += "<tr><td>" + q_("Add custom marker").toHtmlEscaped() + "</td>";
×
343
        htmlText += "<td><b>" + QKeySequence(Qt::SHIFT).toString(QKeySequence::NativeText) + delimiter + q_("left click").toHtmlEscaped() + "</b></td></tr>\n";
×
344
        // delete one custom marker
345
        htmlText += "<tr><td>" + q_("Delete marker closest to mouse cursor").toHtmlEscaped() + "</td>";
×
346
        htmlText += "<td><b>" + QKeySequence(Qt::SHIFT).toString(QKeySequence::NativeText) + delimiter + q_("right click").toHtmlEscaped() + "</b></td></tr>\n";
×
347
        // delete all custom markers
348
        htmlText += "<tr><td>" + q_("Delete all custom markers").toHtmlEscaped() + "</td>";
×
349
        #if (QT_VERSION>=QT_VERSION_CHECK(6,0,0))
350
        htmlText += "<td><b>" + QKeySequence(Qt::SHIFT | Qt::ALT).toString(QKeySequence::NativeText) + delimiter + q_("right click").toHtmlEscaped() + "</b></td></tr>\n";
351
        #else
352
        htmlText += "<td><b>" + QKeySequence(Qt::SHIFT + Qt::ALT).toString(QKeySequence::NativeText) + delimiter + q_("right click").toHtmlEscaped() + "</b></td></tr>\n";
×
353
        #endif
354

355
        htmlText += "</table>\n<p>" +
×
356
                        q_("Below are listed only the actions with assigned keys. Further actions may be available via the \"%1\" button.")
×
357
                        .arg(ui->editShortcutsButton->text()).toHtmlEscaped() +
×
358
                        "</p><table cellpadding='10%' width='100%'>\n";
×
359

360
        // Append all StelAction shortcuts.
361
        StelActionMgr* actionMgr = StelApp::getInstance().getStelActionManager();
×
362
        typedef QPair<QString, QString> KeyDescription;
363
        QString keydelimiter = QString("</b> %1 <b>").arg(q_("or"));
×
364
        QVector<KeyDescription> groups;
×
365
        const QStringList groupList = actionMgr->getGroupList();
×
366
        for (const auto &group : groupList)
×
367
        {
368
                groups.append(KeyDescription(q_(group), group));
×
369
        }
370
        groups.append(KeyDescription(q_("Text User Interface (TUI)"), "TUI")); // Special case: TUI
×
371
        std::sort(groups.begin(), groups.end());
×
372
        for (const auto &group : groups)
×
373
        {
374
                QVector<KeyDescription> descriptions;
×
375
                const QList<StelAction *>actionList = actionMgr->getActionList(group.second);
×
376
                for (auto* action : actionList)
×
377
                {
378
                        QString text = action->getText();
×
379
                        QStringList keys = { action->getShortcut().toString(QKeySequence::NativeText), action->getAltShortcut().toString(QKeySequence::NativeText)};
×
380
                        keys.removeAll(QString("")); // remove empty shortcuts
×
381
                        if (keys.count()>0)
×
382
                                descriptions.append(KeyDescription(text, keys.join(keydelimiter)));
×
383
                }
×
384
                std::sort(descriptions.begin(), descriptions.end());
×
385
                if (descriptions.count()>0)
×
386
                {
387
                        htmlText += "<tr><td colspan='2'>&nbsp;</td></tr>";
×
388
                        htmlText += "<tr><td colspan='2'><b><u>" + group.first.toHtmlEscaped() + ":</u></b></td></tr>\n";
×
389
                        for (const auto& desc : descriptions)
×
390
                        {
391
                                htmlText += "<tr><td>" + desc.first.toHtmlEscaped() + "</td>";
×
392
                                htmlText += "<td><b>" + desc.second + "</b></td></tr>\n";
×
393
                        }
394
                }
395
                if (group.second=="TUI") // Special case: TUI
×
396
                {
397
                        htmlText += "<tr><td colspan='2'>&nbsp;</td></tr>";
×
398
                        htmlText += "<tr><td colspan='2'><b><u>" + group.first.toHtmlEscaped() + ":</u></b></td></tr>\n";
×
399
                        htmlText += "<tr><td>" + q_("Activate TUI") + "</td>";
×
400
                        htmlText += "<td><b>" + hotkeyTextWrapper("Alt+T") + "</b></td></tr>\n";
×
401
                }
402
        }
×
403

404
        htmlText += "<tr><td colspan='2'>&nbsp;</td></tr>";
×
405
        htmlText += "<tr><td colspan='2'><b><u>" + q_("Special local keys") + ":</u></b></td></tr>\n";
×
406
        htmlText += "<tr><td colspan='2'>" + q_("All these hotkeys are locally available to run when specific window or tab is opened.") + "</td></tr>";
×
407
        htmlText += "<tr><td colspan='2'><b><em>" + q_("Script console") + ":</em></b></td></tr>\n";
×
408
        htmlText += "<tr><td>" + q_("Load script from file") + "</td>";
×
409
        htmlText += "<td><b>" + hotkeyTextWrapper("Ctrl+Shift+O") + "</b></td></tr>\n";
×
410
        htmlText += "<tr><td>" + q_("Save script to file") + "</td>";
×
411
        htmlText += "<td><b>" + hotkeyTextWrapper("Ctrl+Shift+S") + "</b></td></tr>\n";
×
412
        htmlText += "<tr><td>" + q_("Run script") + "</td>";
×
413
        htmlText += "<td><b>" + hotkeyTextWrapper("Ctrl+Return") + "</b></td></tr>\n";
×
414
        htmlText += "<tr><td colspan='2'><b><em>" + q_("Astronomical calculations") + ":</em></b></td></tr>\n";
×
415
        htmlText += "<tr><td>" + q_("Update positions") + "</td>";
×
416
        QString shiftF10 = hotkeyTextWrapper("Shift+F10");
×
417
        htmlText += "<td><b>" + shiftF10 + "</b></td></tr>\n";
×
418
        htmlText += "<tr><td>" + q_("Calculate ephemeris") + "</td>";
×
419
        htmlText += "<td><b>" + shiftF10 + "</b></td></tr>\n";
×
420
        // TRANSLATOR: RTS = rise, transit, set
421
        htmlText += "<tr><td>" + q_("Calculate RTS") + "</td>";
×
422
        htmlText += "<td><b>" + shiftF10 + "</b></td></tr>\n";
×
423
        htmlText += "<tr><td>" + q_("Calculate phenomena") + "</td>";
×
424
        htmlText += "<td><b>" + shiftF10 + "</b></td></tr>\n";
×
425
        htmlText += "<tr><td>" + q_("Calculate solar eclipses") + "</td>";
×
426
        htmlText += "<td><b>" + shiftF10 + "</b></td></tr>\n";
×
427
        htmlText += "<tr><td>" + q_("Calculate lunar eclipses") + "</td>";
×
428
        htmlText += "<td><b>" + shiftF10 + "</b></td></tr>\n";
×
429
        htmlText += "<tr><td>" + q_("Calculate transits") + "</td>";
×
430
        htmlText += "<td><b>" + shiftF10 + "</b></td></tr>\n";
×
431

432
        htmlText += "</table>";
×
433

434
        // Regexp to replace {text} with an HTML link.
435
        static const QRegularExpression a_rx("[{]([^{]*)[}]");
×
436

437
        // WARNING! Section titles are re-used above!
438
        htmlText += "<h2 id=\"links\">" + q_("Further Reading").toHtmlEscaped() + "</h2>\n";
×
439
        htmlText += q_("The following links are external web links, and will launch your web browser:\n").toHtmlEscaped();
×
440

441
        htmlText += "<p>";
×
442
        // TRANSLATORS: The text between braces is the text of an HTML link.
443
        htmlText += q_("{Frequently Asked Questions} about Stellarium.  Answers too.").toHtmlEscaped().replace(a_rx, "<a href=\"https://github.com/Stellarium/stellarium/wiki/FAQ\">\\1</a>");
×
444
        htmlText += "</p>\n";
×
445

446
        htmlText += "<p>";
×
447
        // TRANSLATORS: The text between braces is the text of an HTML link.
448
        htmlText += q_("{The Stellarium Wiki} - general information.").toHtmlEscaped().replace(a_rx, "<a href=\"https://github.com/Stellarium/stellarium/wiki\">\\1</a>");
×
449
        htmlText += "</p>\n";
×
450

451
        htmlText += "<p>";
×
452
        // TRANSLATORS: The text between braces is the text of an HTML link.
453
        htmlText += q_("{The landscapes} - user-contributed landscapes for Stellarium.").toHtmlEscaped().replace(a_rx, "<a href=\"https://stellarium.org/landscapes.html\">\\1</a>");
×
454
        htmlText += "</p>\n";
×
455

456
        htmlText += "<p>";
×
457
        // TRANSLATORS: The text between braces is the text of an HTML link.
458
        htmlText += q_("{The scripts} - user-contributed and official scripts for Stellarium.").toHtmlEscaped().replace(a_rx, "<a href=\"https://stellarium.org/scripts.html\">\\1</a>");
×
459
        htmlText += "</p>\n";
×
460

461
        htmlText += "<p>";
×
462
        // TRANSLATORS: The text between braces is the text of an HTML link.
463
        htmlText += q_("{Bug reporting and feature request system} - if something doesn't work properly or is missing and is not listed in the tracker, you can open bug reports here.").toHtmlEscaped().replace(a_rx, "<a href=\"https://github.com/Stellarium/stellarium/issues\">\\1</a>");
×
464
        htmlText += "</p>\n";
×
465

466
        htmlText += "<p>";
×
467
        // TRANSLATORS: The text between braces is the text of an HTML link.
468
        htmlText += q_("{Google Groups} - discuss Stellarium with other users.").toHtmlEscaped().replace(a_rx, "<a href=\"https://groups.google.com/forum/#!forum/stellarium\">\\1</a>");
×
469
        htmlText += "</p>\n";
×
470

471
        htmlText += "<p>";
×
472
        // TRANSLATORS: The text between braces is the text of an HTML link.
473
        htmlText += q_("{Open Collective} - donations to the Stellarium development team.").toHtmlEscaped().replace(a_rx, "<a href=\"https://opencollective.com/stellarium\">\\1</a>");
×
474
        htmlText += "</p>\n";
×
475

476
        htmlText += "</body></html>\n";
×
477

478
        ui->helpBrowser->clear();
×
479
        StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
×
480
        if (gui)
×
481
                ui->helpBrowser->document()->setDefaultStyleSheet(QString(gui->getStelStyle().htmlStyleSheet));
×
482
        ui->helpBrowser->insertHtml(htmlText);
×
483
        ui->helpBrowser->scrollToAnchor("top");
×
484
}
×
485

486
QString HelpDialog::hotkeyTextWrapper(const QString hotkey) const
×
487
{
488
        return QKeySequence(hotkey).toString(QKeySequence::NativeText);
×
489
}
490

491
void HelpDialog::updateAboutText(void) const
×
492
{
493
        QStringList allContributors = StelContributors::contributorsList;
×
494
        allContributors.sort();
×
495
        allContributors.removeDuplicates();
×
496

497
        typedef QPair<QString, int> donator;
498
        QVector<donator> financialContributors = {
499
                // Individuals
500
                { "Laurence Holt", 1000 }, { "Jeff Moe (Spacecruft)", 512 }, { "John Bellora", 470 }, { "Vernon Hermsen", 324 },
×
501
                { "Satish Mallesh", 260 }, { "Marla Pinaire", 260 }, { "Vlad Magdalin", 250  },
×
502
                // Organizations
503
                { "Astronomie-Werkstatt \"Sterne ohne Grenzen\"", 520 }, { "Triplebyte", 280 }
×
504
        };
×
505
        std::sort(financialContributors.begin(), financialContributors.end(), [](donator i, donator j){ return i.second > j.second; });
×
506
        QStringList bestFinancialContributors;
×
507
        for (auto fc = financialContributors.begin(); fc != financialContributors.end(); ++fc)
×
508
        {
509
                bestFinancialContributors << fc->first;
×
510
        }
511

512
        // Regexp to replace {text} with an HTML link.
513
        static const QRegularExpression a_rx("[{]([^{]*)[}]");
×
514

515
        // populate About tab
516
        QString newHtml = "<h1>" + StelUtils::getApplicationName() + "</h1>";
×
517
        newHtml += QString("<p><strong>%1 %2").arg(q_("Version"), StelUtils::getApplicationVersion());
×
518
        newHtml += QString("<br />%1 %2</strong></p>").arg(q_("Based on Qt"), QT_VERSION_STR);
×
519
        if (!message.isEmpty())
×
520
                newHtml += "<p><strong>" + message + "</strong></p>";
×
521
        // Note: this legal notice is not suitable for translation
522
        newHtml += QString("<h3>%1</h3>").arg(STELLARIUM_COPYRIGHT);
×
523
        // newHtml += "<p><em>Version 0.15 is dedicated in memory of our team member Barry Gerdes.</em></p>";
524
        newHtml += "<p>This program is free software; you can redistribute it and/or ";
×
525
        newHtml += "modify it under the terms of the GNU General Public License ";
×
526
        newHtml += "as published by the Free Software Foundation; either version 2 ";
×
527
        newHtml += "of the License, or (at your option) any later version.</p>";
×
528
        newHtml += "<p>This program is distributed in the hope that it will be useful, ";
×
529
        newHtml += "but WITHOUT ANY WARRANTY; without even the implied ";
×
530
        newHtml += "warranty of MERCHANTABILITY or FITNESS FOR A ";
×
531
        newHtml += "PARTICULAR PURPOSE.  See the GNU General Public ";
×
532
        newHtml += "License for more details.</p>";
×
533
        newHtml += "<p>You should have received a copy of the GNU General Public ";
×
534
        newHtml += "License along with this program; if not, write to:</p>";
×
535
        newHtml += "<pre>Free Software Foundation, Inc.\n";
×
536
        newHtml += "51 Franklin Street, Suite 500\n";
×
537
        newHtml += "Boston, MA  02110-1335, USA.\n</pre>";
×
538
        newHtml += "<p><a href=\"http://www.fsf.org\">www.fsf.org</a></p>";
×
539
        newHtml += "<h3>" + q_("Developers").toHtmlEscaped() + "</h3><ul>";
×
540
        newHtml += "<li>" + q_("Project coordinator & lead developer: %1").arg(QString("Fabien Chéreau")).toHtmlEscaped() + "</li>";
×
541
        newHtml += "<li>" + q_("Graphic/other designer: %1").arg(QString("Martín Bernardi")).toHtmlEscaped() + "</li>";
×
542
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Guillaume Chéreau")).toHtmlEscaped() + "</li>";
×
543
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Georg Zotti")).toHtmlEscaped() + "</li>";
×
544
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Alexander V. Wolf")).toHtmlEscaped() + "</li>";
×
545
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Ruslan Kabatsayev")).toHtmlEscaped() + "</li>";
×
546
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Worachate Boonplod")).toHtmlEscaped() + "</li>";
×
547
        newHtml += "<li>" + q_("Sky cultures researcher: %1").arg(QString("Susanne M. Hoffmann")).toHtmlEscaped() + "</li>";
×
548
        newHtml += "<li>" + q_("Continuous Integration: %1").arg(QString("Hans Lambermont")).toHtmlEscaped() + "</li>";
×
549
        newHtml += "<li>" + q_("Tester: %1").arg(QString("Khalid AlAjaji")).toHtmlEscaped() + "</li></ul>";
×
550
        newHtml += "<h3>" + q_("Former Developers").toHtmlEscaped() + "</h3>";
×
551
        newHtml += "<p>"  + q_("Several people have made significant contributions, but are no longer active. Their work has made a big difference to the project:").toHtmlEscaped() + "</p><ul>";
×
552
        newHtml += "<li>" + q_("Graphic/other designer: %1").arg(QString("Johan Meuris")).toHtmlEscaped() + "</li>";
×
553
        newHtml += "<li>" + q_("Doc author/developer: %1").arg(QString("Matthew Gates")).toHtmlEscaped() + "</li>";
×
554
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Johannes Gajdosik")).toHtmlEscaped() + "</li>";
×
555
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Rob Spearman")).toHtmlEscaped() + "</li>";
×
556
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Bogdan Marinov")).toHtmlEscaped() + "</li>";
×
557
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Timothy Reaves")).toHtmlEscaped() + "</li>";
×
558
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Florian Schaukowitsch")).toHtmlEscaped() + "</li>";
×
559
        newHtml += "<li>" + q_("Developer: %1").arg(QString("András Mohari")).toHtmlEscaped() + "</li>";
×
560
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Mike Storm")).toHtmlEscaped() + "</li>";
×
561
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Ferdinand Majerech")).toHtmlEscaped() + "</li>";
×
562
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Jörg Müller")).toHtmlEscaped() + "</li>";
×
563
        newHtml += "<li>" + q_("Developer: %1").arg(QString("Marcos Cardinot")).toHtmlEscaped() + "</li>";        
×
564
        newHtml += "<li>" + q_("OSX Developer: %1").arg(QString("Nigel Kerr")).toHtmlEscaped() + "</li>";
×
565
        newHtml += "<li>" + q_("OSX Developer: %1").arg(QString("Diego Marcos")).toHtmlEscaped() + "</li></ul>";
×
566
        newHtml += "<h3>" + q_("Contributors").toHtmlEscaped() + "</h3>";
×
567
        newHtml += "<p>"  + q_("Many individuals have made contributions to the project and their work has made Stellarium better. Alphabetically sorted list of all contributors: %1.").arg(allContributors.join(", ")).toHtmlEscaped() + "</p>";
×
568
        newHtml += "<h3>" + q_("Financial support").toHtmlEscaped() + "</h3>";
×
569
        newHtml += "<p>"  + q_("Many individuals and organizations are supporting the development of Stellarium by donations, and the most generous financial contributors (with donations of $250 or more) are %1.").arg(bestFinancialContributors.join(", ")).toHtmlEscaped();
×
570
        // TRANSLATORS: The text between braces is the text of an HTML link.
571
        newHtml += " " + q_("The full list of financial contributors you may see on our {Open Collective page}.").toHtmlEscaped().replace(a_rx, "<a href=\"https://opencollective.com/stellarium\">\\1</a>") + "</p>";
×
572
        newHtml += "<h3>" + q_("Acknowledgment").toHtmlEscaped() + "</h3>";
×
573
        newHtml += "<p>"  + q_("If the Stellarium planetarium was helpful for your research work, the following acknowledgment would be appreciated:").toHtmlEscaped() + "</p>";
×
574
        newHtml += "<p><em>"  + q_("This research has made use of the Stellarium planetarium") + "</em></p>";
×
575
        newHtml += "<p>Zotti, G., Hoffmann, S. M., Wolf, A., Chéreau, F., & Chéreau, G. (2021). The Simulated Sky: Stellarium for Cultural Astronomy Research. Journal of Skyscape Archaeology, 6(2), 221–258. <a href='https://doi.org/10.1558/jsa.17822'>https://doi.org/10.1558/jsa.17822</a></p>";
×
576
        // TRANSLATORS: The text between braces is the text of an HTML link.
577
        newHtml += "<p>" + q_("Or you may {download the BibTeX file of the paper} to create another citation format.").toHtmlEscaped().replace(a_rx, "<a href=\"https://stellarium.org/files/stellarium.bib\">\\1</a>") + "</p>";
×
578
        newHtml += "<p>";
×
579

580
        ui->aboutBrowser->clear();
×
581
        StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
×
582
        if (gui)
×
583
                ui->aboutBrowser->document()->setDefaultStyleSheet(QString(gui->getStelStyle().htmlStyleSheet));
×
584
        ui->aboutBrowser->insertHtml(newHtml);
×
585
        ui->aboutBrowser->scrollToAnchor("top");
×
586
}
×
587

588
void HelpDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
×
589
{
590
        if (!current)
×
591
                current = previous;
×
592
        ui->stackedWidget->setCurrentIndex(ui->stackListWidget->row(current));
×
593
}
×
594

595
void HelpDialog::updateTabBarListWidgetWidth()
×
596
{
597
        ui->stackListWidget->setWrapping(false);
×
598
        // Update list item sizes after translation
599
        ui->stackListWidget->adjustSize();
×
600
        QAbstractItemModel* model = ui->stackListWidget->model();
×
601
        if (!model)
×
602
                return;
×
603

604
        // stackListWidget->font() does not work properly!
605
        // It has a incorrect fontSize in the first loading, which produces the bug#995107.
606
        QFont font;
×
607
        font.setPixelSize(14);
×
608
        font.setWeight(QFont::Bold);
×
609
        QFontMetrics fontMetrics(font);
×
610
        int iconSize = ui->stackListWidget->iconSize().width();
×
611
        int width = 0;
×
612
        for (int row = 0; row < model->rowCount(); row++)
×
613
        {
614
                int textWidth = fontMetrics.boundingRect(ui->stackListWidget->item(row)->text()).width();
×
615
                width += iconSize > textWidth ? iconSize : textWidth; // use the wider one
×
616
                width += 24; // margin - 12px left and 12px right
×
617
        }
618
        // Hack to force the window to be resized...
619
        ui->stackListWidget->setMinimumWidth(width);
×
620
        ui->stackListWidget->updateGeometry();
×
621
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc