1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 #include "eventlist.h"
26 #include "eventlistpluginview.h"
27 #include "eventlistview.h"
28 #include "nodelistview.h"
29
30 #include "bindingproperty.h"
31 #include "metainfo.h"
32 #include "projectexplorer/project.h"
33 #include "projectexplorer/session.h"
34 #include "qmldesignerplugin.h"
35 #include "signalhandlerproperty.h"
36 #include "utils/fileutils.h"
37 #include "utils/qtcassert.h"
38 #include "variantproperty.h"
39
40 #include <QDirIterator>
41 #include <QStandardItemModel>
42
43 namespace QmlDesigner {
44
projectFilePath()45 Utils::FilePath projectFilePath()
46 {
47 if (auto *doc = QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()) {
48 if (auto *proj = ProjectExplorer::SessionManager::projectForFile(doc->fileName()))
49 return proj->projectDirectory();
50 }
51 return Utils::FilePath();
52 }
53
findFile(const Utils::FilePath & path,const QString & fileName)54 static Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName)
55 {
56 QDirIterator it(path.toString(), QDirIterator::Subdirectories);
57
58 while (it.hasNext()) {
59 QFileInfo file(it.next());
60 if (file.isDir())
61 continue;
62
63 if (file.fileName() == fileName)
64 return Utils::FilePath::fromFileInfo(file);
65 }
66 return {};
67 }
68
69
70 NodeListView *EventList::st_nodeView = nullptr;
71
setNodeProperties(AbstractView * view)72 void EventList::setNodeProperties(AbstractView *view)
73 {
74 st_nodeView = new NodeListView(view);
75 }
76
selectNode(int internalId)77 void EventList::selectNode(int internalId)
78 {
79 if (st_nodeView)
80 st_nodeView->selectNode(internalId);
81 }
82
currentNode()83 int EventList::currentNode()
84 {
85 if (st_nodeView)
86 return st_nodeView->currentNode();
87
88 return -1;
89 }
90
hasEventListModel()91 bool EventList::hasEventListModel()
92 {
93 Utils::FilePath projectPath = projectFilePath();
94 if (projectPath.isEmpty())
95 return false;
96
97 Utils::FilePath path = findFile(projectPath, "EventListModel.qml");
98 return path.exists();
99 }
100
addEventIdToCurrent(const QString & eventId)101 void EventList::addEventIdToCurrent(const QString &eventId)
102 {
103 int iid = currentNode();
104 if (st_nodeView && iid >= 0)
105 st_nodeView->addEventId(iid, eventId);
106 }
107
removeEventIdFromCurrent(const QString & eventId)108 void EventList::removeEventIdFromCurrent(const QString &eventId)
109 {
110 int iid = currentNode();
111 if (st_nodeView && iid >= 0)
112 st_nodeView->removeEventIds(iid, {eventId});
113 }
114
setNodeId(int internalId,const QString & id)115 QString EventList::setNodeId(int internalId, const QString &id)
116 {
117 if (st_nodeView)
118 return st_nodeView->setNodeId(internalId, id);
119
120 return QString();
121 }
122
nodeModel()123 QStandardItemModel *EventList::nodeModel()
124 {
125 if (st_nodeView)
126 return st_nodeView->itemModel();
127
128 return nullptr;
129 }
130
nodeListView()131 NodeListView *EventList::nodeListView()
132 {
133 return st_nodeView;
134 }
135
modelNode(const QString & id)136 ModelNode EventList::modelNode(const QString &id)
137 {
138 if (st_nodeView)
139 return st_nodeView->modelNodeForId(id);
140
141 return ModelNode();
142 }
143
setSignalSource(SignalHandlerProperty & prop,const QString & source)144 void EventList::setSignalSource(SignalHandlerProperty &prop, const QString &source)
145 {
146 if (st_nodeView) {
147 QmlDesigner::Import import =
148 QmlDesigner::Import::createLibraryImport("QtQuick.Studio.EventSystem", "1.0");
149
150 if (!st_nodeView->model()->hasImport(import, true, true)) {
151 try {
152 st_nodeView->model()->changeImports({import}, {});
153 } catch (const QmlDesigner::Exception &) {
154 QTC_ASSERT(false, return );
155 }
156 }
157
158 if (source == "{}") {
159 if (ModelNode node = prop.parentModelNode(); node.isValid()) {
160 st_nodeView->executeInTransaction("EventList::removeProperty",
161 [&]() { node.removeProperty(prop.name()); });
162 }
163 }
164 else {
165 st_nodeView->executeInTransaction("EventList::setSource",
166 [&]() { prop.setSource(source); });
167 }
168 }
169 }
170
EventList()171 EventList::EventList()
172 : m_model(nullptr)
173 , m_eventView(nullptr)
174 , m_path()
175
176 {}
177
model() const178 Model *EventList::model() const
179 {
180 return m_model;
181 }
182
view() const183 EventListView *EventList::view() const
184 {
185 return m_eventView;
186 }
187
read() const188 QString EventList::read() const
189 {
190 if (!m_path.exists())
191 return QString();
192
193 Utils::FileReader reader;
194 QTC_ASSERT(reader.fetch(m_path), return QString());
195
196 return QString::fromUtf8(reader.data());
197 }
198
199
initialize(EventListPluginView * parent)200 void EventList::initialize(EventListPluginView *parent)
201 {
202 Utils::FilePath projectPath = projectFilePath();
203 QTC_ASSERT(!projectPath.isEmpty(), return );
204 m_path = findFile(projectPath, "EventListModel.qml");
205
206 if (!m_model) {
207 QByteArray unqualifiedTypeName = "ListModel";
208 auto metaInfo = parent->model()->metaInfo(unqualifiedTypeName);
209
210 QByteArray fullTypeName = metaInfo.typeName();
211 int minorVersion = metaInfo.minorVersion();
212 int majorVersion = metaInfo.majorVersion();
213
214 m_model = Model::create(fullTypeName, majorVersion, minorVersion);
215 m_model->setParent(parent);
216 }
217
218 if (!m_eventView) {
219 m_eventView = new EventListView(m_model);
220 m_model->attachView(m_eventView);
221 }
222 }
223
write(const QString & text)224 void EventList::write(const QString &text)
225 {
226 if (!m_path.exists())
227 return;
228
229 Utils::FileSaver writer(m_path);
230 writer.write(text.toUtf8());
231 writer.finalize();
232 }
233
234 } // namespace QmlDesigner.
235