1 #pragma once
2 
3 /*
4  * SPDX-FileCopyrightText: 2003-2007 Craig Drummond <craig@kde.org>
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  */
7 
8 #include "Family.h"
9 #include "FcQuery.h"
10 #include "File.h"
11 #include "FontFilter.h"
12 #include "FontInst.h"
13 #include "JobRunner.h"
14 #include "Misc.h"
15 #include "Style.h"
16 #include <KFileItem>
17 #include <KIO/Job>
18 #include <QAbstractItemModel>
19 #include <QHash>
20 #include <QList>
21 #include <QModelIndex>
22 #include <QSet>
23 #include <QSortFilterProxyModel>
24 #include <QTreeView>
25 #include <QUrl>
26 #include <QVariant>
27 
28 class KFileItem;
29 class QMenu;
30 class QMimeData;
31 class QTimer;
32 
33 #define KFI_FONT_DRAG_MIME "kfontinst/fontlist"
34 
35 namespace KFI
36 {
37 class CFontItem;
38 class CFontItem;
39 class CFamilyItem;
40 class CGroupListItem;
41 class Style;
42 
43 enum EColumns {
44     COL_FONT,
45     COL_STATUS,
46 
47     NUM_COLS,
48 };
49 
50 typedef QList<CFamilyItem *> CFamilyItemCont;
51 typedef QList<CFontItem *> CFontItemCont;
52 typedef QHash<QString, CFamilyItem *> CFamilyItemHash;
53 
54 class CFontList : public QAbstractItemModel
55 {
56     Q_OBJECT
57 
58 private:
59     enum EMsgType {
60         MSG_ADD,
61         MSG_DEL,
62 
63         NUM_MSGS_TYPES,
64     };
65 
66 public:
67     static const QStringList fontMimeTypes;
68 
69 public:
70     static QStringList compact(const QStringList &fonts);
71 
72     CFontList(QWidget *parent = nullptr);
73     ~CFontList() override;
74 
75     QVariant data(const QModelIndex &index, int role) const override;
76     Qt::ItemFlags flags(const QModelIndex &index) const override;
77     Qt::DropActions supportedDropActions() const override;
78     QMimeData *mimeData(const QModelIndexList &indexes) const override;
79     QStringList mimeTypes() const override;
80     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
81     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
82     QModelIndex parent(const QModelIndex &index) const override;
83     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
84     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
row(const CFamilyItem * fam)85     int row(const CFamilyItem *fam) const
86     {
87         return itsFamilies.indexOf((CFamilyItem *)fam);
88     }
89     void forceNewPreviews();
families()90     const CFamilyItemCont &families() const
91     {
92         return itsFamilies;
93     }
94     QModelIndex createIndex(int row, int column, void *data = nullptr) const
95     {
96         return QAbstractItemModel::createIndex(row, column, data);
97     }
hasFamily(const QString & family)98     bool hasFamily(const QString &family)
99     {
100         return nullptr != findFamily(family);
101     }
102     void refresh(bool allowSys, bool allowUser);
allowSys()103     bool allowSys() const
104     {
105         return itsAllowSys;
106     }
allowUser()107     bool allowUser() const
108     {
109         return itsAllowUser;
110     }
111     void getFamilyStats(QSet<QString> &enabled, QSet<QString> &disabled, QSet<QString> &partial);
112     void getFoundries(QSet<QString> &foundries) const;
113     QString whatsThis() const;
114     void setSlowUpdates(bool slow);
slowUpdates()115     bool slowUpdates() const
116     {
117         return itsSlowUpdates;
118     }
119 
120 Q_SIGNALS:
121 
122     void listingPercent(int p);
123 
124 public Q_SLOTS:
125 
126     void unsetSlowUpdates();
127     void load();
128 
129 private Q_SLOTS:
130 
131     void dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to);
132     void fontList(int pid, const QList<KFI::Families> &families);
133     void fontsAdded(const KFI::Families &families);
134     void fontsRemoved(const KFI::Families &families);
135 
136 private:
137     void storeSlowedMessage(const Families &families, EMsgType type);
138     void actionSlowedUpdates(bool sys);
139     void addFonts(const FamilyCont &families, bool sys);
140     void removeFonts(const FamilyCont &families, bool sys);
141     CFamilyItem *findFamily(const QString &familyName);
142 
143 private:
144     CFamilyItemCont itsFamilies;
145     CFamilyItemHash itsFamilyHash;
146     bool itsBlockSignals, itsAllowSys, itsAllowUser, itsSlowUpdates;
147     static int theirPreviewSize;
148     FamilyCont itsSlowedMsgs[NUM_MSGS_TYPES][FontInst::FOLDER_COUNT];
149 };
150 
151 class CFontModelItem
152 {
153 public:
CFontModelItem(CFontModelItem * p)154     CFontModelItem(CFontModelItem *p)
155         : itsParent(p)
156         , itsIsSystem(false)
157     {
158     }
~CFontModelItem()159     virtual ~CFontModelItem()
160     {
161     }
162 
parent()163     CFontModelItem *parent() const
164     {
165         return itsParent;
166     }
isFamily()167     bool isFamily() const
168     {
169         return nullptr == itsParent;
170     }
isFont()171     bool isFont() const
172     {
173         return nullptr != itsParent;
174     }
isSystem()175     bool isSystem() const
176     {
177         return itsIsSystem;
178     }
setIsSystem(bool sys)179     void setIsSystem(bool sys)
180     {
181         itsIsSystem = sys;
182     }
183     virtual int rowNumber() const = 0;
184 
185 protected:
186     CFontModelItem *itsParent;
187     bool itsIsSystem;
188 };
189 
190 class CFamilyItem : public CFontModelItem
191 {
192 public:
193     enum EStatus {
194         ENABLED,
195         PARTIAL,
196         DISABLED,
197     };
198 
199     CFamilyItem(CFontList &p, const Family &f, bool sys);
200     ~CFamilyItem() override;
201 
202     bool operator==(const CFamilyItem &other) const
203     {
204         return itsName == other.itsName;
205     }
206 
207     bool addFonts(const StyleCont &styles, bool sys);
name()208     const QString &name() const
209     {
210         return itsName;
211     }
fonts()212     const CFontItemCont &fonts() const
213     {
214         return itsFonts;
215     }
216     void addFont(CFontItem *font, bool update = true);
217     void removeFont(CFontItem *font, bool update);
218     void refresh();
219     bool updateStatus();
220     bool updateRegularFont(CFontItem *font);
221     CFontItem *findFont(quint32 style, bool sys);
rowNumber()222     int rowNumber() const override
223     {
224         return itsParent.row(this);
225     }
row(const CFontItem * font)226     int row(const CFontItem *font) const
227     {
228         return itsFonts.indexOf((CFontItem *)font);
229     }
status()230     EStatus status() const
231     {
232         return itsStatus;
233     }
realStatus()234     EStatus realStatus() const
235     {
236         return itsRealStatus;
237     }
regularFont()238     CFontItem *regularFont()
239     {
240         return itsRegularFont;
241     }
fontCount()242     int fontCount() const
243     {
244         return itsFontCount;
245     }
246     void getFoundries(QSet<QString> &foundries) const;
slowUpdates()247     bool slowUpdates() const
248     {
249         return itsParent.slowUpdates();
250     }
251 
252 private:
253     bool usable(const CFontItem *font, bool root);
254 
255 private:
256     QString itsName;
257     CFontItemCont itsFonts;
258     int itsFontCount;
259     EStatus itsStatus, itsRealStatus;
260     CFontItem *itsRegularFont; // 'RegularFont' is font nearest to 'Regular' style, and used for previews.
261     CFontList &itsParent;
262 };
263 
264 class CFontItem : public CFontModelItem
265 {
266 public:
267     CFontItem(CFontModelItem *p, const Style &s, bool sys);
~CFontItem()268     ~CFontItem() override
269     {
270     }
271 
272     void refresh();
name()273     QString name() const
274     {
275         return family() + QString::fromLatin1(", ") + itsStyleName;
276     }
isEnabled()277     bool isEnabled() const
278     {
279         return itsEnabled;
280     }
isHidden()281     bool isHidden() const
282     {
283         return !itsEnabled;
284     }
isBitmap()285     bool isBitmap() const
286     {
287         return !itsStyle.scalable();
288     }
fileName()289     const QString &fileName() const
290     {
291         return (*itsStyle.files().begin()).path();
292     }
style()293     const QString &style() const
294     {
295         return itsStyleName;
296     }
styleInfo()297     quint32 styleInfo() const
298     {
299         return itsStyle.value();
300     }
index()301     int index() const
302     {
303         return (*itsStyle.files().begin()).index();
304     }
family()305     const QString &family() const
306     {
307         return (static_cast<CFamilyItem *>(parent()))->name();
308     }
rowNumber()309     int rowNumber() const override
310     {
311         return (static_cast<CFamilyItem *>(parent()))->row(this);
312     }
files()313     const FileCont &files() const
314     {
315         return itsStyle.files();
316     }
writingSystems()317     qulonglong writingSystems() const
318     {
319         return itsStyle.writingSystems();
320     }
url()321     QUrl url() const
322     {
323         return CJobRunner::encode(family(), styleInfo(), isSystem());
324     }
removeFile(const File & f)325     void removeFile(const File &f)
326     {
327         itsStyle.remove(f);
328     }
removeFiles(const FileCont & f)329     void removeFiles(const FileCont &f)
330     {
331         itsStyle.removeFiles(f);
332     }
addFile(const File & f)333     void addFile(const File &f)
334     {
335         itsStyle.add(f);
336     }
addFiles(const FileCont & f)337     void addFiles(const FileCont &f)
338     {
339         itsStyle.addFiles(f);
340     }
341 
342 private:
343     QString itsStyleName;
344     Style itsStyle;
345     bool itsEnabled;
346 };
347 
348 class CFontListSortFilterProxy : public QSortFilterProxyModel
349 {
350     Q_OBJECT
351 
352 public:
353     CFontListSortFilterProxy(QObject *parent, QAbstractItemModel *model);
~CFontListSortFilterProxy()354     ~CFontListSortFilterProxy() override
355     {
356     }
357 
358     QVariant data(const QModelIndex &idx, int role) const override;
359     bool acceptFont(CFontItem *fnt, bool checkFontText) const;
360     bool acceptFamily(CFamilyItem *fam) const;
361     bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
362     bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
363     void setFilterGroup(CGroupListItem *grp);
filterGroup()364     CGroupListItem *filterGroup()
365     {
366         return itsGroup;
367     }
368 
369     void setFilterText(const QString &text);
370     void setFilterCriteria(CFontFilter::ECriteria crit, qulonglong ws, const QStringList &ft);
371 
372 private Q_SLOTS:
373 
374     void timeout();
375     void fcResults();
376 
377 Q_SIGNALS:
378 
379     void refresh();
380 
381 private:
filterText()382     QString filterText() const
383     {
384         return CFontFilter::CRIT_FONTCONFIG == itsFilterCriteria ? (itsFcQuery ? itsFcQuery->font() : QString()) : itsFilterText;
385     }
386 
387 private:
388     CGroupListItem *itsGroup;
389     QString itsFilterText;
390     CFontFilter::ECriteria itsFilterCriteria;
391     qulonglong itsFilterWs;
392     QStringList itsFilterTypes;
393     QTimer *itsTimer;
394     CFcQuery *itsFcQuery;
395 };
396 
397 class CFontListView : public QTreeView
398 {
399     Q_OBJECT
400 
401 public:
402     CFontListView(QWidget *parent, CFontList *model);
~CFontListView()403     ~CFontListView() override
404     {
405     }
406 
407     void getFonts(CJobRunner::ItemList &urls, QStringList &fontNames, QSet<Misc::TFont> *fonts, bool selected, bool getEnabled = true, bool getDisabled = true);
408     QSet<QString> getFiles();
409     void getPrintableFonts(QSet<Misc::TFont> &items, bool selected);
410     void setFilterGroup(CGroupListItem *grp);
411     void stats(int &enabled, int &disabled, int &partial);
412     void selectedStatus(bool &enabled, bool &disabled);
413     QModelIndexList allFonts();
414     void selectFirstFont();
415     QModelIndexList getSelectedItems();
416 
417 Q_SIGNALS:
418 
419     void del();
420     void print();
421     void enable();
422     void disable();
423     void fontsDropped(const QSet<QUrl> &);
424     void itemsSelected(const QModelIndexList &);
425     void refresh();
426     void reload();
427 
428 public Q_SLOTS:
429 
430     void listingPercent(int percent);
431     void refreshFilter();
432     void filterText(const QString &text);
433     void filterCriteria(int crit, qulonglong ws, const QStringList &ft);
434 
435 private Q_SLOTS:
436 
437     void setSortColumn(int col);
438     void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;
439     void itemCollapsed(const QModelIndex &index);
440     void view();
441 
442 private:
443     QModelIndexList allIndexes();
444     void startDrag(Qt::DropActions supportedActions) override;
445     void dragEnterEvent(QDragEnterEvent *event) override;
446     void dropEvent(QDropEvent *event) override;
447     void contextMenuEvent(QContextMenuEvent *ev) override;
448     bool viewportEvent(QEvent *event) override;
449 
450 private:
451     CFontListSortFilterProxy *itsProxy;
452     CFontList *itsModel;
453     QMenu *itsMenu;
454     QAction *itsDeleteAct, *itsEnableAct, *itsDisableAct, *itsPrintAct, *itsViewAct;
455     bool itsAllowDrops;
456 };
457 
458 }
459