1 /*
2 SPDX-License-Identifier: GPL-2.0-or-later
3 SPDX-FileCopyrightText: 2002-2021 Umbrello UML Modeller Authors <umbrello-devel@kde.org>
4 */
5
6 // own header
7 #include "umllistview.h"
8
9 // app includes
10 #include "actor.h"
11 #include "classifier.h"
12 #include "cmds.h"
13 #include "debug_utils.h"
14 #include "dialog_utils.h"
15 #include "package.h"
16 #include "folder.h"
17 #include "component.h"
18 #include "node.h"
19 #include "artifact.h"
20 #include "enum.h"
21 #include "enumliteral.h"
22 #include "entity.h"
23 #include "category.h"
24 #include "datatype.h"
25 #include "docwindow.h"
26 #include "layoutgenerator.h"
27 #include "umllistviewpopupmenu.h"
28 #include "template.h"
29 #include "operation.h"
30 #include "attribute.h"
31 #include "entityattribute.h"
32 #include "instance.h"
33 #include "instanceattribute.h"
34 #include "uniqueconstraint.h"
35 #include "foreignkeyconstraint.h"
36 #include "checkconstraint.h"
37 #include "uml.h"
38 #include "umlclipboard.h"
39 #include "umldoc.h"
40 #include "umllistviewitemlist.h"
41 #include "umllistviewitem.h"
42 #include "umlscene.h"
43 #include "umlview.h"
44 #include "umlviewimageexporter.h"
45 #include "usecase.h"
46 #include "model_utils.h"
47 #include "models/diagramsmodel.h"
48 #include "optionstate.h"
49 #include "uniqueid.h"
50 #include "idchangelog.h"
51 #include "umldragdata.h"
52 #include "classpropertiesdialog.h"
53 #include "umlattributedialog.h"
54 #include "umlentityattributedialog.h"
55 #include "umloperationdialog.h"
56 #include "umltemplatedialog.h"
57 #include "umluniqueconstraintdialog.h"
58 #include "umlforeignkeyconstraintdialog.h"
59 #include "umlcheckconstraintdialog.h"
60 #include "object_factory.h"
61
62 // kde includes
63 #if QT_VERSION < 0x050000
64 #include <kfiledialog.h>
65 #endif
66 #include <KLocalizedString>
67 #include <KMessageBox>
68 #if QT_VERSION < 0x050000
69 #include <ktabwidget.h>
70 #endif
71
72 // qt includes
73 #include <QApplication>
74 #include <QDrag>
75 #include <QDropEvent>
76 #include <QEvent>
77 #if QT_VERSION >= 0x050000
78 #include <QFileDialog>
79 #endif
80 #include <QFocusEvent>
81 #include <QKeyEvent>
82 #include <QMouseEvent>
83 #include <QPointer>
84 #include <QRegExp>
85 #include <QPoint>
86 #include <QRect>
87 #include <QToolTip>
88 #include <QXmlStreamWriter>
89
DEBUG_REGISTER(UMLListView)90 DEBUG_REGISTER(UMLListView)
91
92 /**
93 * Constructs the tree view.
94 *
95 * @param parent The parent to this.
96 */
97 UMLListView::UMLListView(QWidget *parent)
98 : QTreeWidget(parent),
99 m_rv(nullptr),
100 m_datatypeFolder(nullptr),
101 m_settingsFolder(nullptr),
102 m_doc(UMLApp::app()->document()),
103 m_bStartedCut(false),
104 m_bStartedCopy(false),
105 m_bCreatingChildObject(false),
106 m_dragStartPosition(QPoint()),
107 m_dragCopyData(nullptr)
108 {
109 // setup list view
110 setAcceptDrops(true);
111 //setDropVisualizer(false);
112 //setItemsMovable(true);
113 //setItemsRenameable(true);
114 setSelectionMode(ExtendedSelection);
115 setFocusPolicy(Qt::StrongFocus);
116 setDragEnabled(true);
117 //setColumnWidthMode(0, Manual);
118 //setDefaultRenameAction(Accept);
119 //setResizeMode(LastColumn);
120 //header()->setClickEnabled(true);
121 //add columns and initial items
122 //addColumn(m_doc->name());
123 setSortingEnabled(true);
124 sortByColumn(0, Qt::AscendingOrder);
125
126 setEditTriggers(QAbstractItemView::EditKeyPressed);
127
128 for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) {
129 m_lv[i] = nullptr;
130 }
131
132 //setup slots/signals
133 connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(slotCollapsed(QTreeWidgetItem*)));
134 connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotExpanded(QTreeWidgetItem*)));
135 connect(UMLApp::app(), SIGNAL(sigCutSuccessful()), this, SLOT(slotCutSuccessful()));
136 connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(slotItemSelectionChanged()));
137 }
138
139 /**
140 * Standard destructor.
141 */
~UMLListView()142 UMLListView::~UMLListView()
143 {
144 clean(); // m_lv
145 delete m_datatypeFolder;
146 delete m_settingsFolder;
147 delete m_rv;
148 }
149
150 /**
151 * Sets the title.
152 * @param column column in which to write
153 * @param text the text to write
154 */
setTitle(int column,const QString & text)155 void UMLListView::setTitle(int column, const QString &text)
156 {
157 headerItem()->setText(column, text);
158 }
159
160 /**
161 * Handler for item selection changed signals.
162 */
slotItemSelectionChanged()163 void UMLListView::slotItemSelectionChanged()
164 {
165 UMLListViewItem* currItem = static_cast<UMLListViewItem*>(currentItem());
166 if (currItem && currItem->isSelected()) {
167 DEBUG(DBG_SRC) << "UMLListView selection changed to" << currItem->text(0);
168 // Update current view to selected object's view
169 if (Model_Utils::typeIsDiagram(currItem->type())) {
170 // If the user navigates to a diagram, load the diagram just like what
171 // would happen when clicking on it (includes saving/showing the documentation)
172 m_doc->changeCurrentView(currItem->ID());
173 } else {
174 // If the user navigates to any other item, save the current object's
175 // documentation and show selected object's documentation
176 UMLApp::app()->docWindow()->showDocumentation(currItem->umlObject(), true);
177 }
178 }
179 }
180
181 /**
182 * Event handler for the tool tip event.
183 * Works only for operations to show the signature.
184 */
event(QEvent * e)185 bool UMLListView::event(QEvent *e)
186 {
187 if (e->type() == QEvent::ToolTip) {
188 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
189 UMLListViewItem * item = static_cast<UMLListViewItem*>(itemAt(helpEvent->pos()));
190 if (item) {
191 QToolTip::showText(helpEvent->globalPos(), item->toolTip());
192 } else {
193 QToolTip::hideText();
194 e->ignore();
195 }
196 return true;
197 }
198 return QTreeWidget::event(e);
199 }
200
201 /**
202 * Handler for mouse press events.
203 * @param me the mouse event
204 */
mousePressEvent(QMouseEvent * me)205 void UMLListView::mousePressEvent(QMouseEvent *me)
206 {
207 UMLView *currentView = UMLApp::app()->currentView();
208 Q_ASSERT(currentView);
209 UMLScene *scene = currentView->umlScene();
210 Q_ASSERT(scene);
211 scene->clearSelected();
212 if (me->modifiers() != Qt::ShiftModifier)
213 clearSelection();
214
215 // Get the UMLListViewItem at the point where the mouse pointer was pressed
216 UMLListViewItem * item = static_cast<UMLListViewItem*>(itemAt(me->pos()));
217 if (item) {
218 DEBUG(DBG_SRC) << "QMouseEvent on" << UMLListViewItem::toString(item->type());
219 }
220 else {
221 DEBUG(DBG_SRC) << "QMouseEvent on empty space";
222 }
223
224 const Qt::MouseButton button = me->button();
225
226 if (!item || (button != Qt::RightButton && button != Qt::LeftButton)) {
227 UMLApp::app()->docWindow()->updateDocumentation(true);
228 return;
229 }
230
231 if (button == Qt::LeftButton) {
232 UMLObject *o = item->umlObject();
233 if (o)
234 UMLApp::app()->docWindow()->showDocumentation(o, false);
235 else
236 UMLApp::app()->docWindow()->updateDocumentation(true);
237
238 m_dragStartPosition = me->pos();
239 }
240
241 QTreeWidget::mousePressEvent(me);
242 }
243
244 /**
245 * Handler for mouse move events.
246 * @param me the mouse event
247 */
mouseMoveEvent(QMouseEvent * me)248 void UMLListView::mouseMoveEvent(QMouseEvent* me)
249 {
250 if (!(me->buttons() & Qt::LeftButton)) {
251 DEBUG(DBG_SRC) << "not LeftButton (no action)";
252 return;
253 }
254 if ((me->pos() - m_dragStartPosition).manhattanLength()
255 < QApplication::startDragDistance()) {
256 DEBUG(DBG_SRC) << "pos change since dragStart is below startDragDistance threshold (no action)";
257 return;
258 }
259
260 DEBUG(DBG_SRC) << "initiating drag";
261
262 // Store a copy of selected list items in case the user
263 // will ctrl-drag (basically just copy/paste) an item
264 //
265 // The QDrag mime data is used for moving items onto the diagram
266 // or internally in the tree view
267 UMLClipboard clipboard;
268 if ((m_dragCopyData = clipboard.copy(false)) == 0) {
269 // This should never happen, this is just like using ctrl+c on the list view item
270 uError() << "Unable to obtain mime data for copy-drag operation";
271 }
272
273 QDrag* drag = new QDrag(this);
274 drag->setMimeData(getDragData());
275 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
276 }
277
278 /**
279 * Handler for mouse release event.
280 * @param me the mouse event
281 */
mouseReleaseEvent(QMouseEvent * me)282 void UMLListView::mouseReleaseEvent(QMouseEvent *me)
283 {
284 if (me->button() != Qt::LeftButton) {
285 QTreeWidget::mouseReleaseEvent(me);
286 return;
287 }
288 UMLListViewItem *item = static_cast<UMLListViewItem*>(itemAt(me->pos()));
289 if (item == 0 || !Model_Utils::typeIsDiagram(item->type())) {
290 QTreeWidget::mouseReleaseEvent(me);
291 return;
292 }
293 // Switch to diagram on mouse release - not on mouse press
294 // because the user might intend a drag-to-note.
295 m_doc->changeCurrentView(item->ID());
296 UMLView *view = m_doc->findView(item->ID());
297 if (view && view->umlScene())
298 UMLApp::app()->docWindow()->showDocumentation(view->umlScene(), false);
299 QTreeWidget::mouseReleaseEvent(me);
300 }
301
302 /**
303 * Handler for key press events.
304 * @param ke the key event
305 */
keyPressEvent(QKeyEvent * ke)306 void UMLListView::keyPressEvent(QKeyEvent *ke)
307 {
308 QTreeWidget::keyPressEvent(ke); // let parent handle it
309 const int k = ke->key();
310 if (k == Qt::Key_Delete || k == Qt::Key_Backspace) {
311 slotDeleteSelectedItems();
312 } else if (k == Qt::Key_F3) {
313 // preliminary support for layout generator
314 LayoutGenerator r;
315 if (!r.generate(UMLApp::app()->currentView()->umlScene()))
316 return;
317 r.apply(UMLApp::app()->currentView()->umlScene());
318 }
319 }
320
321 /**
322 * Called when a right mouse button menu has an item selected.
323 * @param action the selected action
324 * @param position the position of the menu on the diagram (only used for multi selection "Show")
325 */
slotMenuSelection(QAction * action,const QPoint & position)326 void UMLListView::slotMenuSelection(QAction* action, const QPoint &position)
327 {
328 UMLListViewItem * currItem = static_cast<UMLListViewItem*>(currentItem());
329 if (!currItem) {
330 DEBUG(DBG_SRC) << "Invoked without currently selectedItem!";
331 return;
332 }
333 UMLListViewItem::ListViewType lvt = currItem->type();
334 ListPopupMenu::MenuType menuType = ListPopupMenu::typeFromAction(action);
335
336 switch (menuType) {
337 case ListPopupMenu::mt_Activity_Diagram:
338 addNewItem(currItem, UMLListViewItem::lvt_Activity_Diagram);
339 break;
340
341 case ListPopupMenu::mt_Class_Diagram:
342 addNewItem(currItem, UMLListViewItem::lvt_Class_Diagram);
343 break;
344
345 case ListPopupMenu::mt_Collaboration_Diagram:
346 addNewItem(currItem, UMLListViewItem::lvt_Collaboration_Diagram);
347 break;
348
349 case ListPopupMenu::mt_Component_Diagram:
350 addNewItem(currItem, UMLListViewItem::lvt_Component_Diagram);
351 break;
352
353 case ListPopupMenu::mt_Deployment_Diagram:
354 addNewItem(currItem, UMLListViewItem::lvt_Deployment_Diagram);
355 break;
356
357 case ListPopupMenu::mt_EntityRelationship_Diagram:
358 addNewItem(currItem, UMLListViewItem::lvt_EntityRelationship_Diagram);
359 break;
360
361 case ListPopupMenu::mt_Sequence_Diagram:
362 addNewItem(currItem, UMLListViewItem::lvt_Sequence_Diagram);
363 break;
364
365 case ListPopupMenu::mt_State_Diagram:
366 addNewItem(currItem, UMLListViewItem::lvt_State_Diagram);
367 break;
368
369 case ListPopupMenu::mt_UseCase_Diagram:
370 addNewItem(currItem, UMLListViewItem::lvt_UseCase_Diagram);
371 break;
372
373 case ListPopupMenu::mt_Class:
374 addNewItem(currItem, UMLListViewItem::lvt_Class);
375 break;
376
377 case ListPopupMenu::mt_Package:
378 addNewItem(currItem, UMLListViewItem::lvt_Package);
379 break;
380
381 case ListPopupMenu::mt_Subsystem:
382 addNewItem(currItem, UMLListViewItem::lvt_Subsystem);
383 break;
384
385 case ListPopupMenu::mt_Component:
386 addNewItem(currItem, UMLListViewItem::lvt_Component);
387 break;
388
389 case ListPopupMenu::mt_Port:
390 if (Settings::optionState().generalState.uml2)
391 addNewItem(currItem, UMLListViewItem::lvt_Port);
392 break;
393
394 case ListPopupMenu::mt_Node:
395 addNewItem(currItem, UMLListViewItem::lvt_Node);
396 break;
397
398 case ListPopupMenu::mt_Artifact:
399 addNewItem(currItem, UMLListViewItem::lvt_Artifact);
400 break;
401
402 case ListPopupMenu::mt_Interface:
403 addNewItem(currItem, UMLListViewItem::lvt_Interface);
404 break;
405
406 case ListPopupMenu::mt_Enum:
407 addNewItem(currItem, UMLListViewItem::lvt_Enum);
408 break;
409
410 case ListPopupMenu::mt_EnumLiteral:
411 addNewItem(currItem, UMLListViewItem::lvt_EnumLiteral);
412 break;
413
414 case ListPopupMenu::mt_Template:
415 addNewItem(currItem, UMLListViewItem::lvt_Template);
416 break;
417
418 case ListPopupMenu::mt_Entity:
419 addNewItem(currItem, UMLListViewItem::lvt_Entity);
420 break;
421
422 case ListPopupMenu::mt_Instance:
423 addNewItem(currItem, UMLListViewItem::lvt_Instance);
424 break;
425
426 case ListPopupMenu::mt_Category:
427 addNewItem(currItem, UMLListViewItem::lvt_Category);
428 break;
429
430 case ListPopupMenu::mt_DisjointSpecialisation:
431 {
432 UMLCategory* catObj = currItem->umlObject()->asUMLCategory();
433 catObj->setType(UMLCategory::ct_Disjoint_Specialisation);
434 }
435 break;
436
437 case ListPopupMenu::mt_OverlappingSpecialisation:
438 {
439 UMLCategory* catObj = currItem->umlObject()->asUMLCategory();
440 catObj->setType(UMLCategory::ct_Overlapping_Specialisation);
441 }
442 break;
443
444 case ListPopupMenu::mt_Union:
445 {
446 UMLCategory* catObj = currItem->umlObject()->asUMLCategory();
447 catObj->setType(UMLCategory::ct_Union);
448 }
449 break;
450
451 case ListPopupMenu::mt_Datatype:
452 addNewItem(currItem, UMLListViewItem::lvt_Datatype);
453 break;
454
455 case ListPopupMenu::mt_Actor:
456 addNewItem(currItem, UMLListViewItem::lvt_Actor);
457 break;
458
459 case ListPopupMenu::mt_UseCase:
460 addNewItem(currItem, UMLListViewItem::lvt_UseCase);
461 break;
462
463 case ListPopupMenu::mt_Attribute:
464 addNewItem(currItem, UMLListViewItem::lvt_Attribute);
465 break;
466
467 case ListPopupMenu::mt_EntityAttribute:
468 addNewItem(currItem, UMLListViewItem::lvt_EntityAttribute);
469 break;
470 case ListPopupMenu::mt_InstanceAttribute:
471 addNewItem(currItem, UMLListViewItem::lvt_InstanceAttribute);
472 break;
473 case ListPopupMenu::mt_Operation:
474 addNewItem(currItem, UMLListViewItem::lvt_Operation);
475 break;
476
477 case ListPopupMenu::mt_UniqueConstraint:
478 addNewItem(currItem, UMLListViewItem::lvt_UniqueConstraint);
479 break;
480
481 case ListPopupMenu::mt_PrimaryKeyConstraint:
482 addNewItem(currItem, UMLListViewItem::lvt_PrimaryKeyConstraint);
483 break;
484
485 case ListPopupMenu::mt_ForeignKeyConstraint:
486 addNewItem(currItem, UMLListViewItem::lvt_ForeignKeyConstraint);
487 break;
488
489 case ListPopupMenu::mt_CheckConstraint:
490 addNewItem(currItem, UMLListViewItem::lvt_CheckConstraint);
491 break;
492
493 case ListPopupMenu::mt_Import_Class:
494 UMLApp::app()->slotImportClass();
495 break;
496
497 case ListPopupMenu::mt_Import_Project:
498 UMLApp::app()->slotImportProject();
499 break;
500
501 case ListPopupMenu::mt_Expand_All:
502 expandAll(currItem);
503 break;
504
505 case ListPopupMenu::mt_Collapse_All:
506 collapseAll(currItem);
507 break;
508
509 case ListPopupMenu::mt_Export_Image:
510 {
511 const Uml::ID::Type id = currItem->ID();
512 UMLView *view = m_doc->findView(id);
513 if (view) {
514 if (view->umlScene())
515 view->umlScene()->getImageExporter()->exportView();
516 else
517 uError() << "ListPopupMenu::mt_Export_Image: view " << Uml::ID::toString(id)
518 << " umlScene() is NULL";
519 } else {
520 uError() << "ListPopupMenu::mt_Export_Image: m_doc->findView("
521 << Uml::ID::toString(id) << " returns NULL";
522 }
523 }
524 break;
525
526 case ListPopupMenu::mt_Externalize_Folder:
527 {
528 UMLListViewItem *current = static_cast<UMLListViewItem*>(currentItem());
529 UMLFolder *modelFolder = current->umlObject()->asUMLFolder();
530 if (modelFolder == 0) {
531 uError() << "modelFolder is 0";
532 return;
533 }
534 // configure & show the file dialog
535 #if QT_VERSION >= 0x050000
536 const QString rootDir(m_doc->url().adjusted(QUrl::RemoveFilename).path());
537 QPointer<QFileDialog> fileDialog = new QFileDialog(this, i18n("Externalize Folder"), rootDir, QLatin1String("*.xml"));
538 #else
539 const QString rootDir(m_doc->url().directory());
540 QPointer<KFileDialog> fileDialog = new KFileDialog(rootDir, QLatin1String("*.xml"), this);
541 fileDialog->setCaption(i18n("Externalize Folder"));
542 fileDialog->setOperationMode(KFileDialog::Other);
543 #endif
544 // set a sensible default filename
545 QString defaultFilename = current->text(0).toLower();
546 defaultFilename.replace(QRegExp(QLatin1String("\\W+")), QLatin1String("_"));
547 defaultFilename.append(QLatin1String(".xml")); // default extension
548 #if QT_VERSION >= 0x050000
549 fileDialog->selectFile(defaultFilename);
550 QList<QUrl> selURL;
551 if (fileDialog->exec() == QDialog::Accepted) {
552 selURL = fileDialog->selectedUrls();
553 }
554 #else
555 fileDialog->setSelection(defaultFilename);
556 KUrl selURL;
557 if (fileDialog->exec() == QDialog::Accepted) {
558 selURL = fileDialog->selectedUrl();
559 }
560 #endif
561 delete fileDialog;
562 if (selURL.isEmpty())
563 return;
564 #if QT_VERSION >= 0x050000
565 QString path = selURL[0].toLocalFile();
566 #else
567 QString path = selURL.toLocalFile();
568 #endif
569 QString fileName = path;
570 if (fileName.startsWith(rootDir)) {
571 fileName.remove(rootDir);
572 } else {
573 KMessageBox::error(
574 0,
575 i18n("Folder %1 must be relative to the main model directory, %2.", path, rootDir),
576 i18n("Path Error"));
577 return;
578 }
579 QFile file(path);
580 // Warn if file exists.
581 if (file.exists()) {
582 KMessageBox::error(
583 0,
584 i18n("File %1 already exists!\nThe existing file will be overwritten.", fileName),
585 i18n("File Exist"));
586 }
587 // Test if file is writable.
588 if (file.open(QIODevice::WriteOnly)) {
589 file.close();
590 } else {
591 KMessageBox::error(
592 0,
593 i18n("There was a problem saving file: %1", fileName),
594 i18n("Save Error"));
595 return;
596 }
597 modelFolder->setFolderFile(fileName);
598 // Recompute text of the folder
599 QString folderText = current->text(0);
600 folderText.remove(QRegExp(QLatin1String("\\s*\\(.*$")));
601 folderText.append(QLatin1String(" (") + fileName + QLatin1Char(')'));
602 current->setText(folderText);
603 break;
604 }
605
606 case ListPopupMenu::mt_Internalize_Folder:
607 {
608 UMLListViewItem *current = static_cast<UMLListViewItem*>(currentItem());
609 UMLFolder *modelFolder = current->umlObject()->asUMLFolder();
610 if (modelFolder == 0) {
611 uError() << "modelFolder is 0";
612 return;
613 }
614 modelFolder->setFolderFile(QString());
615 // Recompute text of the folder
616 QString folderText = current->text(0);
617 folderText.remove(QRegExp(QLatin1String("\\s*\\(.*$")));
618 current->setText(folderText);
619 break;
620 }
621
622 case ListPopupMenu::mt_Model:
623 {
624 QString name = m_doc->name();
625 bool ok = Dialog_Utils::askName(i18n("Enter Model Name"),
626 i18n("Enter the new name of the model:"),
627 name);
628 if (ok) {
629 setTitle(0, name);
630 m_doc->setName(name);
631 }
632 break;
633 }
634
635 case ListPopupMenu::mt_Open_File: {
636 UMLListViewItem *current = static_cast<UMLListViewItem*>(currentItem());
637 UMLArtifact *artifact = current->umlObject()->asUMLArtifact();
638 if (artifact == nullptr) {
639 uError() << "artifact is 0";
640 return;
641 }
642 QUrl file = QUrl::fromLocalFile(artifact->fullPath());
643 UMLApp::app()->slotOpenFileInEditor(file);
644 break;
645 }
646
647 case ListPopupMenu::mt_Rename:
648 edit(currentIndex());
649 break;
650
651 case ListPopupMenu::mt_Delete:
652 deleteItem(currItem);
653 break;
654
655 case ListPopupMenu::mt_Show:
656 // first check if we are on a diagram
657 if (!Model_Utils::typeIsDiagram(lvt)) {
658 UMLObject * object = currItem->umlObject();
659 if (!object) {
660 uError() << "UMLObjet of ... is null! Doing nothing.";
661 return;
662 }
663 QList<UMLWidget*> findResults;
664
665 if (Model_Utils::typeIsCanvasWidget(lvt)) {
666 UMLViewList views = m_doc->viewIterator();
667 foreach (UMLView *view, views) {
668 foreach(UMLWidget *widget, view->umlScene()->widgetList()) {
669 if (object == widget->umlObject()) {
670 findResults.append(widget);
671 }
672 }
673 }
674 }
675
676 if (findResults.size() == 0) {
677 break;
678 }
679
680 UMLWidget *selectedResult = 0;
681
682 if (findResults.size() > 1) {
683 QMenu menu(this);
684 int i = 0;
685 foreach(UMLWidget *w, findResults) {
686 QAction *action = menu.addAction(w->umlScene()->name() + QLatin1Char(':') + w->name());
687 action->setData(i++);
688 }
689 QAction *action = menu.exec(position);
690 if (action) {
691 selectedResult = findResults.at(action->data().toInt());
692 }
693 } else {
694 selectedResult = findResults.first();
695 }
696
697 if (!selectedResult) {
698 break;
699 }
700
701 UMLView *view = selectedResult->umlScene()->activeView();
702 selectedResult->umlScene()->setIsOpen(true);
703 view->setZoom(100);
704 if (UMLApp::app()->currentView() != view) {
705 UMLApp::app()->setCurrentView(view, false);
706 }
707 view->centerOn(selectedResult->scenePos());
708 selectedResult->setSelected(true);
709 }
710 break;
711
712 case ListPopupMenu::mt_Properties:
713 if (Model_Utils::typeIsProperties(lvt)) {
714 UMLApp::app()->slotPrefs(Model_Utils::convert_LVT_PT(lvt));
715 return;
716 }
717 else if (Model_Utils::typeIsDiagram(lvt)) {
718 UMLView * pView = m_doc->findView(currItem->ID());
719 if (pView) {
720 UMLApp::app()->docWindow()->updateDocumentation(false);
721 pView->showPropertiesDialog();
722 UMLApp::app()->docWindow()->showDocumentation(pView->umlScene(), true);
723 }
724 return;
725 }
726
727 { // ok, we are on another object, so find out on which one
728 UMLObject * object = currItem->umlObject();
729 if (!object) {
730 uError() << "UMLObject of ... is null! Doing nothing.";
731 return;
732 }
733 object->showPropertiesDialog();
734 }
735 break;
736
737 case ListPopupMenu::mt_Logical_Folder:
738 addNewItem(currItem, UMLListViewItem::lvt_Logical_Folder);
739 break;
740
741 case ListPopupMenu::mt_UseCase_Folder:
742 addNewItem(currItem, UMLListViewItem::lvt_UseCase_Folder);
743 break;
744
745 case ListPopupMenu::mt_Component_Folder:
746 addNewItem(currItem, UMLListViewItem::lvt_Component_Folder);
747 break;
748
749 case ListPopupMenu::mt_Deployment_Folder:
750 addNewItem(currItem, UMLListViewItem::lvt_Deployment_Folder);
751 break;
752
753 case ListPopupMenu::mt_EntityRelationship_Folder:
754 addNewItem(currItem, UMLListViewItem::lvt_EntityRelationship_Folder);
755 break;
756
757 case ListPopupMenu::mt_Cut:
758 m_bStartedCut = true;
759 m_bStartedCopy = false;
760 UMLApp::app()->slotEditCut();
761 break;
762
763 case ListPopupMenu::mt_Copy:
764 m_bStartedCut = false;
765 m_bStartedCopy = true;
766 UMLApp::app()->slotEditCopy();
767 break;
768
769 case ListPopupMenu::mt_Paste:
770 UMLApp::app()->slotEditPaste();
771 break;
772
773 case ListPopupMenu::mt_Clone:
774 UMLApp::app()->slotEditCopy();
775 UMLApp::app()->slotEditPaste();
776 break;
777
778 case ListPopupMenu::mt_ChangeToClass:
779 {
780 UMLClassifier* o = currItem->umlObject()->asUMLClassifier();
781 o->setStereotypeCmd(QString());
782 currItem->updateObject();
783 }
784 break;
785 case ListPopupMenu::mt_ChangeToPackage:
786 {
787 UMLClassifier* o = currItem->umlObject()->asUMLClassifier();
788 o->setStereotypeCmd(QString());
789 o->setBaseType(UMLObject::ot_Package);
790 currItem->updateObject();
791 }
792 break;
793
794 case ListPopupMenu::mt_Undefined:
795 // We got signalled for a menu action, but that menu action was not
796 // defined in ListPopupMenu. This is the case for "create diagram"
797 // actions which are defined and handled in UMLApp. This is fine,
798 // ignore them without warning.
799 break;
800
801 default:
802 uError() << "unknown type" << menuType;
803
804 break;
805
806 }//end switch
807 }
808
809 /**
810 * Find the parent folder for a diagram.
811 * If the currently selected item in the list view is a folder
812 * then that folder is returned as the parent.
813 *
814 * @param dt The Diagram_Type of the diagram.
815 * The type will only be used if there is no currently
816 * selected item, or if the current item is not a folder.
817 * In that case the root folder which is suitable for the
818 * Diagram_Type is returned.
819 * @return Pointer to the parent UMLListViewItem for the diagram.
820 */
findFolderForDiagram(Uml::DiagramType::Enum dt) const821 UMLListViewItem *UMLListView::findFolderForDiagram(Uml::DiagramType::Enum dt) const
822 {
823 UMLListViewItem *p = static_cast<UMLListViewItem*>(currentItem());
824 if (p && Model_Utils::typeIsFolder(p->type())
825 && !Model_Utils::typeIsRootView(p->type())) {
826 return p;
827 }
828 switch (dt) {
829 case Uml::DiagramType::UseCase:
830 p = m_lv[Uml::ModelType::UseCase];
831 break;
832 case Uml::DiagramType::Component:
833 p = m_lv[Uml::ModelType::Component];
834 break;
835 case Uml::DiagramType::Deployment:
836 p = m_lv[Uml::ModelType::Deployment];
837 break;
838 case Uml::DiagramType::EntityRelationship:
839 p = m_lv[Uml::ModelType::EntityRelationship];
840 break;
841 default:
842 p = m_lv[Uml::ModelType::Logical];
843 break;
844 }
845 return p;
846 }
847
848 /**
849 * Creates a new item to represent a new diagram.
850 * @param id the id of the new diagram
851 */
slotDiagramCreated(Uml::ID::Type id)852 void UMLListView::slotDiagramCreated(Uml::ID::Type id)
853 {
854 if (findItem(id)) {
855 uDebug() << "list view item " << Uml::ID::toString(id) << " already exists";
856 return;
857 }
858 UMLView *v = m_doc->findView(id);
859 if (v) {
860 UMLScene *scene = v->umlScene();
861 if (scene) {
862 const Uml::DiagramType::Enum dt = scene->type();
863 UMLListViewItem* p = findUMLObject(scene->folder());
864 UMLListViewItem* item = new UMLListViewItem(p, scene->name(), Model_Utils::convert_DT_LVT(dt), id);
865 item->setSelected(true);
866 UMLApp::app()->docWindow()->showDocumentation(scene, false);
867 }
868 } else {
869 uError() << "UmlDoc::findView(" << Uml::ID::toString(id) << ") returns NULL";
870 }
871 }
872
873 /**
874 * Determine the parent ListViewItem given a UMLObject.
875 *
876 * @param object Pointer to the UMLObject for which to look up the parent.
877 * @return Pointer to the parent UMLListViewItem chosen.
878 * Returns NULL on error (no parent could be determined.)
879 */
determineParentItem(UMLObject * object) const880 UMLListViewItem* UMLListView::determineParentItem(UMLObject* object) const
881 {
882 if (object == nullptr)
883 return nullptr;
884 UMLListViewItem* parentItem = 0;
885 UMLPackage* pkg = 0;
886 UMLListViewItem* current = (UMLListViewItem*) currentItem();
887 UMLListViewItem::ListViewType lvt = UMLListViewItem::lvt_Unknown;
888 if (current)
889 lvt = current->type();
890 UMLObject::ObjectType t = object->baseType();
891
892 switch (t) {
893 case UMLObject::ot_Attribute:
894 case UMLObject::ot_Operation:
895 case UMLObject::ot_Template:
896 case UMLObject::ot_EnumLiteral:
897 case UMLObject::ot_EntityAttribute:
898 case UMLObject::ot_InstanceAttribute:
899 case UMLObject::ot_UniqueConstraint:
900 case UMLObject::ot_ForeignKeyConstraint:
901 case UMLObject::ot_CheckConstraint:
902 //this will be handled by childObjectAdded
903 return 0;
904 break;
905 case UMLObject::ot_Association:
906 case UMLObject::ot_Role:
907 case UMLObject::ot_Stereotype:
908 return 0; // currently no representation in list view
909 break;
910 default:
911 pkg = object->umlPackage();
912 if (pkg) {
913 UMLListViewItem* pkgItem = findUMLObject(pkg);
914 if (pkgItem == 0)
915 uError() << "could not find parent package " << pkg->name();
916 else
917 parentItem = pkgItem;
918 } else if ((lvt == UMLListViewItem::lvt_UseCase_Folder &&
919 (t == UMLObject::ot_Actor || t == UMLObject::ot_UseCase))
920 || (lvt == UMLListViewItem::lvt_Component_Folder && t == UMLObject::ot_Component)
921 || (lvt == UMLListViewItem::lvt_Deployment_Folder && t == UMLObject::ot_Node)
922 || (lvt == UMLListViewItem::lvt_EntityRelationship_Folder && t == UMLObject::ot_Entity)) {
923 parentItem = current;
924 } else if (t == UMLObject::ot_Datatype) {
925 parentItem = m_datatypeFolder;
926 } else {
927 Uml::ModelType::Enum guess = Model_Utils::guessContainer(object);
928 if (guess != Uml::ModelType::N_MODELTYPES)
929 parentItem = m_lv[guess];
930 else
931 uWarning() << "UMLListView::determineParentItem: cannot guess container for object"
932 << object->name();
933 }
934 break;
935 }
936 return parentItem;
937 }
938
939 /**
940 * Return true if the given ObjectType permits child items.
941 * A "child item" is anything that qualifies as a UMLClassifierListItem,
942 * e.g. operations and attributes of classifiers.
943 */
mayHaveChildItems(UMLObject::ObjectType type)944 bool UMLListView::mayHaveChildItems(UMLObject::ObjectType type)
945 {
946 bool retval = false;
947 switch (type) {
948 case UMLObject::ot_Class:
949 case UMLObject::ot_Interface:
950 // case UMLObject::ot_Instance:
951 // Must be handled separately because UMLInstanceAttribute is not a
952 // UMLClassifierListItem.
953 case UMLObject::ot_Enum:
954 case UMLObject::ot_Entity: // CHECK: more?
955 retval = true;
956 break;
957 default:
958 break;
959 }
960 return retval;
961 }
962
963 /**
964 * Creates a new list view item and connects the appropriate signals/slots.
965 * @param object the newly created object
966 */
slotObjectCreated(UMLObject * object)967 void UMLListView::slotObjectCreated(UMLObject* object)
968 {
969 if (m_bCreatingChildObject) {
970 // @todo eliminate futile signal traffic
971 // e.g. we get here thru various indirections from
972 // ClassifierListPage::slot{Up, Down}Clicked()
973 return;
974 }
975
976 if (object->baseType() == UMLObject::ot_Association)
977 return;
978
979 UMLListViewItem* newItem = findUMLObject(object);
980
981 if (newItem) {
982 DEBUG(DBG_SRC) << object->name() << ", type=" << newItem->type()
983 << ", id=" << Uml::ID::toString(object->id())
984 << ": item already exists.";
985 Icon_Utils::IconType icon = Model_Utils::convert_LVT_IT(newItem->type());
986 newItem->setIcon(icon);
987 return;
988 }
989 UMLListViewItem* parentItem = 0;
990 UMLPackage *p = object->umlPackage();
991 if (p) {
992 parentItem = findUMLObject(p);
993 if (parentItem == 0)
994 parentItem = determineParentItem(object);
995 } else {
996 uWarning() << object->name() << " : umlPackage not set on object";
997 parentItem = determineParentItem(object);
998 }
999 if (parentItem == 0)
1000 return;
1001 UMLObject::ObjectType type = object->baseType();
1002 if (type == UMLObject::ot_Datatype) {
1003 UMLDatatype *dt = object->asUMLDatatype();
1004 if (!dt->isActive()) {
1005 DEBUG(DBG_SRC) << object->name() << " is not active. Refusing to create UMLListViewItem";
1006 return;
1007 }
1008 }
1009
1010 connectNewObjectsSlots(object);
1011 const UMLListViewItem::ListViewType lvt = Model_Utils::convert_OT_LVT(object);
1012 QString name = object->name();
1013 if (type == UMLObject::ot_Folder) {
1014 UMLFolder *f = object->asUMLFolder();
1015 QString folderFile = f->folderFile();
1016 if (!folderFile.isEmpty())
1017 name.append(QLatin1String(" (") + folderFile + QLatin1Char(')'));
1018 }
1019 newItem = new UMLListViewItem(parentItem, name, lvt, object);
1020 if (mayHaveChildItems(type)) {
1021 UMLClassifier *c = object->asUMLClassifier();
1022 UMLClassifierListItemList cListItems = c->getFilteredList(UMLObject::ot_UMLObject);
1023 foreach(UMLClassifierListItem *cli, cListItems)
1024 childObjectAdded(cli, c);
1025 }
1026 if (m_doc->loading())
1027 return;
1028 scrollToItem(newItem);
1029 newItem->setOpen(true);
1030 clearSelection();
1031 newItem->setSelected(true);
1032 UMLApp::app()->docWindow()->showDocumentation(object, false);
1033 }
1034
1035 /**
1036 * Connect some signals into slots in the list view for newly created UMLObjects.
1037 */
connectNewObjectsSlots(UMLObject * object)1038 void UMLListView::connectNewObjectsSlots(UMLObject* object)
1039 {
1040 UMLObject::ObjectType type = object->baseType();
1041 switch (type) {
1042 case UMLObject::ot_Class:
1043 case UMLObject::ot_Interface:
1044 {
1045 UMLClassifier *c = object->asUMLClassifier();
1046 connect(c, SIGNAL(attributeAdded(UMLClassifierListItem*)),
1047 this, SLOT(childObjectAdded(UMLClassifierListItem*)));
1048 connect(c, SIGNAL(attributeRemoved(UMLClassifierListItem*)),
1049 this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
1050 connect(c, SIGNAL(operationAdded(UMLClassifierListItem*)),
1051 this, SLOT(childObjectAdded(UMLClassifierListItem*)));
1052 connect(c, SIGNAL(operationRemoved(UMLClassifierListItem*)),
1053 this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
1054 connect(c, SIGNAL(templateAdded(UMLClassifierListItem*)),
1055 this, SLOT(childObjectAdded(UMLClassifierListItem*)));
1056 connect(c, SIGNAL(templateRemoved(UMLClassifierListItem*)),
1057 this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
1058 connect(object, SIGNAL(modified()), this, SLOT(slotObjectChanged()));
1059 }
1060 break;
1061 case UMLObject::ot_Instance:
1062 {
1063 connect(object, SIGNAL(modified()), this, SLOT(slotObjectChanged()));
1064 }
1065 break;
1066 case UMLObject::ot_Enum:
1067 {
1068 UMLEnum *e = object->asUMLEnum();
1069 connect(e, SIGNAL(enumLiteralAdded(UMLClassifierListItem*)),
1070 this, SLOT(childObjectAdded(UMLClassifierListItem*)));
1071 connect(e, SIGNAL(enumLiteralRemoved(UMLClassifierListItem*)),
1072 this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
1073 }
1074 connect(object, SIGNAL(modified()), this, SLOT(slotObjectChanged()));
1075 break;
1076 case UMLObject::ot_Entity:
1077 {
1078 UMLEntity *ent = object->asUMLEntity();
1079 connect(ent, SIGNAL(entityAttributeAdded(UMLClassifierListItem*)),
1080 this, SLOT(childObjectAdded(UMLClassifierListItem*)));
1081 connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)),
1082 this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
1083 connect(ent, SIGNAL(entityConstraintAdded(UMLClassifierListItem*)),
1084 this, SLOT(childObjectAdded(UMLClassifierListItem*)));
1085 connect(ent, SIGNAL(entityConstraintRemoved(UMLClassifierListItem*)),
1086 this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
1087 }
1088 connect(object, SIGNAL(modified()), this, SLOT(slotObjectChanged()));
1089 break;
1090 case UMLObject::ot_Datatype:
1091 case UMLObject::ot_Attribute:
1092 case UMLObject::ot_Operation:
1093 case UMLObject::ot_Template:
1094 case UMLObject::ot_EnumLiteral:
1095 case UMLObject::ot_EntityAttribute:
1096 case UMLObject::ot_InstanceAttribute:
1097 case UMLObject::ot_UniqueConstraint:
1098 case UMLObject::ot_ForeignKeyConstraint:
1099 case UMLObject::ot_CheckConstraint:
1100 case UMLObject::ot_Package:
1101 case UMLObject::ot_Actor:
1102 case UMLObject::ot_UseCase:
1103 case UMLObject::ot_Component:
1104 case UMLObject::ot_Port:
1105 case UMLObject::ot_Artifact:
1106 case UMLObject::ot_Node:
1107 case UMLObject::ot_Folder:
1108 case UMLObject::ot_Category:
1109 connect(object, SIGNAL(modified()), this, SLOT(slotObjectChanged()));
1110 break;
1111 case UMLObject::ot_UMLObject:
1112 case UMLObject::ot_Association:
1113 case UMLObject::ot_Stereotype:
1114 break;
1115 default:
1116 uWarning() << "unknown type in connectNewObjectsSlots";
1117 break;
1118 }
1119 }
1120
1121 /**
1122 * Calls updateObject() on the item representing the sending object
1123 * no parameters, uses sender() to work out which object called the slot.
1124 */
slotObjectChanged()1125 void UMLListView::slotObjectChanged()
1126 {
1127 if (m_doc->loading()) { //needed for class wizard
1128 return;
1129 }
1130 UMLObject* obj = const_cast<UMLObject*>(dynamic_cast<const UMLObject*>(sender()));
1131 UMLListViewItem* item = findUMLObject(obj);
1132 if (item) {
1133 item->updateObject();
1134 }
1135 }
1136
1137 /**
1138 * Adds a new operation, attribute or template item to a classifier.
1139 * @param obj the child object
1140 */
childObjectAdded(UMLClassifierListItem * obj)1141 void UMLListView::childObjectAdded(UMLClassifierListItem* obj)
1142 {
1143 UMLClassifier *parent = const_cast<UMLClassifier*>(dynamic_cast<const UMLClassifier*>(sender()));
1144 childObjectAdded(obj, parent);
1145 }
1146
1147 /**
1148 * Adds a new operation, attribute or template item to a classifier, identical to
1149 * childObjectAdded(obj) but with an explicit parent.
1150 * @param child the child object
1151 * @param parent the parent object
1152 */
childObjectAdded(UMLClassifierListItem * child,UMLClassifier * parent)1153 void UMLListView::childObjectAdded(UMLClassifierListItem* child, UMLClassifier* parent)
1154 {
1155 if (m_bCreatingChildObject)
1156 return;
1157 const QString text = child->toString(Uml::SignatureType::SigNoVis);
1158 UMLListViewItem *childItem = 0;
1159 UMLListViewItem *parentItem = findUMLObject(parent);
1160 if (parentItem == 0) {
1161 DEBUG(DBG_SRC) << child->name() << ": parent " << parent->name()
1162 << " does not yet exist, creating it now.";
1163 const UMLListViewItem::ListViewType lvt = Model_Utils::convert_OT_LVT(parent);
1164 parentItem = new UMLListViewItem(m_lv[Uml::ModelType::Logical], parent->name(), lvt, parent);
1165 } else {
1166 childItem = parentItem->findChildObject(child);
1167 }
1168 if (childItem) {
1169 childItem->setText(text);
1170 } else {
1171 const UMLListViewItem::ListViewType lvt = Model_Utils::convert_OT_LVT(child);
1172 childItem = new UMLListViewItem(parentItem, text, lvt, child);
1173 if (! m_doc->loading()) {
1174 scrollToItem(childItem);
1175 clearSelection();
1176 childItem->setSelected(true);
1177 }
1178 connectNewObjectsSlots(child);
1179 }
1180 }
1181
1182 /**
1183 * Deletes the list view item.
1184 * @param obj the object to remove
1185 */
childObjectRemoved(UMLClassifierListItem * obj)1186 void UMLListView::childObjectRemoved(UMLClassifierListItem* obj)
1187 {
1188 UMLClassifier *parent = const_cast<UMLClassifier*>(dynamic_cast<const UMLClassifier*>(sender()));
1189 UMLListViewItem *parentItem = findUMLObject(parent);
1190 if (parentItem == 0) {
1191 uError() << obj->name() << ": cannot find parent UMLListViewItem";
1192 return;
1193 }
1194 parentItem->deleteChildItem(obj);
1195 }
1196
1197 /**
1198 * Renames a diagram in the list view
1199 * @param id the id of the renamed diagram
1200 */
slotDiagramRenamed(Uml::ID::Type id)1201 void UMLListView::slotDiagramRenamed(Uml::ID::Type id)
1202 {
1203 UMLListViewItem* item;
1204 UMLView* v = m_doc->findView(id);
1205 if ((item = findView(v)) == 0) {
1206 uError() << "UMLDoc::findView(" << Uml::ID::toString(id) << ") returns 0";
1207 return;
1208 }
1209 item->setText(v->umlScene()->name());
1210 }
1211
1212 /**
1213 * Sets the document this is associated with. This is important as
1214 * this is required as to set up the callbacks.
1215 *
1216 * @param doc The document to associate with this class.
1217 */
setDocument(UMLDoc * doc)1218 void UMLListView::setDocument(UMLDoc *doc)
1219 {
1220 if (m_doc && m_doc != doc) {
1221 //disconnect signals from old doc and reset view
1222 }
1223 m_doc = doc;
1224
1225 connect(m_doc, SIGNAL(sigDiagramCreated(Uml::ID::Type)), this, SLOT(slotDiagramCreated(Uml::ID::Type)));
1226 connect(m_doc, SIGNAL(sigDiagramRemoved(Uml::ID::Type)), this, SLOT(slotDiagramRemoved(Uml::ID::Type)));
1227 connect(m_doc, SIGNAL(sigDiagramRenamed(Uml::ID::Type)), this, SLOT(slotDiagramRenamed(Uml::ID::Type)));
1228 connect(m_doc, SIGNAL(sigObjectCreated(UMLObject*)), this, SLOT(slotObjectCreated(UMLObject*)));
1229 connect(m_doc, SIGNAL(sigObjectRemoved(UMLObject*)), this, SLOT(slotObjectRemoved(UMLObject*)));
1230 }
1231
1232 /**
1233 * Disconnects signals and removes the list view item.
1234 * @param object the object about to be removed
1235 */
slotObjectRemoved(UMLObject * object)1236 void UMLListView::slotObjectRemoved(UMLObject* object)
1237 {
1238 if (m_doc->loading() && !m_doc->importing()) { //needed for class wizard but not when importing
1239 return;
1240 }
1241 disconnect(object, SIGNAL(modified()), this, SLOT(slotObjectChanged()));
1242 UMLListViewItem* item = findItem(object->id());
1243 delete item;
1244 UMLApp::app()->docWindow()->updateDocumentation(true);
1245 }
1246
1247 /**
1248 * Removes the item representing a diagram.
1249 * @param id the id of the diagram
1250 */
slotDiagramRemoved(Uml::ID::Type id)1251 void UMLListView::slotDiagramRemoved(Uml::ID::Type id)
1252 {
1253 UMLListViewItem* item = findItem(id);
1254 delete item;
1255 UMLApp::app()->docWindow()->updateDocumentation(true);
1256 }
1257
1258 /**
1259 *
1260 */
getDragData()1261 UMLDragData* UMLListView::getDragData()
1262 {
1263 UMLListViewItemList itemsSelected = selectedItems();
1264
1265 UMLListViewItemList list;
1266 foreach(UMLListViewItem* item, itemsSelected) {
1267 UMLListViewItem::ListViewType type = item->type();
1268 if (!Model_Utils::typeIsCanvasWidget(type) && !Model_Utils::typeIsDiagram(type)
1269 && !Model_Utils::typeIsClassifierList(type)) {
1270 return 0;
1271 }
1272 list.append(item);
1273 }
1274
1275 UMLDragData *t = new UMLDragData(list, this);
1276
1277 return t;
1278 }
1279
1280 /**
1281 * This method looks for an object in a folder an its subfolders recursively.
1282 * @param folder The folder entry of the list view.
1283 * @param obj The object to be found in the folder.
1284 * @return The object if found else a NULL pointer.
1285 */
findUMLObjectInFolder(UMLListViewItem * folder,UMLObject * obj)1286 UMLListViewItem * UMLListView::findUMLObjectInFolder(UMLListViewItem* folder, UMLObject* obj)
1287 {
1288 for (int i=0; i < folder->childCount(); ++i) {
1289 UMLListViewItem *item = folder->childItem(i);
1290 switch (item->type()) {
1291 case UMLListViewItem::lvt_Actor :
1292 case UMLListViewItem::lvt_UseCase :
1293 case UMLListViewItem::lvt_Class :
1294 case UMLListViewItem::lvt_Package :
1295 case UMLListViewItem::lvt_Subsystem :
1296 case UMLListViewItem::lvt_Component :
1297 case UMLListViewItem::lvt_Port :
1298 case UMLListViewItem::lvt_Node :
1299 case UMLListViewItem::lvt_Artifact :
1300 case UMLListViewItem::lvt_Interface :
1301 case UMLListViewItem::lvt_Datatype :
1302 case UMLListViewItem::lvt_Enum :
1303 case UMLListViewItem::lvt_Entity :
1304 case UMLListViewItem::lvt_Category:
1305 if (item->umlObject() == obj)
1306 return item;
1307 break;
1308 case UMLListViewItem::lvt_Logical_Folder :
1309 case UMLListViewItem::lvt_UseCase_Folder :
1310 case UMLListViewItem::lvt_Component_Folder :
1311 case UMLListViewItem::lvt_Deployment_Folder :
1312 case UMLListViewItem::lvt_EntityRelationship_Folder :
1313 case UMLListViewItem::lvt_Datatype_Folder : {
1314 UMLListViewItem *temp = findUMLObjectInFolder(item, obj);
1315 if (temp)
1316 return temp;
1317 }
1318 default:
1319 break;
1320 }
1321 }
1322 return 0;
1323 }
1324
1325 /**
1326 * Find a UMLObject in the listview.
1327 *
1328 * @param p Pointer to the object to find in the list view.
1329 * @return Pointer to the UMLObject found or NULL if not found.
1330 */
findUMLObject(const UMLObject * p) const1331 UMLListViewItem * UMLListView::findUMLObject(const UMLObject *p) const
1332 {
1333 UMLListViewItem *item = m_rv;
1334 UMLListViewItem *testItem = item->findUMLObject(p);
1335 if (testItem)
1336 return testItem;
1337 return 0;
1338 }
1339
1340 /**
1341 * Changes the icon for the given UMLObject to the given icon.
1342 */
changeIconOf(UMLObject * o,Icon_Utils::IconType to)1343 void UMLListView::changeIconOf(UMLObject *o, Icon_Utils::IconType to)
1344 {
1345 UMLListViewItem *item = findUMLObject(o);
1346 if (item)
1347 item->setIcon(to);
1348 }
1349
1350 /**
1351 * Searches through the tree for the item which represents the diagram given.
1352 * @param v the diagram to search for
1353 * @return the item which represents the diagram
1354 */
findView(UMLView * v)1355 UMLListViewItem* UMLListView::findView(UMLView* v)
1356 {
1357 if (!v) {
1358 uWarning() << "returning 0 - param is 0.";
1359 return 0;
1360 }
1361 UMLListViewItem* item;
1362 Uml::DiagramType::Enum dType = v->umlScene()->type();
1363 UMLListViewItem::ListViewType type = Model_Utils::convert_DT_LVT(dType);
1364 Uml::ID::Type id = v->umlScene()->ID();
1365 if (dType == Uml::DiagramType::UseCase) {
1366 item = m_lv[Uml::ModelType::UseCase];
1367 } else if (dType == Uml::DiagramType::Component) {
1368 item = m_lv[Uml::ModelType::Component];
1369 } else if (dType == Uml::DiagramType::Deployment) {
1370 item = m_lv[Uml::ModelType::Deployment];
1371 } else if (dType == Uml::DiagramType::EntityRelationship) {
1372 item = m_lv[Uml::ModelType::EntityRelationship];
1373 } else {
1374 item = m_lv[Uml::ModelType::Logical];
1375 }
1376 for (int i=0; i < item->childCount(); i++) {
1377 UMLListViewItem* foundItem = recursiveSearchForView(item->childItem(i), type, id);
1378 if (foundItem) {
1379 return foundItem;
1380 }
1381 }
1382 if (m_doc->loading()) {
1383 DEBUG(DBG_SRC) << "could not find " << v->umlScene()->name() << " in " << *item;
1384 } else {
1385 uWarning() << "could not find " << v->umlScene()->name() << " in " << *item;
1386 }
1387 return 0;
1388 }
1389
1390 /**
1391 * Searches the tree for a diagram (view).
1392 * Warning: these method may return in some cases the wrong diagram
1393 * Used by findView().
1394 */
recursiveSearchForView(UMLListViewItem * listViewItem,UMLListViewItem::ListViewType type,Uml::ID::Type id)1395 UMLListViewItem* UMLListView::recursiveSearchForView(UMLListViewItem* listViewItem,
1396 UMLListViewItem::ListViewType type, Uml::ID::Type id)
1397 {
1398 if (!listViewItem)
1399 return 0;
1400
1401 if (Model_Utils::typeIsFolder(listViewItem->type())) {
1402 for (int i=0; i < listViewItem->childCount(); i++) {
1403 UMLListViewItem* child = listViewItem->childItem(i);
1404 UMLListViewItem* resultListViewItem = recursiveSearchForView(child, type, id);
1405 if (resultListViewItem)
1406 return resultListViewItem;
1407 }
1408 } else {
1409 if (listViewItem->type() == type && listViewItem->ID() == id)
1410 return listViewItem;
1411 }
1412 return 0;
1413 }
1414
1415 /**
1416 * Searches through the tree for the item with the given ID.
1417 *
1418 * @param id The ID to search for.
1419 * @return The item with the given ID or 0 if not found.
1420 */
findItem(Uml::ID::Type id)1421 UMLListViewItem* UMLListView::findItem(Uml::ID::Type id)
1422 {
1423 UMLListViewItem *topLevel = m_rv;
1424 UMLListViewItem *item = topLevel->findItem(id);
1425 if (item)
1426 return item;
1427 return 0;
1428 }
1429
1430 /**
1431 * Carries out initalisation of attributes in class.
1432 * This method is called more than once during an instance's lifetime (by UMLDoc)!
1433 * So we must not allocate any memory before freeing the previously allocated one
1434 * or do connect()s.
1435 */
init()1436 void UMLListView::init()
1437 {
1438 if (m_rv == 0) {
1439 m_rv = new UMLListViewItem(this, i18n("Views"), UMLListViewItem::lvt_View);
1440 m_rv->setID("Views");
1441 //m_rv->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
1442
1443 for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) {
1444 Uml::ModelType::Enum mt = Uml::ModelType::fromInt(i);
1445 UMLFolder *sysFolder = m_doc->rootFolder(mt);
1446 UMLListViewItem::ListViewType lvt = Model_Utils::convert_MT_LVT(mt);
1447 m_lv[i] = new UMLListViewItem(m_rv, sysFolder->localName(), lvt, sysFolder);
1448 }
1449 } else {
1450 clean();
1451 }
1452 UMLFolder *datatypeFolder = m_doc->datatypeFolder();
1453 if (!m_datatypeFolder) {
1454 m_datatypeFolder = new UMLListViewItem(m_lv[Uml::ModelType::Logical], datatypeFolder->localName(),
1455 UMLListViewItem::lvt_Datatype_Folder, datatypeFolder);
1456 }
1457 if (m_settingsFolder == 0) {
1458 m_settingsFolder = new UMLListViewItem(this, i18n("Settings"), UMLListViewItem::lvt_Properties);
1459 Icon_Utils::IconType icon = Model_Utils::convert_LVT_IT(m_settingsFolder->type());
1460 m_settingsFolder->setIcon(icon);
1461 m_settingsFolder->setID("Settings");
1462 new UMLListViewItem(m_settingsFolder, i18n("Auto Layout"), UMLListViewItem::lvt_Properties_AutoLayout);
1463 new UMLListViewItem(m_settingsFolder, i18n("Class"), UMLListViewItem::lvt_Properties_Class);
1464 new UMLListViewItem(m_settingsFolder, i18n("Code Importer"), UMLListViewItem::lvt_Properties_CodeImport);
1465 new UMLListViewItem(m_settingsFolder, i18n("Code Generation"), UMLListViewItem::lvt_Properties_CodeGeneration);
1466 new UMLListViewItem(m_settingsFolder, i18n("Code Viewer"), UMLListViewItem::lvt_Properties_CodeViewer);
1467 new UMLListViewItem(m_settingsFolder, i18n("Font"), UMLListViewItem::lvt_Properties_Font);
1468 new UMLListViewItem(m_settingsFolder, i18n("General"), UMLListViewItem::lvt_Properties_General);
1469 new UMLListViewItem(m_settingsFolder, i18n("User Interface"), UMLListViewItem::lvt_Properties_UserInterface);
1470 }
1471
1472 m_rv->setOpen(true);
1473 for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) {
1474 m_lv[i]->setOpen(true);
1475 }
1476 m_datatypeFolder->setOpen(false);
1477
1478 //setup misc.
1479 m_bStartedCut = m_bStartedCopy = false;
1480 m_bCreatingChildObject = false;
1481 headerItem()->setHidden(true);
1482 }
1483
1484 /**
1485 * Remove all items and subfolders of the main folders.
1486 * Special case: The datatype folder, child of the logical view, is not deleted.
1487 */
clean()1488 void UMLListView::clean()
1489 {
1490 for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) {
1491 deleteChildrenOf(m_lv[i]);
1492 }
1493 //deleteChildrenOf(m_datatypeFolder);
1494 }
1495
1496 /**
1497 * Set the current view to the given view.
1498 *
1499 * @param view The current view.
1500 */
setView(UMLView * view)1501 void UMLListView::setView(UMLView * view)
1502 {
1503 if (!view)
1504 return;
1505 UMLListViewItem * temp = findView(view);
1506 if (temp)
1507 temp->setSelected(true);
1508 }
1509
1510 /**
1511 * Event handler for mouse double click.
1512 */
mouseDoubleClickEvent(QMouseEvent * me)1513 void UMLListView::mouseDoubleClickEvent(QMouseEvent * me)
1514 {
1515 UMLListViewItem * item = static_cast<UMLListViewItem *>(currentItem());
1516 if (!item || me->button() != Qt::LeftButton)
1517 return;
1518
1519 UMLListViewItem::ListViewType lvType = item->type();
1520 if (Model_Utils::typeIsProperties(lvType)) {
1521 UMLApp::app()->docWindow()->updateDocumentation(false);
1522 UMLApp::app()->slotPrefs(Model_Utils::convert_LVT_PT(lvType));
1523 return;
1524 }
1525 else if (Model_Utils::typeIsDiagram(lvType)) {
1526 UMLView * pView = m_doc->findView(item->ID());
1527 if (pView) {
1528 UMLApp::app()->docWindow()->updateDocumentation(false);
1529 pView->showPropertiesDialog();
1530 UMLApp::app()->docWindow()->showDocumentation(pView->umlScene(), true);
1531 }
1532 return;
1533 }
1534 //else see if an object
1535 UMLObject * object = item->umlObject();
1536 //continue only if we are on a UMLObject
1537 if (!object) {
1538 return;
1539 }
1540
1541 object->showPropertiesDialog(this);
1542 }
1543
1544 /**
1545 * Event handler for accepting drag request.
1546 * @param event the drop event
1547 * @return success state
1548 */
acceptDrag(QDropEvent * event) const1549 bool UMLListView::acceptDrag(QDropEvent* event) const
1550 {
1551 UMLListViewItem* target = (UMLListViewItem*)itemAt(event->pos());
1552 if (!target) {
1553 DEBUG(DBG_SRC) << "itemAt(mouse position) returns 0";
1554 return false;
1555 }
1556
1557 bool accept = false;
1558 UMLListViewItem::ListViewType srcType = UMLListViewItem::lvt_Unknown;
1559 UMLListViewItem::ListViewType dstType = UMLListViewItem::lvt_Unknown;
1560
1561 // Handle different drop actions
1562 switch (event->proposedAction()) {
1563 case Qt::CopyAction: {
1564 // Instead of relying on the current item being the drag source,
1565 // we should use the mime data to obtain the dragged type (or types
1566 // if we implement multiple item selections in tree view)
1567 srcType = static_cast<UMLListViewItem*>(currentItem())->type();
1568 dstType = target->type();
1569
1570 // Copy of diagrams is not supported
1571 if (Model_Utils::typeIsDiagram(srcType)) {
1572 accept = false;
1573 } else {
1574 accept = Model_Utils::typeIsAllowedInType(srcType, dstType);
1575 }
1576 break;
1577 }
1578 case Qt::MoveAction: {
1579 UMLDragData::LvTypeAndID_List list;
1580 if (!UMLDragData::getClip3TypeAndID(event->mimeData(), list)) {
1581 uError() << "UMLDragData::getClip3TypeAndID returns false";
1582 return false;
1583 }
1584
1585 UMLDragData::LvTypeAndID_It it(list);
1586 UMLDragData::LvTypeAndID * data = 0;
1587 dstType = target->type();
1588 while (it.hasNext()) {
1589 data = it.next();
1590 srcType = data->type;
1591 accept = Model_Utils::typeIsAllowedInType(srcType, dstType);
1592
1593 // disallow drop if any child element is not allowed
1594 if (!accept)
1595 break;
1596 }
1597 break;
1598 }
1599 default: {
1600 uError() << "Unsupported drop-action in acceptDrag()";
1601 return false;
1602 }
1603 }
1604
1605 if (!accept) {
1606 uDebug() << "Disallowing drop because source type" << UMLListViewItem::toString(srcType)
1607 << "is not allowed in target type" << UMLListViewItem::toString(dstType);
1608 }
1609
1610 return accept;
1611 }
1612
1613 /**
1614 * Auxiliary method for moveObject(): Adds the model object at the proper
1615 * new container (package if nested, UMLDoc if at global level), and
1616 * updates the containment relationships in the model.
1617 */
addAtContainer(UMLListViewItem * item,UMLListViewItem * parent)1618 void UMLListView::addAtContainer(UMLListViewItem *item, UMLListViewItem *parent)
1619 {
1620 UMLCanvasObject *o = item->umlObject()->asUMLCanvasObject();
1621 if (o == 0) {
1622 DEBUG(DBG_SRC) << item->text(0) << ": item's UMLObject is 0";
1623 } else if (Model_Utils::typeIsContainer(parent->type())) {
1624 /**** TBC: Do this here?
1625 If yes then remove that logic at the callers
1626 and rename this method to moveAtContainer()
1627 UMLPackage *oldPkg = o->getUMLPackage();
1628 if (oldPkg)
1629 oldPkg->removeObject(o);
1630 *********/
1631 UMLPackage *pkg = parent->umlObject()->asUMLPackage();
1632 o->setUMLPackage(pkg);
1633 pkg->addObject(o);
1634 } else {
1635 uError() << item->text(0) << ": parent type is " << parent->type();
1636 }
1637 UMLView *currentView = UMLApp::app()->currentView();
1638 if (currentView)
1639 currentView->umlScene()->updateContainment(o);
1640 }
1641
1642 /**
1643 * Moves an object given its unique ID and listview type to an
1644 * other listview parent item.
1645 * Also takes care of the corresponding move in the model.
1646 */
moveObject(Uml::ID::Type srcId,UMLListViewItem::ListViewType srcType,UMLListViewItem * newParent)1647 UMLListViewItem * UMLListView::moveObject(Uml::ID::Type srcId, UMLListViewItem::ListViewType srcType,
1648 UMLListViewItem *newParent)
1649 {
1650 if (newParent == 0)
1651 return 0;
1652 UMLListViewItem * move = findItem(srcId);
1653 if (move == 0)
1654 return 0;
1655
1656 UMLObject *newParentObj = 0;
1657 // Remove the source object at the old parent package.
1658 UMLObject *srcObj = m_doc->findObjectById(srcId);
1659 if (srcObj) {
1660 newParentObj = newParent->umlObject();
1661 if (srcObj == newParentObj) {
1662 uError() << srcObj->name() << ": Cannot move onto self";
1663 return 0;
1664 }
1665 UMLPackage *srcPkg = srcObj->umlPackage();
1666 if (srcPkg) {
1667 if (srcPkg == newParentObj) {
1668 uError() << srcObj->name() << ": Object is already in target package";
1669 return 0;
1670 }
1671 srcPkg->removeObject(srcObj);
1672 }
1673 }
1674 else if (Model_Utils::typeIsDiagram(srcType)) {
1675 UMLView *v = m_doc->findView(srcId);
1676 UMLFolder *newParentObj = newParent->umlObject()->asUMLFolder();
1677 if (v) {
1678 UMLFolder *srcPkg = v->umlScene()->folder();
1679 if (srcPkg) {
1680 if (srcPkg == newParentObj) {
1681 uError() << v->umlScene()->name() << ": Object is already in target package";
1682 return 0;
1683 }
1684 srcPkg->removeView(v);
1685 newParentObj->addView(v);
1686 v->umlScene()->setFolder(newParentObj);
1687 UMLApp::app()->document()->diagramsModel()->emitDataChanged(v);
1688 }
1689 }
1690 }
1691
1692 UMLListViewItem::ListViewType newParentType = newParent->type();
1693 DEBUG(DBG_SRC) << "newParentType is " << UMLListViewItem::toString(newParentType);
1694 UMLListViewItem *newItem = 0;
1695
1696 //make sure trying to place in correct location
1697 switch (srcType) {
1698 case UMLListViewItem::lvt_UseCase_Folder:
1699 case UMLListViewItem::lvt_Actor:
1700 case UMLListViewItem::lvt_UseCase:
1701 case UMLListViewItem::lvt_UseCase_Diagram:
1702 if (newParentType == UMLListViewItem::lvt_UseCase_Folder ||
1703 newParentType == UMLListViewItem::lvt_UseCase_View) {
1704 newItem = move->deepCopy(newParent);
1705 if (m_doc->loading()) // deletion is not safe while loading
1706 move->setVisible(false); // (the <listview> XMI may be corrupted)
1707 else
1708 delete move;
1709 addAtContainer(newItem, newParent);
1710 }
1711 break;
1712 case UMLListViewItem::lvt_Component_Folder:
1713 case UMLListViewItem::lvt_Artifact:
1714 case UMLListViewItem::lvt_Component_Diagram:
1715 if (newParentType == UMLListViewItem::lvt_Component_Folder ||
1716 newParentType == UMLListViewItem::lvt_Component_View) {
1717 newItem = move->deepCopy(newParent);
1718 if (m_doc->loading()) // deletion is not safe while loading
1719 move->setVisible(false); // (the <listview> XMI may be corrupted)
1720 else
1721 delete move;
1722 addAtContainer(newItem, newParent);
1723 }
1724 break;
1725 case UMLListViewItem::lvt_Subsystem:
1726 if (newParentType == UMLListViewItem::lvt_Component_Folder ||
1727 newParentType == UMLListViewItem::lvt_Component_View ||
1728 newParentType == UMLListViewItem::lvt_Subsystem) {
1729 newItem = move->deepCopy(newParent);
1730 if (m_doc->loading()) // deletion is not safe while loading
1731 move->setVisible(false); // (the <listview> XMI may be corrupted)
1732 else
1733 delete move;
1734 addAtContainer(newItem, newParent);
1735 }
1736 break;
1737 case UMLListViewItem::lvt_Component:
1738 if (newParentType == UMLListViewItem::lvt_Component_Folder ||
1739 newParentType == UMLListViewItem::lvt_Component_View ||
1740 newParentType == UMLListViewItem::lvt_Component ||
1741 newParentType == UMLListViewItem::lvt_Subsystem) {
1742 newItem = move->deepCopy(newParent);
1743 if (m_doc->loading()) // deletion is not safe while loading
1744 move->setVisible(false); // (the <listview> XMI may be corrupted)
1745 else
1746 delete move;
1747 addAtContainer(newItem, newParent);
1748 }
1749 break;
1750 case UMLListViewItem::lvt_Port:
1751 if (newParentType == UMLListViewItem::lvt_Component) {
1752 newItem = move->deepCopy(newParent);
1753 if (m_doc->loading()) // deletion is not safe while loading
1754 move->setVisible(false); // (the <listview> XMI may be corrupted)
1755 else
1756 delete move;
1757 addAtContainer(newItem, newParent);
1758 }
1759 break;
1760 case UMLListViewItem::lvt_Deployment_Folder:
1761 case UMLListViewItem::lvt_Node:
1762 case UMLListViewItem::lvt_Deployment_Diagram:
1763 if (newParentType == UMLListViewItem::lvt_Deployment_Folder ||
1764 newParentType == UMLListViewItem::lvt_Deployment_View) {
1765 newItem = move->deepCopy(newParent);
1766 if (m_doc->loading()) // deletion is not safe while loading
1767 move->setVisible(false); // (the <listview> XMI may be corrupted)
1768 else
1769 delete move;
1770 addAtContainer(newItem, newParent);
1771 }
1772 break;
1773 case UMLListViewItem::lvt_EntityRelationship_Folder:
1774 case UMLListViewItem::lvt_Entity:
1775 case UMLListViewItem::lvt_Category:
1776 case UMLListViewItem::lvt_EntityRelationship_Diagram:
1777 if (newParentType == UMLListViewItem::lvt_EntityRelationship_Folder ||
1778 newParentType == UMLListViewItem::lvt_EntityRelationship_Model) {
1779 newItem = move->deepCopy(newParent);
1780 if (m_doc->loading()) // deletion is not safe while loading
1781 move->setVisible(false); // (the <listview> XMI may be corrupted)
1782 else
1783 delete move;
1784 addAtContainer(newItem, newParent);
1785 }
1786 break;
1787 case UMLListViewItem::lvt_Collaboration_Diagram:
1788 case UMLListViewItem::lvt_Class_Diagram:
1789 case UMLListViewItem::lvt_State_Diagram:
1790 case UMLListViewItem::lvt_Activity_Diagram:
1791 case UMLListViewItem::lvt_Sequence_Diagram:
1792 case UMLListViewItem::lvt_Logical_Folder:
1793 case UMLListViewItem::lvt_Object_Diagram:
1794 if (newParentType == UMLListViewItem::lvt_Package ||
1795 newParentType == UMLListViewItem::lvt_Logical_Folder ||
1796 newParentType == UMLListViewItem::lvt_Logical_View) {
1797 newItem = move->deepCopy(newParent);
1798 if (m_doc->loading()) // deletion is not safe while loading
1799 move->setVisible(false); // (the <listview> XMI may be corrupted)
1800 else
1801 delete move;
1802 addAtContainer(newItem, newParent);
1803 }
1804 break;
1805 case UMLListViewItem::lvt_Class:
1806 case UMLListViewItem::lvt_Package:
1807 case UMLListViewItem::lvt_Interface:
1808 case UMLListViewItem::lvt_Enum:
1809 case UMLListViewItem::lvt_Datatype:
1810 case UMLListViewItem::lvt_Instance:
1811 if (newParentType == UMLListViewItem::lvt_Logical_Folder ||
1812 newParentType == UMLListViewItem::lvt_Datatype_Folder ||
1813 newParentType == UMLListViewItem::lvt_Logical_View ||
1814 newParentType == UMLListViewItem::lvt_Class ||
1815 newParentType == UMLListViewItem::lvt_Interface ||
1816 newParentType == UMLListViewItem::lvt_Package) {
1817 newItem = move->deepCopy(newParent);
1818 if (m_doc->loading()) // deletion is not safe while loading
1819 move->setVisible(false); // (the <listview> XMI may be corrupted)
1820 else
1821 delete move;
1822 UMLCanvasObject *o = newItem->umlObject()->asUMLCanvasObject();
1823 if (o == 0) {
1824 DEBUG(DBG_SRC) << "moveObject: newItem's UMLObject is 0";
1825 } else if (newParentObj == 0) {
1826 uError() << o->name() << ": newParentObj is 0";
1827 } else {
1828 UMLPackage *pkg = newParentObj->asUMLPackage();
1829 o->setUMLPackage(pkg);
1830 pkg->addObject(o);
1831 }
1832 UMLView *currentView = UMLApp::app()->currentView();
1833 if (currentView)
1834 currentView->umlScene()->updateContainment(o);
1835 }
1836 break;
1837 case UMLListViewItem::lvt_Attribute:
1838 case UMLListViewItem::lvt_Operation:
1839 if (newParentType == UMLListViewItem::lvt_Class ||
1840 newParentType == UMLListViewItem::lvt_Interface) {
1841 // update list view
1842
1843 newItem = move->deepCopy(newParent);
1844 // we don't delete move right away, it will be deleted in slots,
1845 // called by subsequent steps
1846 //delete move;
1847
1848 // update model objects
1849 m_bCreatingChildObject = true;
1850
1851 if (!srcObj) {
1852 uError() << "srcObj is NULL";
1853 break;
1854 }
1855
1856 UMLClassifier *oldParentClassifier = srcObj->umlParent()->asUMLClassifier();
1857 UMLClassifier *newParentClassifier = newParentObj->asUMLClassifier();
1858 if (srcType == UMLListViewItem::lvt_Attribute) {
1859 UMLAttribute *att = srcObj->asUMLAttribute();
1860 // We can't use the existing 'att' directly
1861 // because its parent is fixed to the old classifier
1862 // and we have no way of changing that:
1863 // QObject does not permit changing the parent().
1864 if (att == 0) {
1865 uError() << "moveObject internal error: srcObj "
1866 << srcObj->name() << " is not a UMLAttribute";
1867 } else if (oldParentClassifier->takeItem(att) == -1) {
1868 uError() << "moveObject: oldParentClassifier->takeItem(att "
1869 << att->name() << ") returns 0";
1870 } else {
1871 const QString& nm = att->name();
1872 UMLAttribute *newAtt = newParentClassifier->createAttribute(nm,
1873 att->getType(),
1874 att->visibility(),
1875 att->getInitialValue());
1876 newItem->setUMLObject(newAtt);
1877 newParent->addChildItem(newAtt, newItem);
1878
1879 connectNewObjectsSlots(newAtt);
1880 // Let's not forget to update the DocWindow::m_pObject
1881 // because the old one is about to be physically deleted !
1882 UMLApp::app()->docWindow()->showDocumentation(newAtt, true);
1883 delete att;
1884 }
1885 } else {
1886 UMLOperation *op = srcObj->asUMLOperation();
1887 // We can't use the existing 'op' directly
1888 // because its parent is fixed to the old classifier
1889 // and we have no way of changing that:
1890 // QObject does not permit changing the parent().
1891 if (op && oldParentClassifier->takeItem(op) != -1) {
1892 bool isExistingOp;
1893 Model_Utils::NameAndType_List ntDummyList;
1894 // We need to provide a dummy NameAndType_List
1895 // else UMLClassifier::createOperation will
1896 // bring up an operation dialog.
1897 UMLOperation *newOp = newParentClassifier->createOperation(
1898 op->name(), &isExistingOp, &ntDummyList);
1899 newOp->setType(op->getType());
1900 newOp->setVisibility(op->visibility());
1901 UMLAttributeList parmList = op->getParmList();
1902 foreach(UMLAttribute* parm, parmList) {
1903 UMLAttribute *newParm = new UMLAttribute(newParentClassifier,
1904 parm->name(),
1905 Uml::ID::None,
1906 parm->visibility(),
1907 parm->getType(),
1908 parm->getInitialValue());
1909 newParm->setParmKind(parm->getParmKind());
1910 newOp->addParm(newParm);
1911 }
1912 newItem->setUMLObject(newOp);
1913 newParent->addChildItem(newOp, newItem);
1914
1915 connectNewObjectsSlots(newOp);
1916
1917 // Let's not forget to update the DocWindow::m_pObject
1918 // because the old one is about to be physically deleted !
1919 UMLApp::app()->docWindow()->showDocumentation(newOp, true);
1920 delete op;
1921 } else {
1922 uError() << "moveObject: oldParentClassifier->takeItem(op) returns 0";
1923 }
1924 }
1925 m_bCreatingChildObject = false;
1926 }
1927 break;
1928 default:
1929 break;
1930 }
1931 return newItem;
1932 }
1933
1934 /**
1935 * Something has been dragged and dropped onto the list view.
1936 */
slotDropped(QDropEvent * de,UMLListViewItem * target)1937 void UMLListView::slotDropped(QDropEvent* de, UMLListViewItem* target)
1938 {
1939 DEBUG(DBG_SRC) << "Dropping on target " << target->text(0);
1940
1941 // Copy or move tree items
1942 if (de->dropAction() == Qt::CopyAction) {
1943 UMLClipboard clipboard;
1944
1945 // Todo: refactor UMLClipboard to support pasting to a non-current item
1946 setCurrentItem(target);
1947
1948 // Paste the data (not always clip3)
1949 if (!clipboard.paste(m_dragCopyData)) {
1950 uError() << "Unable to copy selected item into the target item";
1951 }
1952 } else {
1953 UMLDragData::LvTypeAndID_List srcList;
1954 if (! UMLDragData::getClip3TypeAndID(de->mimeData(), srcList)) {
1955 uError() << "Unexpected mime data in drop event";
1956 return;
1957 }
1958 UMLDragData::LvTypeAndID_It it(srcList);
1959 UMLDragData::LvTypeAndID * src = 0;
1960 while (it.hasNext()) {
1961 src = it.next();
1962 moveObject(src->id, src->type, target);
1963 }
1964 }
1965 }
1966
1967 /**
1968 * Get selected items.
1969 * @return the list of selected items
1970 */
selectedItems() const1971 UMLListViewItemList UMLListView::selectedItems() const
1972 {
1973 UMLListViewItemList itemList;
1974 // There is no QTreeWidgetItemConstIterator, hence we const_cast :/
1975 UMLListViewItemIterator it(const_cast<UMLListView*>(this));
1976 // iterate through all items of the list view
1977 for (; *it; ++it) {
1978 if ((*it)->isSelected()) {
1979 UMLListViewItem *item = (UMLListViewItem*)*it;
1980 itemList.append(item);
1981 }
1982 }
1983 // DEBUG(DBG_SRC) << "selected items = " << itemList.count();
1984
1985 return itemList;
1986 }
1987
1988 /**
1989 * Get selected items, but only root elements selected (without children).
1990 * @return the list of selected root items
1991 */
selectedItemsRoot() const1992 UMLListViewItemList UMLListView::selectedItemsRoot() const
1993 {
1994 UMLListViewItemList itemList;
1995 // There is no QTreeWidgetItemConstIterator, hence we const_cast :/
1996 UMLListViewItemIterator it(const_cast<UMLListView*>(this));
1997 // iterate through all items of the list view
1998 for (; *it; ++it) {
1999 if ((*it)->isSelected()) {
2000 UMLListViewItem *item = (UMLListViewItem*)*it;
2001 // this is the trick, we select only the item with a parent unselected
2002 // since we can't select a child and its grandfather without its parent
2003 // we would be able to delete each item individually, without an invalid iterator
2004 if (item && item->parent() && item->parent()->isSelected() == false) {
2005 itemList.append(item);
2006 }
2007 }
2008 }
2009
2010 return itemList;
2011 }
2012
2013 /**
2014 * Create a listview item for an existing diagram.
2015 *
2016 * @param view The existing diagram.
2017 */
createDiagramItem(UMLView * view)2018 UMLListViewItem* UMLListView::createDiagramItem(UMLView *view)
2019 {
2020 if (!view) {
2021 return 0;
2022 }
2023 UMLListViewItem::ListViewType lvt = Model_Utils::convert_DT_LVT(view->umlScene()->type());
2024 UMLListViewItem *parent = 0;
2025 UMLFolder *f = view->umlScene()->folder();
2026 if (f) {
2027 parent = findUMLObject(f);
2028 if (parent == 0)
2029 uError() << view->umlScene()->name() << ": findUMLObject(" << f->name() << ") returns 0";
2030 } else {
2031 DEBUG(DBG_SRC) << view->umlScene()->name() << ": no parent folder set, using predefined folder";
2032 }
2033 if (parent == 0) {
2034 parent = determineParentItem(lvt);
2035 lvt = Model_Utils::convert_DT_LVT(view->umlScene()->type());
2036 }
2037 UMLListViewItem *item = new UMLListViewItem(parent, view->umlScene()->name(), lvt, view->umlScene()->ID());
2038 return item;
2039 }
2040
2041 /**
2042 * Determine the parent ListViewItem given a ListViewType.
2043 * This parent is used for creating new UMLListViewItems.
2044 *
2045 * @param lvt The ListViewType for which to lookup the parent.
2046 * @return Pointer to the parent UMLListViewItem chosen.
2047 */
determineParentItem(UMLListViewItem::ListViewType lvt) const2048 UMLListViewItem* UMLListView::determineParentItem(UMLListViewItem::ListViewType lvt) const
2049 {
2050 UMLListViewItem* parent = 0;
2051 switch (lvt) {
2052 case UMLListViewItem::lvt_Datatype:
2053 parent = m_datatypeFolder;
2054 break;
2055 case UMLListViewItem::lvt_Actor:
2056 case UMLListViewItem::lvt_UseCase:
2057 case UMLListViewItem::lvt_UseCase_Folder:
2058 case UMLListViewItem::lvt_UseCase_Diagram:
2059 parent = m_lv[Uml::ModelType::UseCase];
2060 break;
2061 case UMLListViewItem::lvt_Component_Diagram:
2062 case UMLListViewItem::lvt_Component:
2063 case UMLListViewItem::lvt_Port:
2064 case UMLListViewItem::lvt_Artifact:
2065 parent = m_lv[Uml::ModelType::Component];
2066 break;
2067 case UMLListViewItem::lvt_Deployment_Diagram:
2068 case UMLListViewItem::lvt_Node:
2069 parent = m_lv[Uml::ModelType::Deployment];
2070 break;
2071 case UMLListViewItem::lvt_EntityRelationship_Diagram:
2072 case UMLListViewItem::lvt_Entity:
2073 case UMLListViewItem::lvt_Category:
2074 parent = m_lv[Uml::ModelType::EntityRelationship];
2075 break;
2076 default:
2077 if (Model_Utils::typeIsDiagram(lvt) || !Model_Utils::typeIsClassifierList(lvt))
2078 parent = m_lv[Uml::ModelType::Logical];
2079 break;
2080 }
2081 return parent;
2082 }
2083
2084 /**
2085 * Return the amount of items selected.
2086 */
selectedItemsCount() const2087 int UMLListView::selectedItemsCount() const
2088 {
2089 UMLListViewItemList items = selectedItems();
2090 return items.count();
2091 }
2092
2093 /**
2094 * Returns the document pointer. Called by the UMLListViewItem class.
2095 */
document() const2096 UMLDoc * UMLListView::document() const
2097 {
2098 return m_doc;
2099 }
2100
2101 /**
2102 * Event handler for lost focus.
2103 * @param fe the focus event
2104 */
focusOutEvent(QFocusEvent * fe)2105 void UMLListView::focusOutEvent(QFocusEvent * fe)
2106 {
2107 Qt::FocusReason reason = fe->reason();
2108 if (reason != Qt::PopupFocusReason && reason != Qt::MouseFocusReason) {
2109 clearSelection();
2110 //triggerUpdate();
2111 }
2112 //repaint();
2113
2114 QTreeWidget::focusOutEvent(fe);
2115 }
2116
contextMenuEvent(QContextMenuEvent * event)2117 void UMLListView::contextMenuEvent(QContextMenuEvent *event)
2118 {
2119 // Get the UMLListViewItem at the point where the mouse pointer was pressed
2120 UMLListViewItem * item = static_cast<UMLListViewItem*>(itemAt(event->pos()));
2121 if (item) {
2122 UMLListViewPopupMenu popup(this, item);
2123 QAction *triggered = popup.exec(event->globalPos());
2124 slotMenuSelection(triggered, event->globalPos());
2125 event->accept();
2126 }
2127
2128 QTreeWidget::contextMenuEvent(event);
2129 }
2130
2131 /**
2132 * Determines the root listview type of the given UMLListViewItem.
2133 * Starts at the given item, compares it against each of the
2134 * predefined root views (Root, Logical, UseCase, Component,
2135 * Deployment, EntityRelationship.) Returns the ListViewType
2136 * of the matching root view; if no match then continues the
2137 * search using the item's parent, then grandparent, and so forth.
2138 * Returns UMLListViewItem::lvt_Unknown if no match at all is found.
2139 */
rootViewType(UMLListViewItem * item)2140 UMLListViewItem::ListViewType UMLListView::rootViewType(UMLListViewItem *item)
2141 {
2142 if (item == m_rv)
2143 return UMLListViewItem::lvt_View;
2144 if (item == m_lv[Uml::ModelType::Logical])
2145 return UMLListViewItem::lvt_Logical_View;
2146 if (item == m_lv[Uml::ModelType::UseCase])
2147 return UMLListViewItem::lvt_UseCase_View;
2148 if (item == m_lv[Uml::ModelType::Component])
2149 return UMLListViewItem::lvt_Component_View;
2150 if (item == m_lv[Uml::ModelType::Deployment])
2151 return UMLListViewItem::lvt_Deployment_View;
2152 if (item == m_lv[Uml::ModelType::EntityRelationship])
2153 return UMLListViewItem::lvt_EntityRelationship_Model;
2154 UMLListViewItem *parent = dynamic_cast<UMLListViewItem*>(item->parent());
2155 if (parent)
2156 return rootViewType(parent);
2157 return UMLListViewItem::lvt_Unknown;
2158 }
2159
2160 /**
2161 * Return true if the given list view type can be expanded/collapsed.
2162 */
isExpandable(UMLListViewItem::ListViewType lvt)2163 bool UMLListView::isExpandable(UMLListViewItem::ListViewType lvt)
2164 {
2165 if (Model_Utils::typeIsRootView(lvt) || Model_Utils::typeIsFolder(lvt))
2166 return true;
2167 switch (lvt) {
2168 case UMLListViewItem::lvt_Package:
2169 case UMLListViewItem::lvt_Component:
2170 case UMLListViewItem::lvt_Subsystem:
2171 return true;
2172 break;
2173 default:
2174 break;
2175 }
2176 return false;
2177 }
2178
2179 /**
2180 * Calls updateFolder() on the item to update the icon to open.
2181 */
slotExpanded(QTreeWidgetItem * item)2182 void UMLListView::slotExpanded(QTreeWidgetItem * item)
2183 {
2184 UMLListViewItem * myItem = dynamic_cast<UMLListViewItem*>(item);
2185 if (!myItem)
2186 return;
2187 if (isExpandable(myItem->type())) {
2188 myItem->updateFolder();
2189 }
2190 }
2191
2192 /**
2193 * Calls updateFolder() on the item to update the icon to closed.
2194 */
slotCollapsed(QTreeWidgetItem * item)2195 void UMLListView::slotCollapsed(QTreeWidgetItem * item)
2196 {
2197 UMLListViewItem * myItem = dynamic_cast<UMLListViewItem*>(item);
2198 if (!myItem)
2199 return;
2200 if (isExpandable(myItem->type())) {
2201 myItem->updateFolder();
2202 }
2203 }
2204
2205 /**
2206 * Connects to the signal that @ref UMLApp emits when a
2207 * cut operation is successful.
2208 */
slotCutSuccessful()2209 void UMLListView::slotCutSuccessful()
2210 {
2211 if (m_bStartedCut) {
2212 UMLListViewItem* item = static_cast<UMLListViewItem*>(currentItem());
2213 deleteItem(item);
2214
2215 m_bStartedCut = false;
2216 }
2217 }
2218
2219 /**
2220 * Delete every selected item
2221 */
slotDeleteSelectedItems()2222 void UMLListView::slotDeleteSelectedItems()
2223 {
2224 UMLListViewItemList itemsSelected = selectedItemsRoot();
2225 foreach(UMLListViewItem *item, itemsSelected) {
2226 deleteItem(item);
2227 }
2228 }
2229
2230 /**
2231 * Adds a new item to the tree of the given type under the given parent.
2232 * Method will take care of signalling anyone needed on creation of new item.
2233 * e.g. UMLDoc if a UMLObject is created.
2234 */
addNewItem(UMLListViewItem * parentItem,UMLListViewItem::ListViewType type)2235 void UMLListView::addNewItem(UMLListViewItem *parentItem, UMLListViewItem::ListViewType type)
2236 {
2237 if (type == UMLListViewItem::lvt_Datatype) {
2238 parentItem = m_datatypeFolder;
2239 }
2240
2241 parentItem->setOpen(true);
2242
2243 // Determine the UMLObject belonging to the listview item we're using as parent
2244 UMLObject* parent = parentItem->umlObject();
2245 if (parent == 0) {
2246 uError() << "UMLListView::addNewItem - "
2247 << UMLListViewItem::toString(type) << ": parentPkg is 0";
2248 return;
2249 }
2250
2251 if (Model_Utils::typeIsDiagram(type)) {
2252 Uml::DiagramType::Enum diagramType = Model_Utils::convert_LVT_DT(type);
2253 QString diagramName = m_doc->createDiagramName(diagramType);
2254 if (diagramName.isEmpty()) {
2255 // creation was cancelled by the user
2256 return;
2257 }
2258 UMLFolder* parent = parentItem->umlObject()->asUMLFolder();
2259 UMLApp::app()->executeCommand(new Uml::CmdCreateDiagram(m_doc, diagramType, diagramName, parent));
2260 return;
2261 }
2262
2263 // Determine the ObjectType of the new object
2264 UMLObject::ObjectType objectType = Model_Utils::convert_LVT_OT(type);
2265 if (objectType == UMLObject::ot_UMLObject) {
2266 uError() << "no UMLObject for type " << UMLListViewItem::toString(type);
2267 return;
2268 }
2269
2270 if (Model_Utils::typeIsClassifierList(type)) {
2271 UMLClassifier* classifier = parent->asUMLClassifier();
2272 QString name = classifier->uniqChildName(objectType);
2273 UMLObject* object = Object_Factory::createChildObject(classifier, objectType, name);
2274
2275 if (object == 0) {
2276 // creation was cancelled by the user
2277 return;
2278 }
2279
2280 // Handle primary key constraints (mark the unique constraint as PK on
2281 // the parent entity)
2282 if (type == UMLListViewItem::lvt_PrimaryKeyConstraint) {
2283 UMLUniqueConstraint* uuc = object->asUMLUniqueConstraint();
2284 UMLEntity* ent = uuc ? uuc->umlParent()->asUMLEntity() : 0;
2285 if (ent) {
2286 ent->setAsPrimaryKey(uuc);
2287 }
2288 }
2289 } else {
2290 bool instanceOfClass = (type == UMLListViewItem::lvt_Instance && parent->isUMLClassifier());
2291 UMLPackage* package = (instanceOfClass ? parent->umlPackage() : parent->asUMLPackage());
2292 QString name = Model_Utils::uniqObjectName(objectType, package);
2293 UMLObject* object = Object_Factory::createUMLObject(objectType, name, package);
2294
2295 if (object == 0) {
2296 // creation was cancelled by the user
2297 return;
2298 }
2299
2300 if (type == UMLListViewItem::lvt_Subsystem) {
2301 object->setStereotypeCmd(QLatin1String("subsystem"));
2302 } else if (Model_Utils::typeIsFolder(type)) {
2303 object->setStereotypeCmd(QLatin1String("folder"));
2304 } else if (instanceOfClass) {
2305 qApp->processEvents();
2306 UMLInstance *inst = object->asUMLInstance();
2307 inst->setClassifierCmd(parent->asUMLClassifier());
2308 UMLListViewItem *instanceItem = findUMLObject(inst);
2309 if (instanceItem == 0) {
2310 uError() << "listviewitem for " << inst->name() << " not found";
2311 return;
2312 }
2313 scrollToItem(instanceItem);
2314 clearSelection();
2315 instanceItem->setSelected(true);
2316 UMLObjectList& values = inst->subordinates();
2317 foreach (UMLObject *child, values) {
2318 if (!child->isUMLInstanceAttribute())
2319 continue;
2320 connectNewObjectsSlots(child);
2321 const QString text = child->asUMLInstanceAttribute()->toString();
2322 UMLListViewItem *childItem =
2323 new UMLListViewItem(instanceItem, text, UMLListViewItem::lvt_InstanceAttribute , child);
2324 Q_UNUSED(childItem);
2325 }
2326 }
2327 }
2328 }
2329
2330 /**
2331 * Returns if the given name is unique for the given items type.
2332 */
isUnique(UMLListViewItem * item,const QString & name) const2333 bool UMLListView::isUnique(UMLListViewItem * item, const QString &name) const
2334 {
2335 UMLListViewItem * parentItem = static_cast<UMLListViewItem *>(item->parent());
2336 UMLListViewItem::ListViewType type = item->type();
2337 switch (type) {
2338 case UMLListViewItem::lvt_Class_Diagram:
2339 return !m_doc->findView(Uml::DiagramType::Class, name);
2340 break;
2341
2342 case UMLListViewItem::lvt_Sequence_Diagram:
2343 return !m_doc->findView(Uml::DiagramType::Sequence, name);
2344 break;
2345
2346 case UMLListViewItem::lvt_UseCase_Diagram:
2347 return !m_doc->findView(Uml::DiagramType::UseCase, name);
2348 break;
2349
2350 case UMLListViewItem::lvt_Collaboration_Diagram:
2351 return !m_doc->findView(Uml::DiagramType::Collaboration, name);
2352 break;
2353
2354 case UMLListViewItem::lvt_State_Diagram:
2355 return !m_doc->findView(Uml::DiagramType::State, name);
2356 break;
2357
2358 case UMLListViewItem::lvt_Activity_Diagram:
2359 return !m_doc->findView(Uml::DiagramType::Activity, name);
2360 break;
2361
2362 case UMLListViewItem::lvt_Component_Diagram:
2363 return !m_doc->findView(Uml::DiagramType::Component, name);
2364 break;
2365
2366 case UMLListViewItem::lvt_Deployment_Diagram:
2367 return !m_doc->findView(Uml::DiagramType::Deployment, name);
2368 break;
2369
2370 case UMLListViewItem::lvt_EntityRelationship_Diagram:
2371 return !m_doc->findView(Uml::DiagramType::EntityRelationship, name);
2372 break;
2373
2374 case UMLListViewItem::lvt_Object_Diagram:
2375 return !m_doc->findView(Uml::DiagramType::Object, name);
2376 break;
2377
2378 case UMLListViewItem::lvt_Actor:
2379 case UMLListViewItem::lvt_UseCase:
2380 case UMLListViewItem::lvt_Node:
2381 case UMLListViewItem::lvt_Artifact:
2382 case UMLListViewItem::lvt_Category:
2383 case UMLListViewItem::lvt_Instance:
2384 return !m_doc->findUMLObject(name, Model_Utils::convert_LVT_OT(type));
2385 break;
2386
2387 case UMLListViewItem::lvt_Class:
2388 case UMLListViewItem::lvt_Package:
2389 case UMLListViewItem::lvt_Interface:
2390 case UMLListViewItem::lvt_Datatype:
2391 case UMLListViewItem::lvt_Enum:
2392 case UMLListViewItem::lvt_Entity:
2393 case UMLListViewItem::lvt_Component:
2394 case UMLListViewItem::lvt_Port:
2395 case UMLListViewItem::lvt_Subsystem:
2396 case UMLListViewItem::lvt_Logical_Folder:
2397 case UMLListViewItem::lvt_UseCase_Folder:
2398 case UMLListViewItem::lvt_Component_Folder:
2399 case UMLListViewItem::lvt_Deployment_Folder:
2400 case UMLListViewItem::lvt_EntityRelationship_Folder: {
2401 UMLListViewItem::ListViewType lvt = parentItem->type();
2402 if (!Model_Utils::typeIsContainer(lvt))
2403 return (m_doc->findUMLObject(name) == 0);
2404 UMLPackage *pkg = parentItem->umlObject()->asUMLPackage();
2405 if (pkg == 0) {
2406 uError() << "internal error - "
2407 << "parent listviewitem is package but has no UMLObject";
2408 return true;
2409 }
2410 return (pkg->findObject(name) == 0);
2411 break;
2412 }
2413
2414 case UMLListViewItem::lvt_Template:
2415 case UMLListViewItem::lvt_Attribute:
2416 case UMLListViewItem::lvt_EntityAttribute:
2417 case UMLListViewItem::lvt_InstanceAttribute:
2418 case UMLListViewItem::lvt_Operation:
2419 case UMLListViewItem::lvt_EnumLiteral:
2420 case UMLListViewItem::lvt_UniqueConstraint:
2421 case UMLListViewItem::lvt_PrimaryKeyConstraint:
2422 case UMLListViewItem::lvt_ForeignKeyConstraint:
2423 case UMLListViewItem::lvt_CheckConstraint: {
2424 UMLClassifier *parent = parentItem->umlObject()->asUMLClassifier();
2425 if (parent == 0) {
2426 uError() << "internal error - "
2427 << "parent listviewitem is package but has no UMLObject";
2428 return true;
2429 }
2430 return (parent->findChildObject(name) == 0);
2431 break;
2432 }
2433
2434 default:
2435 break;
2436 }
2437 return false;
2438 }
2439
2440 /**
2441 *
2442 */
saveToXMI1(QXmlStreamWriter & writer)2443 void UMLListView::saveToXMI1(QXmlStreamWriter& writer)
2444 {
2445 writer.writeStartElement(QLatin1String("listview"));
2446 m_rv->saveToXMI1(writer);
2447 writer.writeEndElement();
2448 }
2449
2450 /**
2451 *
2452 */
loadFromXMI1(QDomElement & element)2453 bool UMLListView::loadFromXMI1(QDomElement & element)
2454 {
2455 QDomNode node = element.firstChild();
2456 QDomElement domElement = node.toElement();
2457 m_doc->writeToStatusBar(i18n("Loading listview..."));
2458 while (!domElement.isNull()) {
2459 if (domElement.tagName() == QLatin1String("listitem")) {
2460 QString type = domElement.attribute(QLatin1String("type"), QLatin1String("-1"));
2461 if (type == QLatin1String("-1"))
2462 return false;
2463 UMLListViewItem::ListViewType lvType = (UMLListViewItem::ListViewType)type.toInt();
2464 if (lvType == UMLListViewItem::lvt_View) {
2465 if (!loadChildrenFromXMI(m_rv, domElement))
2466 return false;
2467 } else
2468 return false;
2469 }
2470 node = node.nextSibling();
2471 domElement = node.toElement();
2472
2473 }//end while
2474 return true;
2475 }
2476
2477 /**
2478 *
2479 */
loadChildrenFromXMI(UMLListViewItem * parent,QDomElement & element)2480 bool UMLListView::loadChildrenFromXMI(UMLListViewItem * parent, QDomElement & element)
2481 {
2482 QDomNode node = element.firstChild();
2483 QDomElement domElement = node.toElement();
2484 while (!domElement.isNull()) {
2485 node = domElement.nextSibling();
2486 if (domElement.tagName() != QLatin1String("listitem")) {
2487 domElement = node.toElement();
2488 continue;
2489 }
2490 QString id = domElement.attribute(QLatin1String("id"), QLatin1String("-1"));
2491 QString type = domElement.attribute(QLatin1String("type"), QLatin1String("-1"));
2492 QString label = domElement.attribute(QLatin1String("label"));
2493 QString open = domElement.attribute(QLatin1String("open"), QLatin1String("1"));
2494 if (type == QLatin1String("-1"))
2495 return false;
2496 UMLListViewItem::ListViewType lvType = (UMLListViewItem::ListViewType)type.toInt();
2497 bool bOpen = (bool)open.toInt();
2498 Uml::ID::Type nID = Uml::ID::fromString(id);
2499 UMLListViewItem * item = 0;
2500 if (nID != Uml::ID::None) {
2501 // The following is an ad hoc hack for the copy/paste code.
2502 // The clip still contains the old children although new
2503 // UMLCLassifierListItems have already been created.
2504 // If the IDChangeLog finds new IDs this means we are in
2505 // copy/paste and need to adjust the child listitems to the
2506 // new UMLCLassifierListItems.
2507 IDChangeLog *idchanges = m_doc->changeLog();
2508 if (idchanges) {
2509 Uml::ID::Type newID = idchanges->findNewID(nID);
2510 if (newID != Uml::ID::None) {
2511 DEBUG(DBG_SRC) << " using id " << Uml::ID::toString(newID)
2512 << " instead of " << Uml::ID::toString(nID);
2513 nID = newID;
2514 }
2515 }
2516 /************ End of hack for copy/paste code ************/
2517
2518 UMLObject *pObject = m_doc->findObjectById(nID);
2519 if (pObject) {
2520 if (label.isEmpty())
2521 label = pObject->name();
2522 } else if (Model_Utils::typeIsFolder(lvType)) {
2523 // Synthesize the UMLFolder here
2524 UMLObject *umlParent = parent->umlObject();
2525 UMLPackage *parentPkg = umlParent->asUMLPackage();
2526 if (parentPkg == 0) {
2527 uError() << "umlParent(" << umlParent << ") is not a UMLPackage";
2528 domElement = node.toElement();
2529 continue;
2530 }
2531 UMLFolder *f = new UMLFolder(label, nID);
2532 f->setUMLPackage(parentPkg);
2533 parentPkg->addObject(f);
2534 pObject = f;
2535 item = new UMLListViewItem(parent, label, lvType, pObject);
2536 // Moving all relevant UMLObjects to the new UMLFolder is done below,
2537 // in the switch(lvType)
2538 }
2539 } else if (Model_Utils::typeIsRootView(lvType)) {
2540 // Predefined folders did not have their ID set.
2541 const Uml::ModelType::Enum mt = Model_Utils::convert_LVT_MT(lvType);
2542 nID = m_doc->rootFolder(mt)->id();
2543 } else if (Model_Utils::typeIsFolder(lvType)) {
2544 // Pre-1.2 format: Folders did not have their ID set.
2545 // Pull a new ID now.
2546 nID = m_doc->rootFolder(Uml::ModelType::Logical)->id();
2547 } else {
2548 uError() << "item of type " << type << " has no ID, skipping.";
2549 domElement = node.toElement();
2550 continue;
2551 }
2552
2553 switch (lvType) {
2554 case UMLListViewItem::lvt_Actor:
2555 case UMLListViewItem::lvt_UseCase:
2556 case UMLListViewItem::lvt_Class:
2557 case UMLListViewItem::lvt_Instance:
2558 case UMLListViewItem::lvt_Interface:
2559 case UMLListViewItem::lvt_Datatype:
2560 case UMLListViewItem::lvt_Enum:
2561 case UMLListViewItem::lvt_Entity:
2562 case UMLListViewItem::lvt_Package:
2563 case UMLListViewItem::lvt_Subsystem:
2564 case UMLListViewItem::lvt_Component:
2565 case UMLListViewItem::lvt_Port:
2566 case UMLListViewItem::lvt_Node:
2567 case UMLListViewItem::lvt_Artifact:
2568 case UMLListViewItem::lvt_Logical_Folder:
2569 case UMLListViewItem::lvt_UseCase_Folder:
2570 case UMLListViewItem::lvt_Component_Folder:
2571 case UMLListViewItem::lvt_Deployment_Folder:
2572 case UMLListViewItem::lvt_EntityRelationship_Folder:
2573 case UMLListViewItem::lvt_Category:
2574 item = findItem(nID);
2575 if (item == 0) {
2576 uError() << "INTERNAL ERROR: "
2577 << "findItem(id " << Uml::ID::toString(nID) << ") returns 0";
2578 } else if (parent != item->parent()) {
2579 // The existing item was created by the slot event triggered
2580 // by the loading of the corresponding model object from the
2581 // XMI file.
2582 UMLListViewItem *itmParent = dynamic_cast<UMLListViewItem*>(item->parent());
2583 DEBUG(DBG_SRC) << "Loaded <listview> entry does not match uml model"
2584 << item->text(0) << " parent "
2585 << parent->text(0) << " (" << parent << ") != "
2586 << (itmParent ? itmParent->text(0) : QLatin1String(""))
2587 << " (" << itmParent << ")";
2588 }
2589 break;
2590 case UMLListViewItem::lvt_Attribute:
2591 case UMLListViewItem::lvt_EntityAttribute:
2592 case UMLListViewItem::lvt_InstanceAttribute:
2593 case UMLListViewItem::lvt_Template:
2594 case UMLListViewItem::lvt_Operation:
2595 case UMLListViewItem::lvt_EnumLiteral:
2596 case UMLListViewItem::lvt_UniqueConstraint:
2597 case UMLListViewItem::lvt_PrimaryKeyConstraint:
2598 case UMLListViewItem::lvt_ForeignKeyConstraint:
2599 case UMLListViewItem::lvt_CheckConstraint:
2600 item = findItem(nID);
2601 if (item == 0) {
2602 DEBUG(DBG_SRC) << "item " << Uml::ID::toString(nID) << " (of type "
2603 << UMLListViewItem::toString(lvType) << ") does not yet exist...";
2604 UMLObject* umlObject = parent->umlObject();
2605 if (!umlObject) {
2606 DEBUG(DBG_SRC) << "And also the parent->umlObject() does not exist";
2607 return false;
2608 }
2609 if (nID == Uml::ID::None) {
2610 uWarning() << "lvtype " << UMLListViewItem::toString(lvType) << " has id -1";
2611 } else if (lvType == UMLListViewItem::lvt_InstanceAttribute) {
2612 UMLInstance *instance = umlObject->asUMLInstance();
2613 if (instance) {
2614 umlObject = instance->findChildObjectById(nID);
2615 if (umlObject) {
2616 UMLInstanceAttribute *instAttr = umlObject->asUMLInstanceAttribute();
2617 connectNewObjectsSlots(instAttr);
2618 label = instAttr->toString();
2619 item = new UMLListViewItem(parent, label, lvType, instAttr);
2620 } else {
2621 DEBUG(DBG_SRC) << umlObject->name() << " lvt_InstanceAttribute child "
2622 << " object " << Uml::ID::toString(nID) << " not found";
2623 }
2624 } else {
2625 DEBUG(DBG_SRC) << "cast to instance object failed";
2626 }
2627 } else {
2628 UMLClassifier *classifier = umlObject->asUMLClassifier();
2629 if (classifier) {
2630 umlObject = classifier->findChildObjectById(nID);
2631 if (umlObject) {
2632 connectNewObjectsSlots(umlObject);
2633 label = umlObject->name();
2634 item = new UMLListViewItem(parent, label, lvType, umlObject);
2635 } else {
2636 DEBUG(DBG_SRC) << "lvtype " << UMLListViewItem::toString(lvType)
2637 << " child object " << Uml::ID::toString(nID) << " not found";
2638 }
2639 } else {
2640 DEBUG(DBG_SRC) << "cast to classifier object failed";
2641 }
2642 }
2643 }
2644 break;
2645 case UMLListViewItem::lvt_Logical_View:
2646 item = m_lv[Uml::ModelType::Logical];
2647 break;
2648 case UMLListViewItem::lvt_Datatype_Folder:
2649 item = m_datatypeFolder;
2650 break;
2651 case UMLListViewItem::lvt_UseCase_View:
2652 item = m_lv[Uml::ModelType::UseCase];
2653 break;
2654 case UMLListViewItem::lvt_Component_View:
2655 item = m_lv[Uml::ModelType::Component];
2656 break;
2657 case UMLListViewItem::lvt_Deployment_View:
2658 item = m_lv[Uml::ModelType::Deployment];
2659 break;
2660 case UMLListViewItem::lvt_EntityRelationship_Model:
2661 item = m_lv[Uml::ModelType::EntityRelationship];
2662 break;
2663 default:
2664 if (Model_Utils::typeIsDiagram(lvType)) {
2665 item = new UMLListViewItem(parent, label, lvType, nID);
2666 } else {
2667 uError() << "INTERNAL ERROR: unexpected listview type "
2668 << UMLListViewItem::toString(lvType) << " (ID " << Uml::ID::toString(nID) << ")";
2669 }
2670 break;
2671 }//end switch
2672
2673 if (item) {
2674 item->setOpen((bool)bOpen);
2675 if (!loadChildrenFromXMI(item, domElement)) {
2676 return false;
2677 }
2678 } else {
2679 uWarning() << "unused list view item " << Uml::ID::toString(nID)
2680 << " of lvtype " << UMLListViewItem::toString(lvType);
2681 }
2682 domElement = node.toElement();
2683 }//end while
2684 return true;
2685 }
2686
2687 /**
2688 * Open all items in the list view.
2689 */
expandAll(UMLListViewItem * item)2690 void UMLListView::expandAll(UMLListViewItem *item)
2691 {
2692 if (!item) item = m_rv;
2693 for (int i = 0; i < item->childCount(); i++) {
2694 expandAll(item->childItem(i));
2695 }
2696 item->setExpanded(true);
2697 }
2698
2699 /**
2700 * Close all items in the list view.
2701 */
collapseAll(UMLListViewItem * item)2702 void UMLListView::collapseAll(UMLListViewItem *item)
2703 {
2704 if (!item) item = m_rv;
2705 for (int i = 0; i < item->childCount(); i++) {
2706 collapseAll(item->childItem(i));
2707 }
2708 item->setExpanded(false);
2709 }
2710
2711 /**
2712 * Set the variable m_bStartedCut
2713 * to indicate that selection should be deleted
2714 * in slotCutSuccessful().
2715 */
setStartedCut(bool startedCut)2716 void UMLListView::setStartedCut(bool startedCut)
2717 {
2718 m_bStartedCut = startedCut;
2719 }
2720
2721 /**
2722 * Set the variable m_bStartedCopy.
2723 * NB: While m_bStartedCut is reset as soon as the Cut operation is done,
2724 * the variable m_bStartedCopy is reset much later - upon pasting.
2725 */
setStartedCopy(bool startedCopy)2726 void UMLListView::setStartedCopy(bool startedCopy)
2727 {
2728 m_bStartedCopy = startedCopy;
2729 }
2730
2731 /**
2732 * Return the variable m_bStartedCopy.
2733 */
startedCopy() const2734 bool UMLListView::startedCopy() const
2735 {
2736 return m_bStartedCopy;
2737 }
2738
2739 /**
2740 * Returns the corresponding view if the listview type is one of the root views,
2741 * Root/Logical/UseCase/Component/Deployment/EntityRelation View.
2742 */
rootView(UMLListViewItem::ListViewType type)2743 UMLListViewItem *UMLListView::rootView(UMLListViewItem::ListViewType type)
2744 {
2745 UMLListViewItem *theView = 0;
2746 switch (type) {
2747 case UMLListViewItem::lvt_View:
2748 theView = m_rv;
2749 break;
2750 case UMLListViewItem::lvt_Logical_View:
2751 theView = m_lv[Uml::ModelType::Logical];
2752 break;
2753 case UMLListViewItem::lvt_UseCase_View:
2754 theView = m_lv[Uml::ModelType::UseCase];
2755 break;
2756 case UMLListViewItem::lvt_Component_View:
2757 theView = m_lv[Uml::ModelType::Component];
2758 break;
2759 case UMLListViewItem::lvt_Deployment_View:
2760 theView = m_lv[Uml::ModelType::Deployment];
2761 break;
2762 case UMLListViewItem::lvt_EntityRelationship_Model:
2763 theView = m_lv[Uml::ModelType::EntityRelationship];
2764 break;
2765 case UMLListViewItem::lvt_Datatype_Folder: // @todo fix asymmetric naming
2766 theView = m_datatypeFolder;
2767 break;
2768 default:
2769 break;
2770 }
2771 return theView;
2772 }
2773
2774 /**
2775 * Deletes all child-items of @p parent.
2776 * Do it in reverse order, because of the index.
2777 */
deleteChildrenOf(UMLListViewItem * parent)2778 void UMLListView::deleteChildrenOf(UMLListViewItem* parent)
2779 {
2780 if (!parent) {
2781 return;
2782 }
2783 if (parent == m_lv[Uml::ModelType::Logical]) {
2784 delete m_datatypeFolder;
2785 m_datatypeFolder = 0;
2786 }
2787 for (int i = parent->childCount() - 1; i >= 0; --i)
2788 parent->removeChild(parent->child(i));
2789 }
2790
2791 /**
2792 *
2793 */
closeDatatypesFolder()2794 void UMLListView::closeDatatypesFolder()
2795 {
2796 m_datatypeFolder->setOpen(false);
2797 }
2798
2799 /**
2800 * Delete a listview item.
2801 * @param temp a non-null UMLListViewItem, for example: (UMLListViewItem*)currentItem()
2802 * @return true if correctly deleted
2803 */
deleteItem(UMLListViewItem * temp)2804 bool UMLListView::deleteItem(UMLListViewItem *temp)
2805 {
2806 if (!temp)
2807 return false;
2808 UMLObject *object = temp->umlObject();
2809 UMLListViewItem::ListViewType lvt = temp->type();
2810 if (Model_Utils::typeIsDiagram(lvt)) {
2811 m_doc->removeDiagram(temp->ID());
2812 } else if (temp == m_datatypeFolder) {
2813 // we can't delete the datatypeFolder because umbrello will crash without a special handling
2814 return false;
2815 } else if (Model_Utils::typeIsCanvasWidget(lvt) || Model_Utils::typeIsClassifierList(lvt)) {
2816 UMLPackage *nmSpc = object->asUMLPackage();
2817 if (nmSpc) {
2818 UMLObjectList contained = nmSpc->containedObjects();
2819 if (contained.count()) {
2820 if (nmSpc->baseType() == UMLObject::ot_Class) {
2821 KMessageBox::error(
2822 nullptr,
2823 i18n("The class must be emptied before it can be deleted."),
2824 i18n("Class Not Empty"));
2825 } else if (nmSpc->baseType() == UMLObject::ot_Package) {
2826 KMessageBox::error(
2827 nullptr,
2828 i18n("The package must be emptied before it can be deleted."),
2829 i18n("Package Not Empty"));
2830 } else if (nmSpc->baseType() == UMLObject::ot_Folder) {
2831 KMessageBox::error(
2832 nullptr,
2833 i18n("The folder must be emptied before it can be deleted."),
2834 i18n("Folder Not Empty"));
2835 }
2836 return false;
2837 }
2838 }
2839 UMLCanvasObject *canvasObj = object->asUMLCanvasObject();
2840 if (canvasObj) {
2841 // We cannot just delete canvasObj here: What if the object
2842 // is still being used by others (for example, as a parameter
2843 // or return type of an operation) ?
2844 // Deletion should not have been permitted in the first place
2845 // if the object still has users - but Umbrello is lacking
2846 // that logic.
2847 canvasObj->removeAllChildObjects();
2848 }
2849 if (object) {
2850 UMLApp::app()->executeCommand(new Uml::CmdRemoveUMLObject(object));
2851
2852 // Physical deletion of `temp' will be done by Qt signal, see
2853 // UMLDoc::removeUMLObject()
2854 } else {
2855 delete temp;
2856 }
2857 } else {
2858 uWarning() << "mt_Delete called with unknown type";
2859 }
2860 return true;
2861 }
2862
2863 /**
2864 * Always allow starting a drag
2865 */
dragEnterEvent(QDragEnterEvent * event)2866 void UMLListView::dragEnterEvent(QDragEnterEvent* event)
2867 {
2868 event->accept();
2869 }
2870
2871 /**
2872 * Check drag destination and update move/copy action
2873 */
dragMoveEvent(QDragMoveEvent * event)2874 void UMLListView::dragMoveEvent(QDragMoveEvent* event)
2875 {
2876 // Check if drag destination is compatible with source
2877 if (acceptDrag(event)) {
2878 event->acceptProposedAction();
2879 } else {
2880 event->ignore();
2881 return;
2882 }
2883 }
2884
2885 /**
2886 *
2887 */
dropEvent(QDropEvent * event)2888 void UMLListView::dropEvent(QDropEvent* event)
2889 {
2890 if (!acceptDrag(event)) {
2891 event->ignore();
2892 }
2893 else {
2894 UMLListViewItem* target = static_cast<UMLListViewItem*>(itemAt(event->pos()));
2895 if (!target) {
2896 DEBUG(DBG_SRC) << "itemAt(mousePoint) returns 0";
2897 event->ignore();
2898 return;
2899 }
2900 slotDropped(event, target);
2901 }
2902 }
2903
commitData(QWidget * editor)2904 void UMLListView::commitData(QWidget *editor)
2905 {
2906 if (!editor)
2907 return;
2908
2909 QModelIndex index = currentIndex();
2910 if (!index.isValid())
2911 return;
2912
2913 QAbstractItemDelegate *delegate = itemDelegate(index);
2914 editor->removeEventFilter(delegate);
2915 QByteArray n = editor->metaObject()->userProperty().name();
2916 if (n.isEmpty()) {
2917 DEBUG(DBG_SRC) << "no name property found in list view item editor";
2918 return;
2919 }
2920
2921 QString newText = editor->property(n).toString();
2922
2923 UMLListViewItem *item = dynamic_cast<UMLListViewItem *>(currentItem());
2924 if (!item) {
2925 DEBUG(DBG_SRC) << "no item found after editing model index" << index;
2926 return;
2927 }
2928 item->slotEditFinished(newText);
2929 editor->installEventFilter(delegate);
2930 }
2931
2932 /**
2933 * Set the background color.
2934 * @param color the new background color
2935 */
setBackgroundColor(const QColor & color)2936 void UMLListView::setBackgroundColor(const QColor & color)
2937 {
2938 QPalette palette;
2939 palette.setColor(backgroundRole(), color);
2940 setPalette(palette);
2941 }
2942
2943 /**
2944 * Overloading operator for debugging output.
2945 */
operator <<(QDebug out,const UMLListView & view)2946 QDebug operator<<(QDebug out, const UMLListView& view)
2947 {
2948 UMLListViewItem* header = static_cast<UMLListViewItem*>(view.headerItem());
2949 if (header) {
2950 out << *header;
2951 for(int indx = 0; indx < header->childCount(); ++indx) {
2952 UMLListViewItem* item = static_cast<UMLListViewItem*>(header->child(indx));
2953 if (item) {
2954 out << indx << " - " << *item << endl;
2955 }
2956 else {
2957 out << indx << " - " << "<null>" << endl;
2958 }
2959 }
2960 }
2961 else {
2962 out << "<null>";
2963 }
2964 return out.space();
2965 }
2966
2967