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