1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "promotionmodel_p.h"
30 #include "widgetdatabase_p.h"
31 
32 #include <QtDesigner/abstractwidgetdatabase.h>
33 #include <QtDesigner/abstractpromotioninterface.h>
34 #include <QtDesigner/abstractformeditor.h>
35 
36 #include <QtGui/qstandarditemmodel.h>
37 #include <QtCore/qcoreapplication.h>
38 
39 QT_BEGIN_NAMESPACE
40 
41 namespace {
42     using StandardItemList = QList<QStandardItem *>;
43 
44     // Model columns.
45     enum { ClassNameColumn, IncludeFileColumn, IncludeTypeColumn, ReferencedColumn, NumColumns };
46 
47     // Create a model row.
modelRow()48     StandardItemList modelRow() {
49         StandardItemList rc;
50         for (int i = 0; i < NumColumns; i++) {
51             rc.push_back(new QStandardItem());
52         }
53         return rc;
54     }
55 
56     // Create a model row for a base class (read-only, cannot be selected).
baseModelRow(const QDesignerWidgetDataBaseItemInterface * dbItem)57     StandardItemList baseModelRow(const QDesignerWidgetDataBaseItemInterface *dbItem) {
58         StandardItemList rc =  modelRow();
59 
60         rc[ClassNameColumn]->setText(dbItem->name());
61         for (int i = 0; i < NumColumns; i++) {
62             rc[i]->setFlags(Qt::ItemIsEnabled);
63         }
64         return rc;
65     }
66 
67     // Create an editable model row for a promoted class.
promotedModelRow(QDesignerWidgetDataBaseItemInterface * baseItem,QDesignerWidgetDataBaseItemInterface * dbItem,bool referenced)68     StandardItemList promotedModelRow(QDesignerWidgetDataBaseItemInterface *baseItem,
69                                       QDesignerWidgetDataBaseItemInterface *dbItem,
70                                       bool referenced)
71     {
72         qdesigner_internal::PromotionModel::ModelData data;
73         data.baseItem = baseItem;
74         data.promotedItem = dbItem;
75         data.referenced = referenced;
76 
77         const QVariant userData = QVariant::fromValue(data);
78 
79         StandardItemList rc =  modelRow();
80         // name
81         rc[ClassNameColumn]->setText(dbItem->name());
82         rc[ClassNameColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable);
83         rc[ClassNameColumn]->setData(userData);
84         // header
85         const qdesigner_internal::IncludeSpecification spec = qdesigner_internal::includeSpecification(dbItem->includeFile());
86         rc[IncludeFileColumn]->setText(spec.first);
87         rc[IncludeFileColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable);
88         rc[IncludeFileColumn]->setData(userData);
89         // global include
90         rc[IncludeTypeColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsUserCheckable);
91         rc[IncludeTypeColumn]->setData(userData);
92         rc[IncludeTypeColumn]->setCheckState(spec.second == qdesigner_internal::IncludeGlobal ? Qt::Checked : Qt::Unchecked);
93         // referenced
94         rc[ReferencedColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
95         rc[ClassNameColumn]->setData(userData);
96         if (!referenced) {
97             //: Usage of promoted widgets
98             static const QString notUsed = QCoreApplication::translate("PromotionModel", "Not used");
99             rc[ReferencedColumn]->setText(notUsed);
100         }
101         return rc;
102     }
103 }
104 
105 namespace qdesigner_internal {
106 
PromotionModel(QDesignerFormEditorInterface * core)107     PromotionModel::PromotionModel(QDesignerFormEditorInterface *core) :
108         m_core(core)
109     {
110         connect(this, &QStandardItemModel::itemChanged, this, &PromotionModel::slotItemChanged);
111     }
112 
initializeHeaders()113     void PromotionModel::initializeHeaders() {
114         setColumnCount(NumColumns);
115         QStringList horizontalLabels(tr("Name"));
116         horizontalLabels += tr("Header file");
117         horizontalLabels += tr("Global include");
118         horizontalLabels += tr("Usage");
119         setHorizontalHeaderLabels (horizontalLabels);
120     }
121 
updateFromWidgetDatabase()122     void PromotionModel::updateFromWidgetDatabase() {
123         using PromotedClasses = QDesignerPromotionInterface::PromotedClasses;
124 
125         clear();
126         initializeHeaders();
127 
128         // retrieve list of pairs from DB and convert into a tree structure.
129         // Set the item index as user data on the item.
130         const PromotedClasses promotedClasses = m_core->promotion()->promotedClasses();
131 
132         if (promotedClasses.isEmpty())
133             return;
134 
135         const QSet<QString> usedPromotedClasses = m_core->promotion()->referencedPromotedClassNames();
136 
137         QDesignerWidgetDataBaseItemInterface *baseClass = nullptr;
138         QStandardItem *baseItem = nullptr;
139 
140         const PromotedClasses::const_iterator bcend = promotedClasses.constEnd();
141         for (PromotedClasses::const_iterator it = promotedClasses.constBegin(); it !=  bcend; ++it) {
142             // Start a new base class?
143             if (baseClass !=  it->baseItem) {
144                 baseClass =  it->baseItem;
145                 const StandardItemList baseRow = baseModelRow(it->baseItem);
146                 baseItem = baseRow.constFirst();
147                 appendRow(baseRow);
148             }
149             Q_ASSERT(baseItem);
150             // Append derived
151             baseItem->appendRow(promotedModelRow(it->baseItem, it->promotedItem, usedPromotedClasses.contains(it->promotedItem->name())));
152         }
153     }
154 
slotItemChanged(QStandardItem * changedItem)155     void PromotionModel::slotItemChanged(QStandardItem * changedItem) {
156         // Retrieve DB item
157         const ModelData data = modelData(changedItem);
158         Q_ASSERT(data.isValid());
159         QDesignerWidgetDataBaseItemInterface *dbItem = data.promotedItem;
160         // Change header or type
161         switch (changedItem->column()) {
162         case ClassNameColumn:
163             emit classNameChanged(dbItem,  changedItem->text());
164             break;
165         case IncludeTypeColumn:
166         case IncludeFileColumn: {
167             // Get both file and type items via parent.
168             const QStandardItem *baseClassItem = changedItem->parent();
169             const QStandardItem *fileItem = baseClassItem->child(changedItem->row(), IncludeFileColumn);
170             const QStandardItem *typeItem =  baseClassItem->child(changedItem->row(), IncludeTypeColumn);
171             emit includeFileChanged(dbItem, buildIncludeFile(fileItem->text(), typeItem->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal));
172         }
173             break;
174         }
175     }
176 
modelData(const QStandardItem * item) const177     PromotionModel::ModelData PromotionModel::modelData(const QStandardItem *item) const
178     {
179         const QVariant userData = item->data();
180         return userData.canConvert<ModelData>() ? userData.value<ModelData>() : ModelData();
181     }
182 
modelData(const QModelIndex & index) const183     PromotionModel::ModelData PromotionModel::modelData(const QModelIndex &index) const
184     {
185         return index.isValid() ? modelData(itemFromIndex(index)) : ModelData();
186     }
187 
indexOfClass(const QString & className) const188     QModelIndex PromotionModel::indexOfClass(const QString &className) const {
189         const StandardItemList matches = findItems (className, Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive);
190         return matches.isEmpty() ? QModelIndex() : indexFromItem (matches.constFirst());
191     }
192 } // namespace qdesigner_internal
193 
194 QT_END_NAMESPACE
195