1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #include "promotionmodel_p.h" |
5 | #include "widgetdatabase_p.h" |
6 | |
7 | #include <QtDesigner/abstractwidgetdatabase.h> |
8 | #include <QtDesigner/abstractpromotioninterface.h> |
9 | #include <QtDesigner/abstractformeditor.h> |
10 | |
11 | #include <QtGui/qstandarditemmodel.h> |
12 | #include <QtCore/qcoreapplication.h> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | namespace { |
17 | using StandardItemList = QList<QStandardItem *>; |
18 | |
19 | // Model columns. |
20 | enum { ClassNameColumn, IncludeFileColumn, IncludeTypeColumn, ReferencedColumn, NumColumns }; |
21 | |
22 | // Create a model row. |
23 | StandardItemList modelRow() { |
24 | StandardItemList rc; |
25 | for (int i = 0; i < NumColumns; i++) { |
26 | rc.push_back(t: new QStandardItem()); |
27 | } |
28 | return rc; |
29 | } |
30 | |
31 | // Create a model row for a base class (read-only, cannot be selected). |
32 | StandardItemList baseModelRow(const QDesignerWidgetDataBaseItemInterface *dbItem) { |
33 | StandardItemList rc = modelRow(); |
34 | |
35 | rc[ClassNameColumn]->setText(dbItem->name()); |
36 | for (int i = 0; i < NumColumns; i++) { |
37 | rc[i]->setFlags(Qt::ItemIsEnabled); |
38 | } |
39 | return rc; |
40 | } |
41 | |
42 | // Create an editable model row for a promoted class. |
43 | StandardItemList promotedModelRow(QDesignerWidgetDataBaseItemInterface *baseItem, |
44 | QDesignerWidgetDataBaseItemInterface *dbItem, |
45 | bool referenced) |
46 | { |
47 | qdesigner_internal::PromotionModel::ModelData data; |
48 | data.baseItem = baseItem; |
49 | data.promotedItem = dbItem; |
50 | data.referenced = referenced; |
51 | |
52 | const QVariant userData = QVariant::fromValue(value: data); |
53 | |
54 | StandardItemList rc = modelRow(); |
55 | // name |
56 | rc[ClassNameColumn]->setText(dbItem->name()); |
57 | rc[ClassNameColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable); |
58 | rc[ClassNameColumn]->setData(value: userData); |
59 | // header |
60 | const qdesigner_internal::IncludeSpecification spec = qdesigner_internal::includeSpecification(includeFile: dbItem->includeFile()); |
61 | rc[IncludeFileColumn]->setText(spec.first); |
62 | rc[IncludeFileColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable); |
63 | rc[IncludeFileColumn]->setData(value: userData); |
64 | // global include |
65 | rc[IncludeTypeColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsUserCheckable); |
66 | rc[IncludeTypeColumn]->setData(value: userData); |
67 | rc[IncludeTypeColumn]->setCheckState(spec.second == qdesigner_internal::IncludeGlobal ? Qt::Checked : Qt::Unchecked); |
68 | // referenced |
69 | rc[ReferencedColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); |
70 | rc[ClassNameColumn]->setData(value: userData); |
71 | if (!referenced) { |
72 | //: Usage of promoted widgets |
73 | static const QString notUsed = QCoreApplication::translate(context: "PromotionModel" , key: "Not used" ); |
74 | rc[ReferencedColumn]->setText(notUsed); |
75 | } |
76 | return rc; |
77 | } |
78 | } |
79 | |
80 | namespace qdesigner_internal { |
81 | |
82 | PromotionModel::PromotionModel(QDesignerFormEditorInterface *core) : |
83 | m_core(core) |
84 | { |
85 | connect(sender: this, signal: &QStandardItemModel::itemChanged, context: this, slot: &PromotionModel::slotItemChanged); |
86 | } |
87 | |
88 | void PromotionModel::() { |
89 | setColumnCount(NumColumns); |
90 | QStringList horizontalLabels(tr(s: "Name" )); |
91 | horizontalLabels += tr(s: "Header file" ); |
92 | horizontalLabels += tr(s: "Global include" ); |
93 | horizontalLabels += tr(s: "Usage" ); |
94 | setHorizontalHeaderLabels (horizontalLabels); |
95 | } |
96 | |
97 | void PromotionModel::updateFromWidgetDatabase() { |
98 | using PromotedClasses = QDesignerPromotionInterface::PromotedClasses; |
99 | |
100 | clear(); |
101 | initializeHeaders(); |
102 | |
103 | // retrieve list of pairs from DB and convert into a tree structure. |
104 | // Set the item index as user data on the item. |
105 | const PromotedClasses promotedClasses = m_core->promotion()->promotedClasses(); |
106 | |
107 | if (promotedClasses.isEmpty()) |
108 | return; |
109 | |
110 | const QSet<QString> usedPromotedClasses = m_core->promotion()->referencedPromotedClassNames(); |
111 | |
112 | QDesignerWidgetDataBaseItemInterface *baseClass = nullptr; |
113 | QStandardItem *baseItem = nullptr; |
114 | |
115 | for (auto &pi : promotedClasses) { |
116 | // Start a new base class? |
117 | if (baseClass != pi.baseItem) { |
118 | baseClass = pi.baseItem; |
119 | const StandardItemList baseRow = baseModelRow(dbItem: pi.baseItem); |
120 | baseItem = baseRow.constFirst(); |
121 | appendRow(items: baseRow); |
122 | } |
123 | Q_ASSERT(baseItem); |
124 | // Append derived |
125 | baseItem->appendRow(aitems: promotedModelRow(baseItem: pi.baseItem, dbItem: pi.promotedItem, |
126 | referenced: usedPromotedClasses.contains(value: pi.promotedItem->name()))); |
127 | } |
128 | } |
129 | |
130 | void PromotionModel::slotItemChanged(QStandardItem * changedItem) { |
131 | // Retrieve DB item |
132 | const ModelData data = modelData(item: changedItem); |
133 | Q_ASSERT(data.isValid()); |
134 | QDesignerWidgetDataBaseItemInterface *dbItem = data.promotedItem; |
135 | // Change header or type |
136 | switch (changedItem->column()) { |
137 | case ClassNameColumn: |
138 | emit classNameChanged(dbItem, newName: changedItem->text()); |
139 | break; |
140 | case IncludeTypeColumn: |
141 | case IncludeFileColumn: { |
142 | // Get both file and type items via parent. |
143 | const QStandardItem *baseClassItem = changedItem->parent(); |
144 | const QStandardItem *fileItem = baseClassItem->child(row: changedItem->row(), column: IncludeFileColumn); |
145 | const QStandardItem *typeItem = baseClassItem->child(row: changedItem->row(), column: IncludeTypeColumn); |
146 | emit includeFileChanged(dbItem, includeFile: buildIncludeFile(includeFile: fileItem->text(), includeType: typeItem->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal)); |
147 | } |
148 | break; |
149 | } |
150 | } |
151 | |
152 | PromotionModel::ModelData PromotionModel::modelData(const QStandardItem *item) const |
153 | { |
154 | const QVariant userData = item->data(); |
155 | return userData.canConvert<ModelData>() ? userData.value<ModelData>() : ModelData(); |
156 | } |
157 | |
158 | PromotionModel::ModelData PromotionModel::modelData(const QModelIndex &index) const |
159 | { |
160 | return index.isValid() ? modelData(item: itemFromIndex(index)) : ModelData(); |
161 | } |
162 | |
163 | QModelIndex PromotionModel::indexOfClass(const QString &className) const { |
164 | const StandardItemList matches = findItems (text: className, flags: Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive); |
165 | return matches.isEmpty() ? QModelIndex() : indexFromItem (item: matches.constFirst()); |
166 | } |
167 | } // namespace qdesigner_internal |
168 | |
169 | QT_END_NAMESPACE |
170 | |