6#include <iconloader_p.h>
8#include <QtDesigner/abstractsettings.h>
10#include <QtGui/qfontdatabase.h>
11#include <QtGui/qstandarditemmodel.h>
13#include <QtWidgets/qboxlayout.h>
14#include <QtWidgets/qdialogbuttonbox.h>
15#include <QtWidgets/qfiledialog.h>
16#include <QtWidgets/qlayoutitem.h>
17#include <QtWidgets/qmessagebox.h>
18#include <QtWidgets/qtoolbutton.h>
19#include <QtWidgets/qtreeview.h>
21#include <QtCore/qalgorithms.h>
22#include <QtCore/qcoreapplication.h>
23#include <QtCore/qdebug.h>
24#include <QtCore/qfileinfo.h>
25#include <QtCore/qlist.h>
26#include <QtCore/qsettings.h>
27#include <QtCore/qstringlist.h>
33using namespace Qt::StringLiterals;
51 void save(QDesignerSettingsInterface *s,
const QString &prefix)
const;
52 void restore(
const QDesignerSettingsInterface *s,
const QString &prefix);
55 int add(
const QString &fontFile, QString *errorMessage);
57 bool remove(
int id, QString *errorMessage);
58 bool remove(
const QString &fontFile, QString *errorMessage);
59 bool removeAt(
int index, QString *errorMessage);
67 FileNameFontIdPairs m_fonts;
81 QStringList fontFiles;
82 for (
const auto &fnp : m_fonts)
83 fontFiles.push_back(fnp.first);
85 s->beginGroup(prefix);
86 s->setValue(fontFileKeyC, fontFiles);
90 qDebug() <<
"AppFontManager::saved" << fontFiles.size() <<
"fonts under " << prefix;
95 const QString key = prefix + u'/' + fontFileKeyC;
96 const QStringList fontFiles = s->value(key, QStringList()).toStringList();
99 qDebug() <<
"AppFontManager::restoring" << fontFiles.size() <<
"fonts from " << prefix;
100 if (!fontFiles.isEmpty()) {
101 QString errorMessage;
102 for (
const auto &ff : fontFiles) {
103 if (add(ff, &errorMessage) == -1)
104 qWarning(
"%s", qPrintable(errorMessage));
111 const QFileInfo inf(fontFile);
113 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"'%1' is not a file.").arg(fontFile);
116 if (!inf.isReadable()) {
117 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font file '%1' does not have read permissions.").arg(fontFile);
120 const QString fullPath = inf.absoluteFilePath();
122 for (
const auto &fnp : std::as_const(m_fonts)) {
123 if (fnp.first == fullPath) {
124 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font file '%1' is already loaded.").arg(fontFile);
129 const int id = QFontDatabase::addApplicationFont(fullPath);
131 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font file '%1' could not be loaded.").arg(fontFile);
136 qDebug() <<
"AppFontManager::add" << fontFile << id;
137 m_fonts.push_back(FileNameFontIdPair(fullPath, id));
143 for (qsizetype i = 0, count = m_fonts.size(); i < count; ++i)
144 if (m_fonts.at(i).second == id)
145 return removeAt(i, errorMessage);
147 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"'%1' is not a valid font id.").arg(id);
153 for (qsizetype i = 0, count = m_fonts.size(); i < count; ++i)
154 if (m_fonts.at(i).first == fontFile)
155 return removeAt(i, errorMessage);
157 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"There is no loaded font matching the id '%1'.").arg(fontFile);
163 Q_ASSERT(index >= 0 && index < m_fonts.size());
165 const QString fontFile = m_fonts[index].first;
166 const int id = m_fonts[index].second;
169 qDebug() <<
"AppFontManager::removeAt" << index <<
'(' << fontFile << id <<
')';
171 if (!QFontDatabase::removeApplicationFont(id)) {
172 *errorMessage = QCoreApplication::translate(
"AppFontManager",
"The font '%1' (%2) could not be unloaded.").arg(fontFile).arg(id);
175 m_fonts.removeAt(index);
191 void add(
const QString &fontFile,
int id);
192 int idAt(
const QModelIndex &idx)
const;
196 QStandardItemModel(parent)
198 setHorizontalHeaderLabels(QStringList(AppFontWidget::tr(
"Fonts")));
203 using FileNameFontIdPairs = AppFontManager::FileNameFontIdPairs;
205 const FileNameFontIdPairs &fonts = mgr.fonts();
206 for (
const auto &fnp : fonts)
207 add(fnp.first, fnp.second);
212 const QFileInfo inf(fontFile);
214 auto *fileItem =
new QStandardItem(inf.completeBaseName());
215 const QString fullPath = inf.absoluteFilePath();
217 fileItem->setToolTip(fullPath);
218 fileItem->setData(id,
IdRole);
219 fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
222 const QStringList families = QFontDatabase::applicationFontFamilies(id);
223 for (
const auto &fam : families) {
224 auto *familyItem =
new QStandardItem(fam);
225 familyItem->setToolTip(fullPath);
226 familyItem->setFont(QFont(fam));
227 familyItem->setFlags(Qt::ItemIsEnabled);
228 fileItem->appendRow(familyItem);
234 if (
const QStandardItem *item = itemFromIndex(idx))
235 return item->data(
IdRole).toInt();
242 m_view(
new QTreeView),
243 m_addButton(
new QToolButton),
244 m_removeButton(
new QToolButton),
245 m_removeAllButton(
new QToolButton),
246 m_model(
new AppFontModel(
this))
249 m_view->setModel(m_model);
250 m_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
252 connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &
AppFontWidget::selectionChanged);
254 m_addButton->setToolTip(tr(
"Add font files"));
255 m_addButton->setIcon(qdesigner_internal::createIconSet(
"plus.png"_L1));
256 connect(m_addButton, &QAbstractButton::clicked,
this, &AppFontWidget::addFiles);
258 m_removeButton->setEnabled(
false);
259 m_removeButton->setToolTip(tr(
"Remove current font file"));
260 m_removeButton->setIcon(qdesigner_internal::createIconSet(
"minus.png"_L1));
261 connect(m_removeButton, &QAbstractButton::clicked,
this, &
AppFontWidget::slotRemoveFiles);
263 m_removeAllButton->setToolTip(tr(
"Remove all font files"));
264 m_removeAllButton->setIcon(qdesigner_internal::createIconSet(QIcon::ThemeIcon::EditDelete,
265 "editdelete.png"_L1));
266 connect(m_removeAllButton, &QAbstractButton::clicked,
this, &
AppFontWidget::slotRemoveAll);
268 auto *hLayout =
new QHBoxLayout;
269 hLayout->addWidget(m_addButton);
270 hLayout->addWidget(m_removeButton);
271 hLayout->addWidget(m_removeAllButton);
272 hLayout->addItem(
new QSpacerItem(0, 0,QSizePolicy::MinimumExpanding));
274 auto *vLayout =
new QVBoxLayout;
275 vLayout->addWidget(m_view);
276 vLayout->addLayout(hLayout);
282 const QStringList files =
283 QFileDialog::getOpenFileNames(
this, tr(
"Add Font Files"), QString(),
284 tr(
"Font files (*.ttf)"));
288 QString errorMessage;
291 for (
const auto &f : files) {
292 const int id = fmgr.add(f, &errorMessage);
296 QMessageBox::critical(
this, tr(
"Error Adding Fonts"), errorMessage);
304 if (selectedIndexes.isEmpty())
310 rows.reserve(selectedIndexes.size());
312 QString errorMessage;
313 for (
const auto &mi : selectedIndexes) {
314 const int id = model->idAt(mi);
316 if (fmgr.remove(id, &errorMessage)) {
317 rows.append(mi.row());
319 QMessageBox::critical(dialogParent, AppFontWidget::tr(
"Error Removing Fonts"), errorMessage);
324 std::stable_sort(rows.begin(), rows.end());
325 for (qsizetype i = rows.size() - 1; i >= 0; --i)
326 model->removeRow(rows.at(i));
331 removeFonts(m_view->selectionModel()->selectedIndexes(), m_model,
this);
336 const int count = m_model->rowCount();
340 const QMessageBox::StandardButton answer =
341 QMessageBox::question(
this, tr(
"Remove Fonts"), tr(
"Would you like to remove all fonts?"),
342 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
343 if (answer == QMessageBox::No)
346 QModelIndexList topLevels;
347 for (
int i = 0; i < count; i++)
348 topLevels.push_back(m_model->index(i, 0));
349 removeFonts(topLevels, m_model,
this);
352void AppFontWidget::selectionChanged(
const QItemSelection &selected,
const QItemSelection & )
354 m_removeButton->setEnabled(!selected.indexes().isEmpty());
357void AppFontWidget::save(QDesignerSettingsInterface *s,
const QString &prefix)
362void AppFontWidget::restore(
const QDesignerSettingsInterface *s,
const QString &prefix)
372 setAttribute(Qt::WA_DeleteOnClose,
true);
373 setWindowTitle(tr(
"Additional Fonts"));
375 auto *vl =
new QVBoxLayout(
this);
376 vl->addWidget(m_appFontWidget);
378 auto *bb =
new QDialogButtonBox(QDialogButtonBox::Close);
379 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)