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