1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "promotionmodel_p.h"
43 #include "widgetdatabase_p.h"
44 
45 #include <QtDesigner/QDesignerWidgetDataBaseInterface>
46 #include <QtDesigner/QDesignerPromotionInterface>
47 #include <QtDesigner/QDesignerFormEditorInterface>
48 
49 #include <QtGui/QStandardItem>
50 #include <QtCore/QCoreApplication>
51 
52 QT_BEGIN_NAMESPACE
53 
54 namespace {
55     typedef QList<QStandardItem *> StandardItemList;
56 
57     // Model columns.
58     enum { ClassNameColumn, IncludeFileColumn, IncludeTypeColumn, ReferencedColumn, NumColumns };
59 
60     // Create a model row.
modelRow()61     StandardItemList modelRow() {
62         StandardItemList rc;
63         for (int i = 0; i < NumColumns; i++) {
64             rc.push_back(new QStandardItem());
65         }
66         return rc;
67     }
68 
69     // Create a model row for a base class (read-only, cannot be selected).
baseModelRow(const QDesignerWidgetDataBaseItemInterface * dbItem)70     StandardItemList baseModelRow(const QDesignerWidgetDataBaseItemInterface *dbItem) {
71         StandardItemList rc =  modelRow();
72 
73         rc[ClassNameColumn]->setText(dbItem->name());
74         for (int i = 0; i < NumColumns; i++) {
75             rc[i]->setFlags(Qt::ItemIsEnabled);
76         }
77         return rc;
78     }
79 
80     // Create an editable model row for a promoted class.
promotedModelRow(const QDesignerWidgetDataBaseInterface * widgetDataBase,QDesignerWidgetDataBaseItemInterface * dbItem,bool referenced=false)81     StandardItemList promotedModelRow(const QDesignerWidgetDataBaseInterface *widgetDataBase,
82                                       QDesignerWidgetDataBaseItemInterface *dbItem,
83                                       bool referenced = false) {
84 
85         const int index = widgetDataBase->indexOf(dbItem);
86 
87         // Associate user data: database index and enabled flag
88         QVariantList userDataList;
89         userDataList.push_back(QVariant(index));
90         userDataList.push_back(QVariant(referenced));
91         const QVariant userData(userDataList);
92 
93         StandardItemList rc =  modelRow();
94         // name
95         rc[ClassNameColumn]->setText(dbItem->name());
96         rc[ClassNameColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable);
97         rc[ClassNameColumn]->setData(userData);
98         // header
99         const qdesigner_internal::IncludeSpecification spec = qdesigner_internal::includeSpecification(dbItem->includeFile());
100         rc[IncludeFileColumn]->setText(spec.first);
101         rc[IncludeFileColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable);
102         rc[IncludeFileColumn]->setData(userData);
103         // global include
104         rc[IncludeTypeColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsUserCheckable);
105         rc[IncludeTypeColumn]->setData(userData);
106         rc[IncludeTypeColumn]->setCheckState(spec.second == qdesigner_internal::IncludeGlobal ? Qt::Checked : Qt::Unchecked);
107         // referenced
108         rc[ReferencedColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
109         rc[ClassNameColumn]->setData(userData);
110         if (!referenced) {
111             //: Usage of promoted widgets
112             static const QString notUsed = QCoreApplication::translate("PromotionModel", "Not used");
113             rc[ReferencedColumn]->setText(notUsed);
114         }
115         return rc;
116     }
117 }
118 
119 namespace qdesigner_internal {
120 
PromotionModel(QDesignerFormEditorInterface * core)121     PromotionModel::PromotionModel(QDesignerFormEditorInterface *core) :
122         m_core(core)
123     {
124         connect(this, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotItemChanged(QStandardItem*)));
125     }
126 
initializeHeaders()127     void PromotionModel::initializeHeaders() {
128         setColumnCount(NumColumns);
129         QStringList horizontalLabels(tr("Name"));
130         horizontalLabels += tr("Header file");
131         horizontalLabels += tr("Global include");
132         horizontalLabels += tr("Usage");
133         setHorizontalHeaderLabels (horizontalLabels);
134     }
135 
updateFromWidgetDatabase()136     void PromotionModel::updateFromWidgetDatabase() {
137         typedef QDesignerPromotionInterface::PromotedClasses PromotedClasses;
138 
139         clear();
140         initializeHeaders();
141 
142         // retrieve list of pairs from DB and convert into a tree structure.
143         // Set the item index as user data on the item.
144         const PromotedClasses promotedClasses = m_core->promotion()->promotedClasses();
145 
146         if (promotedClasses.empty())
147             return;
148 
149         const QSet<QString> usedPromotedClasses = m_core->promotion()->referencedPromotedClassNames();
150 
151         QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase();
152         QDesignerWidgetDataBaseItemInterface *baseClass = 0;
153         QStandardItem *baseItem = 0;
154 
155         const PromotedClasses::const_iterator bcend = promotedClasses.constEnd();
156         for (PromotedClasses::const_iterator it = promotedClasses.constBegin(); it !=  bcend; ++it) {
157             // Start a new base class?
158             if (baseClass !=  it->baseItem) {
159                 baseClass =  it->baseItem;
160                 const StandardItemList baseRow = baseModelRow(it->baseItem);
161                 baseItem = baseRow.front();
162                 appendRow(baseRow);
163             }
164             Q_ASSERT(baseItem);
165             // Append derived
166             baseItem->appendRow(promotedModelRow(widgetDataBase, it->promotedItem, usedPromotedClasses.contains(it->promotedItem->name())));
167         }
168     }
169 
slotItemChanged(QStandardItem * changedItem)170     void PromotionModel::slotItemChanged(QStandardItem * changedItem) {
171         // Retrieve DB item
172         bool referenced;
173         QDesignerWidgetDataBaseItemInterface *dbItem = databaseItem(changedItem, &referenced);
174         Q_ASSERT(dbItem);
175         // Change header or type
176         switch (changedItem->column()) {
177         case ClassNameColumn:
178             emit classNameChanged(dbItem,  changedItem->text());
179             break;
180         case IncludeTypeColumn:
181         case IncludeFileColumn: {
182             // Get both file and type items via parent.
183             const QStandardItem *baseClassItem = changedItem->parent();
184             const QStandardItem *fileItem = baseClassItem->child(changedItem->row(), IncludeFileColumn);
185             const QStandardItem *typeItem =  baseClassItem->child(changedItem->row(), IncludeTypeColumn);
186             emit includeFileChanged(dbItem, buildIncludeFile(fileItem->text(), typeItem->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal));
187         }
188             break;
189         }
190     }
191 
databaseItemAt(const QModelIndex & index,bool * referenced) const192     QDesignerWidgetDataBaseItemInterface *PromotionModel::databaseItemAt(const QModelIndex &index, bool *referenced) const {
193         if (const QStandardItem *item = itemFromIndex (index))
194             return databaseItem(item, referenced);
195 
196         *referenced = false;
197         return 0;
198     }
199 
databaseItem(const QStandardItem * item,bool * referenced) const200     QDesignerWidgetDataBaseItemInterface *PromotionModel::databaseItem(const QStandardItem * item, bool *referenced) const {
201         // Decode user data associated with item.
202         const QVariant data =  item->data();
203         if (data.type() != QVariant::List) {
204             *referenced = false;
205             return 0;
206         }
207 
208         const QVariantList dataList = data.toList();
209         const int index = dataList[0].toInt();
210         *referenced     = dataList[1].toBool();
211         return  m_core->widgetDataBase()->item(index);
212     }
213 
indexOfClass(const QString & className) const214     QModelIndex PromotionModel::indexOfClass(const QString &className) const {
215         const StandardItemList matches = findItems (className, Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive);
216         return matches.empty() ? QModelIndex() : indexFromItem (matches.front());
217     }
218 } // namespace qdesigner_internal
219 
220 QT_END_NAMESPACE
221