RabbitCommon v2.3.3
Loading...
Searching...
No Matches
mimetypemodel.cpp
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
4#include "mimetypemodel.h"
5
6#include <QDebug>
7#include <QIcon>
8#include <QMimeDatabase>
9#include <QTextStream>
10#include <QVariant>
11
12#include <algorithm>
13
14Q_DECLARE_METATYPE(QMimeType)
15
16typedef QList<QStandardItem *> StandardItemList;
17
18enum { mimeTypeRole = Qt::UserRole + 1, iconQueriedRole = Qt::UserRole + 2 };
19
20QT_BEGIN_NAMESPACE
21bool operator<(const QMimeType &t1, const QMimeType &t2)
22{
23 return t1.name() < t2.name();
24}
25QT_END_NAMESPACE
26
27static StandardItemList createRow(const QMimeType &t)
28{
29 const QVariant v = QVariant::fromValue(t);
30 QStandardItem *nameItem = new QStandardItem(t.name());
31 const Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
32 nameItem->setData(v, mimeTypeRole);
33 nameItem->setData(QVariant(false), iconQueriedRole);
34 nameItem->setFlags(flags);
35 nameItem->setToolTip(t.comment());
36 return StandardItemList{nameItem};
37}
38
39MimetypeModel::MimetypeModel(QObject *parent)
40 : QStandardItemModel(0, ColumnCount, parent)
41{
42 setHorizontalHeaderLabels(QStringList{tr("Name")});
43 populate();
44}
45
46QVariant MimetypeModel::data(const QModelIndex &index, int role) const
47{
48 if (role != Qt::DecorationRole || !index.isValid() || index.data(iconQueriedRole).toBool())
49 return QStandardItemModel::data(index, role);
50 QStandardItem *item = itemFromIndex(index);
51 const QString iconName = qvariant_cast<QMimeType>(item->data(mimeTypeRole)).iconName();
52 if (!iconName.isEmpty())
53 item->setIcon(QIcon::fromTheme(iconName));
54 item->setData(QVariant(true), iconQueriedRole);
55 return item->icon();
56}
57
58QMimeType MimetypeModel::mimeType(const QModelIndex &index) const
59{
60 return qvariant_cast<QMimeType>(index.data(mimeTypeRole));
61}
62
63void MimetypeModel::populate()
64{
65 typedef QList<QMimeType>::Iterator Iterator;
66
67 QMimeDatabase mimeDatabase;
68 QList<QMimeType> allTypes = mimeDatabase.allMimeTypes();
69
70 // Move top level types to rear end of list, sort this partition,
71 // create top level items and truncate the list.
72 Iterator end = allTypes.end();
73 const Iterator topLevelStart =
74 std::stable_partition(allTypes.begin(), end,
75 [](const QMimeType &t) { return !t.parentMimeTypes().isEmpty(); });
76 std::stable_sort(topLevelStart, end);
77 for (Iterator it = topLevelStart; it != end; ++it) {
78 const StandardItemList row = createRow(*it);
79 appendRow(row);
80 m_nameIndexHash.insert(it->name(), indexFromItem(row.constFirst()));
81 }
82 allTypes.erase(topLevelStart, end);
83
84 while (!allTypes.isEmpty()) {
85 // Find a type inheriting one that is already in the model.
86 end = allTypes.end();
87 auto nameIndexIt = m_nameIndexHash.constEnd();
88 for (Iterator it = allTypes.begin(); it != end; ++it) {
89 nameIndexIt = m_nameIndexHash.constFind(it->parentMimeTypes().constFirst());
90 if (nameIndexIt != m_nameIndexHash.constEnd())
91 break;
92 }
93 if (nameIndexIt == m_nameIndexHash.constEnd()) {
94 qWarning() << "Orphaned mime types:" << allTypes;
95 break;
96 }
97
98 // Move types inheriting the parent type to rear end of list, sort this partition,
99 // append the items to parent and truncate the list.
100 const QString &parentName = nameIndexIt.key();
101 const Iterator start =
102 std::stable_partition(allTypes.begin(), end, [parentName](const QMimeType &t)
103 { return !t.parentMimeTypes().contains(parentName); });
104 std::stable_sort(start, end);
105 QStandardItem *parentItem = itemFromIndex(nameIndexIt.value());
106 for (Iterator it = start; it != end; ++it) {
107 const StandardItemList row = createRow(*it);
108 parentItem->appendRow(row);
109 m_nameIndexHash.insert(it->name(), indexFromItem(row.constFirst()));
110 }
111 allTypes.erase(start, end);
112 }
113}
114
115QTextStream &operator<<(QTextStream &stream, const QStringList &list)
116{
117 for (int i = 0, size = list.size(); i < size; ++i) {
118 if (i)
119 stream << ", ";
120 stream << list.at(i);
121 }
122 return stream;
123}
124
125QString MimetypeModel::formatMimeTypeInfo(const QMimeType &t)
126{
127 QString result;
128 QTextStream str(&result);
129 str << "<html><head/><body><h3><center>" << t.name() << "</center></h3><br><table>";
130
131 const QStringList &aliases = t.aliases();
132 if (!aliases.isEmpty())
133 str << "<tr><td>Aliases:</td><td>" << " (" << aliases << ')';
134
135 str << "</td></tr>"
136 << "<tr><td>Comment:</td><td>" << t.comment() << "</td></tr>"
137 << "<tr><td>Icon name:</td><td>" << t.iconName() << "</td></tr>"
138 << "<tr><td>Generic icon name</td><td>" << t.genericIconName() << "</td></tr>";
139
140 const QString &filter = t.filterString();
141 if (!filter.isEmpty())
142 str << "<tr><td>Filter:</td><td>" << t.filterString() << "</td></tr>";
143
144 const QStringList &patterns = t.globPatterns();
145 if (!patterns.isEmpty())
146 str << "<tr><td>Glob patterns:</td><td>" << patterns << "</td></tr>";
147
148 const QStringList &parentMimeTypes = t.parentMimeTypes();
149 if (!parentMimeTypes.isEmpty())
150 str << "<tr><td>Parent types:</td><td>" << t.parentMimeTypes() << "</td></tr>";
151
152 QStringList suffixes = t.suffixes();
153 if (!suffixes.isEmpty()) {
154 str << "<tr><td>Suffixes:</td><td>";
155 const QString &preferredSuffix = t.preferredSuffix();
156 if (!preferredSuffix.isEmpty()) {
157 suffixes.removeOne(preferredSuffix);
158 str << "<b>" << preferredSuffix << "</b> ";
159 }
160 str << suffixes << "</td></tr>";
161 }
162 str << "</table></body></html>";
163 return result;
164}