1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Jochen Becher
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 
26 #include "elementtasks.h"
27 
28 #include "modelsmanager.h"
29 #include "openelementvisitor.h"
30 #include "modeleditor_plugin.h"
31 #include "componentviewcontroller.h"
32 
33 #include "qmt/diagram/delement.h"
34 #include "qmt/diagram/dpackage.h"
35 #include "qmt/document_controller/documentcontroller.h"
36 #include "qmt/infrastructure/contextmenuaction.h"
37 #include "qmt/model/melement.h"
38 #include "qmt/model/mclass.h"
39 #include "qmt/model/mdiagram.h"
40 #include "qmt/model/mcanvasdiagram.h"
41 #include "qmt/model/mpackage.h"
42 #include "qmt/model_controller/modelcontroller.h"
43 #include "qmt/tasks/finddiagramvisitor.h"
44 #include "qmt/project_controller/projectcontroller.h"
45 #include "qmt/project/project.h"
46 
47 #include <extensionsystem/pluginmanager.h>
48 #include <cpptools/cppclassesfilter.h>
49 #include <cpptools/indexitem.h>
50 #include <cpptools/searchsymbols.h>
51 #include <coreplugin/editormanager/editormanager.h>
52 #include <coreplugin/locator/ilocatorfilter.h>
53 #include <utils/qtcassert.h>
54 
55 #include <QMenu>
56 
57 namespace ModelEditor {
58 namespace Internal {
59 
60 class ElementTasks::ElementTasksPrivate {
61 public:
62     qmt::DocumentController *documentController = nullptr;
63     ComponentViewController *componentViewController = nullptr;
64 };
65 
ElementTasks(QObject * parent)66 ElementTasks::ElementTasks(QObject *parent)
67     : QObject(parent),
68       d(new ElementTasksPrivate)
69 {
70 }
71 
~ElementTasks()72 ElementTasks::~ElementTasks()
73 {
74     delete d;
75 }
76 
setDocumentController(qmt::DocumentController * documentController)77 void ElementTasks::setDocumentController(qmt::DocumentController *documentController)
78 {
79     d->documentController = documentController;
80 }
81 
setComponentViewController(ComponentViewController * componentViewController)82 void ElementTasks::setComponentViewController(ComponentViewController *componentViewController)
83 {
84     d->componentViewController = componentViewController;
85 }
86 
openElement(const qmt::MElement * element)87 void ElementTasks::openElement(const qmt::MElement *element)
88 {
89     OpenModelElementVisitor visitor;
90     visitor.setElementTasks(this);
91     element->accept(&visitor);
92 }
93 
openElement(const qmt::DElement * element,const qmt::MDiagram * diagram)94 void ElementTasks::openElement(const qmt::DElement *element, const qmt::MDiagram *diagram)
95 {
96     Q_UNUSED(diagram)
97 
98     OpenDiagramElementVisitor visitor;
99     visitor.setModelController(d->documentController->modelController());
100     visitor.setElementTasks(this);
101     element->accept(&visitor);
102 }
103 
hasClassDefinition(const qmt::MElement * element) const104 bool ElementTasks::hasClassDefinition(const qmt::MElement *element) const
105 {
106     if (auto klass = dynamic_cast<const qmt::MClass *>(element)) {
107         QString qualifiedClassName = klass->umlNamespace().isEmpty()
108                 ? klass->name()
109                 : klass->umlNamespace() + "::" + klass->name();
110 
111         Core::ILocatorFilter *classesFilter
112                 = CppTools::CppModelManager::instance()->classesFilter();
113         if (!classesFilter)
114             return false;
115 
116         QFutureInterface<Core::LocatorFilterEntry> dummyInterface;
117         QList<Core::LocatorFilterEntry> matches = classesFilter->matchesFor(dummyInterface,
118                                                                             qualifiedClassName);
119         foreach (const Core::LocatorFilterEntry &entry, matches) {
120             CppTools::IndexItem::Ptr info = qvariant_cast<CppTools::IndexItem::Ptr>(entry.internalData);
121             if (info->scopedSymbolName() != qualifiedClassName)
122                 continue;
123             return true;
124         }
125     }
126     return false;
127 }
128 
hasClassDefinition(const qmt::DElement * element,const qmt::MDiagram * diagram) const129 bool ElementTasks::hasClassDefinition(const qmt::DElement *element,
130                                       const qmt::MDiagram *diagram) const
131 {
132     Q_UNUSED(diagram)
133 
134     qmt::MElement *melement = d->documentController->modelController()->findElement(
135                 element->modelUid());
136     if (!melement)
137         return false;
138     return hasClassDefinition(melement);
139 }
140 
openClassDefinition(const qmt::MElement * element)141 void ElementTasks::openClassDefinition(const qmt::MElement *element)
142 {
143     if (auto klass = dynamic_cast<const qmt::MClass *>(element)) {
144         QString qualifiedClassName = klass->umlNamespace().isEmpty()
145                 ? klass->name()
146                 : klass->umlNamespace() + "::" + klass->name();
147 
148         Core::ILocatorFilter *classesFilter
149                 = CppTools::CppModelManager::instance()->classesFilter();
150         if (!classesFilter)
151             return;
152 
153         QFutureInterface<Core::LocatorFilterEntry> dummyInterface;
154         QList<Core::LocatorFilterEntry> matches = classesFilter->matchesFor(dummyInterface, qualifiedClassName);
155         foreach (const Core::LocatorFilterEntry &entry, matches) {
156             CppTools::IndexItem::Ptr info = qvariant_cast<CppTools::IndexItem::Ptr>(entry.internalData);
157             if (info->scopedSymbolName() != qualifiedClassName)
158                 continue;
159             if (Core::EditorManager::instance()->openEditorAt(info->fileName(), info->line(), info->column()))
160                 return;
161         }
162     }
163 }
164 
openClassDefinition(const qmt::DElement * element,const qmt::MDiagram * diagram)165 void ElementTasks::openClassDefinition(const qmt::DElement *element, const qmt::MDiagram *diagram)
166 {
167     Q_UNUSED(diagram)
168 
169     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
170     if (!melement)
171         return;
172     openClassDefinition(melement);
173 }
174 
hasHeaderFile(const qmt::MElement * element) const175 bool ElementTasks::hasHeaderFile(const qmt::MElement *element) const
176 {
177     // TODO implement
178     Q_UNUSED(element)
179     return false;
180 }
181 
hasHeaderFile(const qmt::DElement * element,const qmt::MDiagram * diagram) const182 bool ElementTasks::hasHeaderFile(const qmt::DElement *element, const qmt::MDiagram *diagram) const
183 {
184     Q_UNUSED(diagram)
185 
186     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
187     if (!melement)
188         return false;
189     return hasHeaderFile(melement);
190 }
191 
hasSourceFile(const qmt::MElement * element) const192 bool ElementTasks::hasSourceFile(const qmt::MElement *element) const
193 {
194     // TODO implement
195     Q_UNUSED(element)
196     return false;
197 }
198 
hasSourceFile(const qmt::DElement * element,const qmt::MDiagram * diagram) const199 bool ElementTasks::hasSourceFile(const qmt::DElement *element, const qmt::MDiagram *diagram) const
200 {
201     Q_UNUSED(diagram)
202 
203     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
204     if (!melement)
205         return false;
206     return hasSourceFile(melement);
207 }
208 
openHeaderFile(const qmt::MElement * element)209 void ElementTasks::openHeaderFile(const qmt::MElement *element)
210 {
211     // TODO implement
212     Q_UNUSED(element)
213 }
214 
openHeaderFile(const qmt::DElement * element,const qmt::MDiagram * diagram)215 void ElementTasks::openHeaderFile(const qmt::DElement *element, const qmt::MDiagram *diagram)
216 {
217     Q_UNUSED(diagram)
218 
219     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
220     if (!melement)
221         return;
222     openHeaderFile(melement);
223 }
224 
openSourceFile(const qmt::MElement * element)225 void ElementTasks::openSourceFile(const qmt::MElement *element)
226 {
227     // TODO implement
228     Q_UNUSED(element)
229 }
230 
openSourceFile(const qmt::DElement * element,const qmt::MDiagram * diagram)231 void ElementTasks::openSourceFile(const qmt::DElement *element, const qmt::MDiagram *diagram)
232 {
233     Q_UNUSED(diagram)
234 
235     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
236     if (!melement)
237         return;
238     openSourceFile(melement);
239 }
240 
hasFolder(const qmt::MElement * element) const241 bool ElementTasks::hasFolder(const qmt::MElement *element) const
242 {
243     // TODO implement
244     Q_UNUSED(element)
245     return false;
246 }
247 
hasFolder(const qmt::DElement * element,const qmt::MDiagram * diagram) const248 bool ElementTasks::hasFolder(const qmt::DElement *element, const qmt::MDiagram *diagram) const
249 {
250     Q_UNUSED(diagram)
251 
252     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
253     if (!melement)
254         return false;
255     return hasFolder(melement);
256 }
257 
showFolder(const qmt::MElement * element)258 void ElementTasks::showFolder(const qmt::MElement *element)
259 {
260     // TODO implement
261     Q_UNUSED(element)
262 }
263 
showFolder(const qmt::DElement * element,const qmt::MDiagram * diagram)264 void ElementTasks::showFolder(const qmt::DElement *element, const qmt::MDiagram *diagram)
265 {
266     Q_UNUSED(diagram)
267 
268     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
269     if (!melement)
270         return;
271     showFolder(melement);
272 }
273 
hasDiagram(const qmt::MElement * element) const274 bool ElementTasks::hasDiagram(const qmt::MElement *element) const
275 {
276     qmt::FindDiagramVisitor visitor;
277     element->accept(&visitor);
278     const qmt::MDiagram *diagram = visitor.diagram();
279     return diagram != nullptr;
280 }
281 
hasDiagram(const qmt::DElement * element,const qmt::MDiagram * diagram) const282 bool ElementTasks::hasDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram) const
283 {
284     Q_UNUSED(diagram)
285 
286     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
287     if (!melement)
288         return false;
289     return hasDiagram(melement);
290 }
291 
openDiagram(const qmt::MElement * element)292 void ElementTasks::openDiagram(const qmt::MElement *element)
293 {
294     qmt::FindDiagramVisitor visitor;
295     element->accept(&visitor);
296     const qmt::MDiagram *diagram = visitor.diagram();
297     if (diagram) {
298         ModelEditorPlugin::modelsManager()->openDiagram(
299                     d->documentController->projectController()->project()->uid(),
300                     diagram->uid());
301     }
302 }
303 
openDiagram(const qmt::DElement * element,const qmt::MDiagram * diagram)304 void ElementTasks::openDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram)
305 {
306     Q_UNUSED(diagram)
307 
308     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
309     if (!melement)
310         return;
311     openDiagram(melement);
312 }
313 
hasParentDiagram(const qmt::MElement * element) const314 bool ElementTasks::hasParentDiagram(const qmt::MElement *element) const
315 {
316     while (element && element->owner()) {
317         qmt::MObject *parentObject = element->owner()->owner();
318         if (parentObject) {
319             qmt::FindDiagramVisitor visitor;
320             parentObject->accept(&visitor);
321             const qmt::MDiagram *parentDiagram = visitor.diagram();
322             if (parentDiagram) {
323                 return true;
324             }
325         }
326         element = element->owner();
327     }
328     return false;
329 }
330 
hasParentDiagram(const qmt::DElement * element,const qmt::MDiagram * diagram) const331 bool ElementTasks::hasParentDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram) const
332 {
333     Q_UNUSED(diagram)
334 
335     if (!element)
336         return false;
337 
338     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
339     if (!melement)
340         return false;
341     return hasParentDiagram(melement);
342 }
343 
openParentDiagram(const qmt::MElement * element)344 void ElementTasks::openParentDiagram(const qmt::MElement *element)
345 {
346     while (element && element->owner()) {
347         qmt::MObject *parentObject = element->owner()->owner();
348         if (parentObject) {
349             qmt::FindDiagramVisitor visitor;
350             parentObject->accept(&visitor);
351             const qmt::MDiagram *parentDiagram = visitor.diagram();
352             if (parentDiagram) {
353                 ModelEditorPlugin::modelsManager()->openDiagram(
354                             d->documentController->projectController()->project()->uid(),
355                             parentDiagram->uid());
356                 return;
357             }
358         }
359         element = element->owner();
360     }
361 }
362 
openParentDiagram(const qmt::DElement * element,const qmt::MElement * diagram)363 void ElementTasks::openParentDiagram(const qmt::DElement *element, const qmt::MElement *diagram)
364 {
365     Q_UNUSED(diagram)
366 
367     if (!element)
368         return;
369 
370     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
371     if (!melement)
372         return;
373     openParentDiagram(melement);
374 }
375 
mayCreateDiagram(const qmt::MElement * element) const376 bool ElementTasks::mayCreateDiagram(const qmt::MElement *element) const
377 {
378     return dynamic_cast<const qmt::MPackage *>(element) != nullptr;
379 }
380 
mayCreateDiagram(const qmt::DElement * element,const qmt::MDiagram * diagram) const381 bool ElementTasks::mayCreateDiagram(const qmt::DElement *element,
382                                     const qmt::MDiagram *diagram) const
383 {
384     Q_UNUSED(diagram)
385 
386     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
387     if (!melement)
388         return false;
389     return mayCreateDiagram(melement);
390 }
391 
createAndOpenDiagram(const qmt::MElement * element)392 void ElementTasks::createAndOpenDiagram(const qmt::MElement *element)
393 {
394     if (auto package = dynamic_cast<const qmt::MPackage *>(element)) {
395         qmt::FindDiagramVisitor visitor;
396         element->accept(&visitor);
397         const qmt::MDiagram *diagram = visitor.diagram();
398         if (diagram) {
399             ModelEditorPlugin::modelsManager()->openDiagram(
400                         d->documentController->projectController()->project()->uid(),
401                         diagram->uid());
402         } else {
403             auto newDiagram = new qmt::MCanvasDiagram();
404             newDiagram->setName(package->name());
405             qmt::MPackage *parentPackage = d->documentController->modelController()->findObject<qmt::MPackage>(package->uid());
406             QMT_ASSERT(parentPackage, delete newDiagram; return);
407             d->documentController->modelController()->addObject(parentPackage, newDiagram);
408             ModelEditorPlugin::modelsManager()->openDiagram(
409                         d->documentController->projectController()->project()->uid(),
410                         newDiagram->uid());
411         }
412     }
413 }
414 
createAndOpenDiagram(const qmt::DElement * element,const qmt::MDiagram * diagram)415 void ElementTasks::createAndOpenDiagram(const qmt::DElement *element, const qmt::MDiagram *diagram)
416 {
417     Q_UNUSED(diagram)
418 
419     qmt::MElement *melement = d->documentController->modelController()->findElement(element->modelUid());
420     if (!melement)
421         return;
422     createAndOpenDiagram(melement);
423 }
424 
extendContextMenu(const qmt::DElement * delement,const qmt::MDiagram *,QMenu * menu)425 bool ElementTasks::extendContextMenu(const qmt::DElement *delement, const qmt::MDiagram *, QMenu *menu)
426 {
427     bool extended = false;
428     if (dynamic_cast<const qmt::DPackage *>(delement)) {
429         menu->addAction(new qmt::ContextMenuAction(tr("Update Include Dependencies"), "updateIncludeDependencies", menu));
430         extended = true;
431     }
432     return extended;
433 }
434 
handleContextMenuAction(const qmt::DElement * element,const qmt::MDiagram *,const QString & id)435 bool ElementTasks::handleContextMenuAction(const qmt::DElement *element, const qmt::MDiagram *, const QString &id)
436 {
437     if (id == "updateIncludeDependencies") {
438         qmt::MPackage *mpackage = d->documentController->modelController()->findElement<qmt::MPackage>(element->modelUid());
439         if (mpackage)
440             d->componentViewController->updateIncludeDependencies(mpackage);
441         return true;
442     }
443     return false;
444 }
445 
446 } // namespace Internal
447 } // namespace ModelEditor
448