7#include <iconloader_p.h>
9#include <QtDesigner/abstractsettings.h>
11#include <QtGui/qfontdatabase.h>
12#include <QtGui/qstandarditemmodel.h>
14#include <QtWidgets/qboxlayout.h>
15#include <QtWidgets/qdialogbuttonbox.h>
16#include <QtWidgets/qfiledialog.h>
17#include <QtWidgets/qlayoutitem.h>
18#include <QtWidgets/qmessagebox.h>
19#include <QtWidgets/qtoolbutton.h>
20#include <QtWidgets/qtreeview.h>
22#include <QtCore/qalgorithms.h>
23#include <QtCore/qcoreapplication.h>
24#include <QtCore/qdebug.h>
25#include <QtCore/qfileinfo.h>
26#include <QtCore/qlist.h>
27#include <QtCore/qsettings.h>
28#include <QtCore/qstringlist.h>
34using namespace Qt::StringLiterals;
52 void save(QDesignerSettingsInterface *s,
const QString &prefix)
const;
53 void restore(
const QDesignerSettingsInterface *s,
const QString &prefix);
56 int add(
const QString &fontFile, QString *errorMessage);
58 bool remove(
int id, QString *errorMessage);
59 bool remove(
const QString &fontFile, QString *errorMessage);
60 bool removeAt(
int index, QString *errorMessage);
68 FileNameFontIdPairs m_fonts;
82 QStringList fontFiles;
83 for (
const auto &fnp : m_fonts)
84 fontFiles.push_back(fnp.first);
86 s->beginGroup(prefix);
87 s->setValue(fontFileKeyC, fontFiles);
91 qDebug() <<
"AppFontManager::saved" << fontFiles.size() <<
"fonts under " << prefix;
96 const QString key = prefix + u'/' + fontFileKeyC;
97 const QStringList fontFiles = s->value(key, QStringList()).toStringList();
100 qDebug() <<
"AppFontManager::restoring" << fontFiles.size() <<
"fonts from " << prefix;
101 if (!fontFiles.isEmpty()) {
102 QString errorMessage;
103 for (
const auto &ff : fontFiles) {
104 if (add(ff, &errorMessage) == -1)
105 qWarning(
"%s", qPrintable(errorMessage));
112 const QFileInfo inf(fontFile);
114 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"'%1' is not a file.").arg(fontFile);
117 if (!inf.isReadable()) {
118 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font file '%1' does not have read permissions.").arg(fontFile);
121 const QString fullPath = inf.absoluteFilePath();
123 for (
const auto &fnp : std::as_const(m_fonts)) {
124 if (fnp.first == fullPath) {
125 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font file '%1' is already loaded.").arg(fontFile);
130 const int id = QFontDatabase::addApplicationFont(fullPath);
132 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font file '%1' could not be loaded.").arg(fontFile);
137 qDebug() <<
"AppFontManager::add" << fontFile << id;
138 m_fonts.push_back(FileNameFontIdPair(fullPath, id));
144 for (qsizetype i = 0, count = m_fonts.size(); i < count; ++i)
145 if (m_fonts.at(i).second == id)
146 return removeAt(i, errorMessage);
148 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"'%1' is not a valid font id.").arg(id);
154 for (qsizetype i = 0, count = m_fonts.size(); i < count; ++i)
155 if (m_fonts.at(i).first == fontFile)
156 return removeAt(i, errorMessage);
158 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"There is no loaded font matching the id '%1'.").arg(fontFile);
164 Q_ASSERT(index >= 0 && index < m_fonts.size());
166 const QString fontFile = m_fonts[index].first;
167 const int id = m_fonts[index].second;
170 qDebug() <<
"AppFontManager::removeAt" << index <<
'(' << fontFile << id <<
')';
172 if (!QFontDatabase::removeApplicationFont(id)) {
173 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font '%1' (%2) could not be unloaded.").arg(fontFile).arg(id);
176 m_fonts.removeAt(index);
192 void add(
const QString &fontFile,
int id);
193 int idAt(
const QModelIndex &idx)
const;
197 QStandardItemModel(parent)
199 setHorizontalHeaderLabels(QStringList(AppFontWidget::tr(
"Fonts")));
204 using FileNameFontIdPairs = AppFontManager::FileNameFontIdPairs;
206 const FileNameFontIdPairs &fonts = mgr.fonts();
207 for (
const auto &fnp : fonts)
208 add(fnp.first, fnp.second);
213 const QFileInfo inf(fontFile);
215 auto *fileItem =
new QStandardItem(inf.completeBaseName());
216 const QString fullPath = inf.absoluteFilePath();
218 fileItem->setToolTip(fullPath);
219 fileItem->setData(id,
IdRole);
220 fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
223 const QStringList families = QFontDatabase::applicationFontFamilies(id);
224 for (
const auto &fam : families) {
225 auto *familyItem =
new QStandardItem(fam);
226 familyItem->setToolTip(fullPath);
227 familyItem->setFont(QFont(fam));
228 familyItem->setFlags(Qt::ItemIsEnabled);
229 fileItem->appendRow(familyItem);
235 if (
const QStandardItem *item = itemFromIndex(idx))
236 return item->data(
IdRole).toInt();
243 m_view(
new QTreeView),
244 m_addButton(
new QToolButton),
245 m_removeButton(
new QToolButton),
246 m_removeAllButton(
new QToolButton),
247 m_model(
new AppFontModel(
this))
250 m_view->setModel(m_model);
251 m_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
253 connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &
AppFontWidget::selectionChanged);
255 m_addButton->setToolTip(tr(
"Add font files"));
256 m_addButton->setIcon(qdesigner_internal::createIconSet(
"plus.png"_L1));
257 connect(m_addButton, &QAbstractButton::clicked,
this, &AppFontWidget::addFiles);
259 m_removeButton->setEnabled(
false);
260 m_removeButton->setToolTip(tr(
"Remove current font file"));
261 m_removeButton->setIcon(qdesigner_internal::createIconSet(
"minus.png"_L1));
262 connect(m_removeButton, &QAbstractButton::clicked,
this, &
AppFontWidget::slotRemoveFiles);
264 m_removeAllButton->setToolTip(tr(
"Remove all font files"));
265 m_removeAllButton->setIcon(qdesigner_internal::createIconSet(QIcon::ThemeIcon::EditDelete,
266 "editdelete.png"_L1));
267 connect(m_removeAllButton, &QAbstractButton::clicked,
this, &
AppFontWidget::slotRemoveAll);
269 auto *hLayout =
new QHBoxLayout;
270 hLayout->addWidget(m_addButton);
271 hLayout->addWidget(m_removeButton);
272 hLayout->addWidget(m_removeAllButton);
273 hLayout->addItem(
new QSpacerItem(0, 0,QSizePolicy::MinimumExpanding));
275 auto *vLayout =
new QVBoxLayout;
276 vLayout->addWidget(m_view);
277 vLayout->addLayout(hLayout);
283 const QStringList files =
284 QFileDialog::getOpenFileNames(
this, tr(
"Add Font Files"), QString(),
285 tr(
"Font files (*.ttf)"));
289 QString errorMessage;
292 for (
const auto &f : files) {
293 const int id = fmgr.add(f, &errorMessage);
297 QMessageBox::critical(
this, tr(
"Error Adding Fonts"), errorMessage);
305 if (selectedIndexes.isEmpty())
311 rows.reserve(selectedIndexes.size());
313 QString errorMessage;
314 for (
const auto &mi : selectedIndexes) {
315 const int id = model->idAt(mi);
317 if (fmgr.remove(id, &errorMessage)) {
318 rows.append(mi.row());
320 QMessageBox::critical(dialogParent, AppFontWidget::tr(
"Error Removing Fonts"), errorMessage);
325 std::stable_sort(rows.begin(), rows.end());
326 for (qsizetype i = rows.size() - 1; i >= 0; --i)
327 model->removeRow(rows.at(i));
332 removeFonts(m_view->selectionModel()->selectedIndexes(), m_model,
this);
337 const int count = m_model->rowCount();
341 const QMessageBox::StandardButton answer =
342 QMessageBox::question(
this, tr(
"Remove Fonts"), tr(
"Would you like to remove all fonts?"),
343 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
344 if (answer == QMessageBox::No)
347 QModelIndexList topLevels;
348 for (
int i = 0; i < count; i++)
349 topLevels.push_back(m_model->index(i, 0));
350 removeFonts(topLevels, m_model,
this);
353void AppFontWidget::selectionChanged(
const QItemSelection &selected,
const QItemSelection & )
355 m_removeButton->setEnabled(!selected.indexes().isEmpty());
358void AppFontWidget::save(QDesignerSettingsInterface *s,
const QString &prefix)
363void AppFontWidget::restore(
const QDesignerSettingsInterface *s,
const QString &prefix)
373 setAttribute(Qt::WA_DeleteOnClose,
true);
374 setWindowTitle(tr(
"Additional Fonts"));
376 auto *vl =
new QVBoxLayout(
this);
377 vl->addWidget(m_appFontWidget);
379 auto *bb =
new QDialogButtonBox(QDialogButtonBox::Close);
380 QDialog::connect(bb, &QDialogButtonBox::rejected,
this, &AppFontDialog::reject);
static void removeFonts(const QModelIndexList &selectedIndexes, AppFontModel *model, QWidget *dialogParent)
static constexpr auto fontFileKeyC
std::pair< QString, int > FileNameFontIdPair
bool removeAt(int index, QString *errorMessage)
void save(QDesignerSettingsInterface *s, const QString &prefix) const
int add(const QString &fontFile, QString *errorMessage)
static AppFontManager & instance()
void restore(const QDesignerSettingsInterface *s, const QString &prefix)
bool remove(int id, QString *errorMessage)
const FileNameFontIdPairs & fonts() const
bool remove(const QString &fontFile, QString *errorMessage)
void init(const AppFontManager &mgr)
int idAt(const QModelIndex &idx) const
void add(const QString &fontFile, int id)