BibleTime
cdisplaysettings.cpp
Go to the documentation of this file.
1/*********
2*
3* In the name of the Father, and of the Son, and of the Holy Spirit.
4*
5* This file is part of BibleTime's source code, https://bibletime.info/
6*
7* Copyright 1999-2025 by the BibleTime developers.
8* The BibleTime source code is licensed under the GNU General Public License
9* version 2.0.
10*
11**********/
12
13#include "cdisplaysettings.h"
14
15#include <QCheckBox>
16#include <QComboBox>
17#include <QFont>
18#include <QLabel>
19#include <QLocale>
20#include <QMap>
21#include <QNonConstOverload>
22#include <QPalette>
23#include <QSizePolicy>
24#include <Qt>
25#include <QVBoxLayout>
26#include <QFormLayout>
27#include <utility>
28#include "../../backend/config/btconfig.h"
29#include "../../backend/language.h"
30#include "../../backend/managers/btlocalemgr.h"
31#include "../../backend/managers/colormanager.h"
32#include "../../backend/managers/cdisplaytemplatemgr.h"
33#include "../../backend/rendering/cdisplayrendering.h"
34#include "../../backend/rendering/ctextrendering.h"
35#include "../../util/btassert.h"
36#include "../../util/btconnect.h"
37#include "../../util/cresmgr.h"
38#include "../../util/tool.h"
40
41// Sword includes:
42#include <swbuf.h>
43
44
45/** Initializes the startup section of the OD. */
47 : BtConfigDialog::Page(CResMgr::settings::startup::icon(), parent)
48{
49 QVBoxLayout *mainLayout = new QVBoxLayout(this);
50
51 QFormLayout *formLayout = new QFormLayout();
52
53 //startup logo
54 m_showLogoLabel = new QLabel(this);
55 m_showLogoCheck = new QCheckBox(this);
56 m_showLogoCheck->setChecked(
57 btConfig().value<bool>(QStringLiteral("GUI/showSplashScreen"),
58 true));
59 formLayout->addRow(m_showLogoLabel, m_showLogoCheck);
60
61 m_swordLocaleCombo = new QComboBox(this);
62 m_languageNamesLabel = new QLabel(this);
64 formLayout->addRow(m_languageNamesLabel, m_swordLocaleCombo);
65
67
68 // Light/Dark Mode
69 m_lightDarkLabel = new QLabel(this);
70 m_lightDarkCombo = new QComboBox(this);
71 formLayout->addRow(m_lightDarkLabel, m_lightDarkCombo);
72
73 m_styleChooserCombo = new QComboBox( this ); //create first to enable buddy for label
74 BT_CONNECT(m_styleChooserCombo, qOverload<int>(&QComboBox::activated),
76
77 m_availableLabel = new QLabel(this);
79 formLayout->addRow(m_availableLabel, m_styleChooserCombo );
80 mainLayout->addLayout(formLayout);
81
82 m_previewLabel = new QLabel(this);
83 m_previewLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
84
85 m_stylePreviewViewer = new QLabel(this);
86 m_stylePreviewViewer->setWordWrap(true);
87 m_stylePreviewViewer->setTextFormat(Qt::RichText);
88 m_stylePreviewViewer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
89 m_stylePreviewViewer->setAlignment(Qt::AlignTop);
90 m_stylePreviewViewer->setMargin(15);
91 m_stylePreviewViewer->setAutoFillBackground(true);
92 QFont font = m_stylePreviewViewer->font();
93 font.setPointSize(font.pointSize()+2);
94 m_stylePreviewViewer->setFont(font);
95
96 mainLayout->addWidget(m_previewLabel);
97 mainLayout->addWidget(m_stylePreviewViewer);
98
100 m_styleChooserCombo->addItems(tMgr->availableTemplates());
101
102 for (int i = 0; i < m_styleChooserCombo->count(); ++i) {
104 m_styleChooserCombo->setCurrentIndex(i);
105 break;
106 }
107 }
108
109 m_transifexLabel = new QLabel(this);
110 mainLayout->addWidget(m_transifexLabel);
111
112 retranslateUi(); // also calls updateStylePreview();
113 m_lightDarkCombo->setCurrentIndex(
114 btConfig().value<int>(QStringLiteral("GUI/lightDarkMode")));
115}
116
118 setHeaderText(tr("Display"));
119
120 m_languageNamesLabel->setText(tr("Language for names of Bible books:"));
121 const QString toolTip(tr("The languages which can be used for the biblical book names. Translations are provided by the Sword library."));
122 m_languageNamesLabel->setToolTip(toolTip);
123 m_swordLocaleCombo->setToolTip(toolTip);
124
125 m_showLogoLabel->setText(tr("Show startup logo:"));
126 m_showLogoLabel->setToolTip(tr("Show the BibleTime logo on startup."));
127
128 m_lightDarkLabel->setText(tr("Light / dark Mode (Requires restart)"));
129 m_lightDarkCombo->addItem(tr("System default"));
130 m_lightDarkCombo->addItem(tr("Light"));
131 m_lightDarkCombo->addItem(tr("Dark"));
132
133 m_availableLabel->setText(tr("Available display styles:"));
134 m_previewLabel->setText(tr("Style preview"));
135
137
138 m_transifexLabel->setWordWrap(true);
139 m_transifexLabel->setOpenExternalLinks(true);
140 m_transifexLabel->setText(tr(
141 "Did you know? You can help translating the GUI of BibleTime to your "
142 "language at "
143 "<a href=\"https://www.transifex.com/bibletime/bibletime/\">Transifex"
144 "</a>."));
145}
146
148 QList<QString> atv = bookNameAbbreviationsTryVector();
149
150 BT_ASSERT(!atv.isEmpty());
151 QString best = atv.takeLast();
152 for (auto const & localePair : BtLocaleMgr::internalSwordLocales()) {
153 auto const & swordAbbreviation = localePair.first;
154 if (swordAbbreviation == "locales")
155 continue;
156 auto abbreviation =
157 util::tool::fixSwordBcp47(swordAbbreviation.c_str());
158 if (auto const i = atv.indexOf(abbreviation); i >= 0) {
159 best = std::move(abbreviation);
160 if (i == 0)
161 break;
162 atv.resize(i);
163 }
164 }
165 btConfig().setValue(QStringLiteral("GUI/booknameLanguage"), best);
166}
167
169 QList<QString> atv;
170 atv.reserve(4);
171 {
172 QString settingsLanguage = btConfig().booknameLanguage();
173 if (!settingsLanguage.isEmpty())
174 atv.append(settingsLanguage);
175 }
176 {
177 auto localeLanguageAndCountry = QLocale().name(); // ISO 639 _ ISO 3166
178 if (!localeLanguageAndCountry.isEmpty()) {
179 localeLanguageAndCountry.replace('_', '-'); // Ensure BCP 47
180 atv.append(localeLanguageAndCountry);
181 if (auto const i = localeLanguageAndCountry.indexOf('-'); i > 0)
182 atv.append(localeLanguageAndCountry.left(i));
183 }
184 }
185 atv.append(Language::fromAbbrev({})->abbrev());
186 return atv;
187}
188
190 QMap<QString, QString> languageNames;
191 {
192 auto const defaultLanguage = Language::fromAbbrev({});
193 languageNames.insert(defaultLanguage->translatedName(),
194 defaultLanguage->abbrev());
195 }
196
197 for (auto const & localePair : BtLocaleMgr::internalSwordLocales()) {
198 auto const & swordAbbreviation = localePair.first;
199 if (swordAbbreviation.size() <= 0)
200 continue; // work around Sword not checking [Meta] Name= validity
201 if (swordAbbreviation == "locales")
202 continue;
203 auto abbreviation =
204 util::tool::fixSwordBcp47(swordAbbreviation.c_str());
205 auto const l = Language::fromAbbrev(std::move(abbreviation));
206 languageNames.insert(l->translatedName(), l->abbrev());
207 }
208
209 int index = 0;
210 QList<QString> atv = bookNameAbbreviationsTryVector();
211 for (auto it = languageNames.constBegin(); it != languageNames.constEnd(); ++it) {
212 if (!atv.isEmpty()) {
213 int i = atv.indexOf(it.value());
214 if (i >= 0) {
215 atv.resize(i);
216 index = m_swordLocaleCombo->count();
217 }
218 }
219 m_swordLocaleCombo->addItem(it.key(), it.value());
220 }
221 m_swordLocaleCombo->setCurrentIndex(index);
222}
223
224
226 //update the style preview widget
227 using namespace Rendering;
228
229 const QString styleName = m_styleChooserCombo->currentText();
231
233 settings.highlight = false;
234
235 auto const previewText =
236 tr(R"====(<div class="sectiontitle">CHAPTER 3</div>
237
238<div xml:lang="en" lang="en" class="sectiontitle">The New Birth</div>
239
240<span class="entryname">
241 <a name="crossref" href="sword://Bible/WEB/John 3:1">1</a>
242</span>
243<span lemma="G1161">Now</span>
244<span lemma="G444">there was a man</span>
245<span lemma="G5330">of the Pharisees</span>,
246<span lemma="G3686">named</span>
247<span class="crossreference">
248 <a href="sword://Bible/NASB/John 7:50;" name="crossref">John 7:50</a>;
249 <a href="sword://Bible/NASB/John 19:39;" name="crossref">19:39</a>
250</span>
251<span lemma="G3530">Nicodemus</span>, a
252<span class="crossreference">
253 <a href="sword://Bible/NASB/Luke 23:13;" name="crossref">Luke 23:13</a>;
254 <a href="sword://Bible/NASB/John 7:26;" name="crossref">John 7:26</a>,<a href="sword://Bible/NASB/John 7:48;" name="crossref">48</a>
255</span>
256<span lemma="G758">ruler</span>
257<span lemma="G2453">of the Jews</span>;
258
259<span class="entryname">
260 <a name="crossref" href="sword://Bible/WEB/John 3:2">2</a>
261</span>
262<span lemma="G3778">this</span>
263<span lemma="G3778">man</span>
264<span lemma="G2064">came</span>
265<span lemma="G3571">to Jesus by night</span>
266<span lemma="G3004">and said</span> to Him,
267<span class="crossreference">
268 <a href="sword://Bible/NASB/Matthew 23:7;" name="crossref">Matt 23:7</a>;
269 <a href="sword://Bible/NASB/John 3:26;" name="crossref">John 3:26</a>
270</span>
271"<span lemma="G4461">Rabbi</span>,
272<span lemma="G3609a">we know</span>
273<span lemma="G2064">that You have come</span>
274<span lemma="G2316">from God</span>
275<span class="transchange" title="Added text">
276 <span class="added">as</span>
277</span>
278<span lemma="G1320">a teacher</span>;
279<span lemma="G3762">for no</span>
280<span lemma="G3762">one</span>
281<span lemma="G1410">can</span>
282<span lemma="G4160">do</span>
283<span lemma="G3778">these</span>
284<span class="footnote" note="NASB/John 3:2/1">(1)</span>
285<span class="crossreference">
286 <a href="sword://Bible/NASB/John 2:11;" name="crossref">John 2:11</a>
287</span>
288<span lemma="G4592">signs</span>
289<span lemma="G4160">that You do</span>
290<span lemma="G1437|G3361">unless</span>
291<span class="crossreference">
292 <a href="sword://Bible/NASB/John 9:33;" name="crossref">John 9:33</a>;
293 <a href="sword://Bible/NASB/John 10:38;" name="crossref">10:38</a>;
294 <a href="sword://Bible/NASB/John 14:10-John 14:11;" name="crossref">
295 14:10f</a>;
296 <a href="sword://Bible/NASB/Acts 2:22;" name="crossref">Acts 2:22</a>;
297 <a href="sword://Bible/NASB/Acts 10:38;" name="crossref">10:38</a>
298</span>
299<span lemma="G2316">God</span> is with him."
300
301<span class="entryname">
302 <a name="crossref" href="sword://Bible/WEB/John 3:3">3</a>
303</span>
304<span lemma="G2424">Jesus answered and said to him</span>,
305<span class="jesuswords">
306 "Truly, truly, I say to you, unless one
307 <span class="crossreference">
308 <a href="sword://Bible/NASB/II Corinthians 5:17;" name="crossref">
309 2 Cor 5:17</a>;
310 <a href="sword://Bible/NASB/I Peter 1:23;" name="crossref">
311 1 Pet 1:23</a>
312 </span>
313 <span lemma="G1080">is born</span>
314 <span class="footnote" note="NASB/John 3:3/1">(1)</span>
315 <span lemma="G509">again</span>
316 <span lemma="G1410|G3756">he cannot</span>
317 <span lemma="G3708">see</span>
318 <span class="crossreference">
319 <a href="sword://Bible/NASB/Matthew 19:24;" name="crossref">
320 Matt 19:24</a>;
321 <a href="sword://Bible/NASB/Matthew 21:31;" name="crossref">21:31</a>;
322 <a href="sword://Bible/NASB/Mark 9:47;" name="crossref">Mark 9:47</a>;
323 <a href="sword://Bible/NASB/Mark 10:14-Mark 10:15;" name="crossref">
324 10:14f</a>;
325 <a href="sword://Bible/NASB/John 3:5;" name="crossref">John 3:5</a>
326 </span>
327 <span lemma="G932">the kingdom</span>
328 <span lemma="G2316">of God</span>."
329</span>)====",
330 "This markup is used to render the preview text in the settings "
331 "dialog. It contains a lot of markup because we want to "
332 "showcase multiple textual features to the user comparing "
333 "different display templates to choose from. For English we "
334 "have chosen to use John 3:1-3 but translations are free to use "
335 "other Bible passages as well as markup specific to the Bible "
336 "translations of the language as long as the text continues to "
337 "serve the intended purpose. At runtime, the translated text is "
338 "automatically split into multiple verses when empty lines (two "
339 "consecutive newline characters) are encountered.");
340 for (auto const & verse
341 : previewText.split(QStringLiteral("\n\n"), Qt::SkipEmptyParts))
342 tree.emplace_back(verse, settings);
343
344 CDisplayRendering render;
345 render.setDisplayTemplateName(styleName);
346 QString text = render.renderKeyTree(tree);
347 text.replace(QStringLiteral("#CHAPTERTITLE#"), QString());
348
349 // Update colors:
350 QPalette p = m_stylePreviewViewer->palette();
351 p.setColor(QPalette::Window, ColorManager::getBackgroundColor(styleName));
352 p.setColor(QPalette::WindowText,
354 m_stylePreviewViewer->setPalette(p);
355
356 text = ColorManager::replaceColors(text, styleName);
357 m_stylePreviewViewer->setText(text);
358}
359
361 btConfig().setValue(QStringLiteral("GUI/showSplashScreen"),
362 m_showLogoCheck->isChecked());
363 btConfig().setValue(QStringLiteral("GUI/activeTemplateName"),
364 m_styleChooserCombo->currentText());
365 btConfig().setValue(QStringLiteral("GUI/booknameLanguage"),
366 m_swordLocaleCombo->itemData(
367 m_swordLocaleCombo->currentIndex()));
368 btConfig().setValue(QStringLiteral("GUI/lightDarkMode"),
369 m_lightDarkCombo->currentIndex());
370}
#define BT_ASSERT(...)
Definition btassert.h:17
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
#define BT_CONNECT(...)
Definition btconnect.h:20
void setValue(QString const &key, T const &value)
Sets a value for a key.
void setHeaderText(QString const &headerText)
QString booknameLanguage()
Definition btconfig.cpp:463
QComboBox * m_swordLocaleCombo
CDisplaySettingsPage(CConfigurationDialog *parent=nullptr)
static QList< QString > bookNameAbbreviationsTryVector()
void save() const final override
QComboBox * m_styleChooserCombo
static QString activeTemplateName()
static CDisplayTemplateMgr * instance()
QStringList const & availableTemplates() const
static std::shared_ptr< Language const > fromAbbrev(QString const &abbrev)
Definition language.cpp:329
Rendering for the html display widget.
void setDisplayTemplateName(QString displayTemplateName) noexcept
std::list< KeyTreeItem > KeyTree
QString renderKeyTree(KeyTree const &tree) const
std::map< sword::SWBuf, sword::SWLocale * > const & internalSwordLocales()
QString getForegroundColor()
QString getBackgroundColor()
QString replaceColors(QString content)
QString fixSwordBcp47(QString input)
Definition tool.cpp:120