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 "listpopupmenu.h"
8 
9 // app includes
10 #include "activitywidget.h"
11 #include "associationline.h"
12 #include "associationwidget.h"
13 #include "category.h"
14 #include "classifier.h"
15 #include "classifierwidget.h"
16 #include "combinedfragmentwidget.h"
17 #include "debug_utils.h"
18 #include "floatingtextwidget.h"
19 #include "folder.h"
20 #include "forkjoinwidget.h"
21 #include "layoutgenerator.h"
22 #include "model_utils.h"
23 #include "objectnodewidget.h"
24 #include "objectwidget.h"
25 #include "notewidget.h"
26 #include "pinportbase.h"
27 #include "preconditionwidget.h"
28 #include "signalwidget.h"
29 #include "statewidget.h"
30 #include "uml.h"
31 #include "umldoc.h"
32 #include "umlscene.h"
33 #include "umlview.h"
34 #include "umllistview.h"
35 #include "umllistviewitem.h"
36 #include "widget_utils.h"
37 #include "widgetbase.h"
38 
39 // kde includes
40 #include <KLocalizedString>
41 #include <kactioncollection.h>
42 
43 DEBUG_REGISTER_DISABLED(ListPopupMenu)
44 
45 static const bool CHECKABLE = true;
46 
47 // uncomment to see not handled switch cases
48 //#define CHECK_SWITCH
49 
50 class DebugMenu {
51 public:
DebugMenu(ListPopupMenu::MenuType _m)52     DebugMenu(ListPopupMenu::MenuType _m) : m(_m) {}
DebugMenu(const QString & _m)53     DebugMenu(const QString & _m) : menu(_m) {}
54     ListPopupMenu::MenuType m{ListPopupMenu::mt_Undefined};
55     QString menu;
56 };
57 
58 class ListPopupMenuPrivate {
59 public:
60     QList<DebugMenu> debugActions;
~ListPopupMenuPrivate()61     ~ListPopupMenuPrivate()
62     {
63         debugActions.clear();
64     }
65 };
66 
67 #define DEBUG_AddAction(m) d->debugActions.append(DebugMenu(m))
68 #define DEBUG_StartMenu(m) d->debugActions.append(DebugMenu(m->title() + QLatin1String(" - start")))
69 #define DEBUG_EndMenu(m) d->debugActions.append(DebugMenu(m->title() + QLatin1String(" - end")))
70 
71 /**
72  * Constructs the popup menu
73  *
74  * @param parent   The parent to ListPopupMenu.
75  */
ListPopupMenu(QWidget * parent)76 ListPopupMenu::ListPopupMenu(QWidget *parent)
77   : KMenu(parent),
78     d(new ListPopupMenuPrivate)
79 {
80 }
81 
82 /**
83  * Standard destructor.
84  */
~ListPopupMenu()85 ListPopupMenu::~ListPopupMenu()
86 {
87     foreach (QAction* action, m_actions) {
88         delete action;
89     }
90     m_actions.clear();
91     delete d;
92 }
93 
newMenu(const QString & title,QWidget * widget)94 KMenu *ListPopupMenu::newMenu(const QString &title, QWidget *widget)
95 {
96     KMenu *menu = new KMenu(title, widget);
97     DEBUG_StartMenu(menu);
98     return menu;
99 }
100 
addMenu(KMenu * menu)101 void ListPopupMenu::addMenu(KMenu *menu)
102 {
103     KMenu::addMenu(menu);
104     DEBUG_EndMenu(menu);
105 }
106 
107 /**
108  * Shortcut for the frequently used addAction() calls.
109  *
110  * @param m   The MenuType for which to insert a menu item.
111  */
insert(MenuType m)112 void ListPopupMenu::insert(MenuType m)
113 {
114     insert(m, this);
115 }
116 
117 /**
118  * Shortcut for the frequently used addAction() calls.
119  *
120  * @param m      The MenuType for which to insert a menu item.
121  * @param menu   The KMenu for which to insert a menu item.
122  * @param s      The entry to be inserted from the action collection
123  */
insertFromActionKey(const MenuType m,KMenu * menu,const QString & s)124 void ListPopupMenu::insertFromActionKey(const MenuType m, KMenu *menu, const QString &s)
125 {
126     QAction* action = UMLApp::app()->actionCollection()->action(s);
127     insert(m, menu, action->icon(), action->text());
128 }
129 
130 /**
131  * Shortcut for the frequently used addAction() calls.
132  *
133  * @param m      The MenuType for which to insert a menu item.
134  * @param menu   The KMenu for which to insert a menu item.
135  */
insert(const MenuType m,KMenu * menu)136 void ListPopupMenu::insert(const MenuType m, KMenu* menu)
137 {
138     // Preprocessor macro for List Popup Menu Insert Small Icon
139 #define LPMISI(IT, TXT) m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::IT), TXT)
140     // Preprocessor macro for List Popup Menu Insert Bar Icon
141 #define LPMIBI(IT, TXT) m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::IT), TXT)
142     DEBUG_AddAction(m);
143     Q_ASSERT(menu != 0);
144     switch (m) {
145     case mt_Accept_Signal:              LPMISI(it_Accept_Signal,         i18n("Accept Signal")); break;
146     case mt_Accept_Time_Event:          LPMISI(it_Accept_TimeEvent,      i18n("Accept Time Event")); break;
147     case mt_Activity:                   LPMISI(it_UseCase,               i18n("Activity...")); break;
148     case mt_Activity_Transition:        LPMISI(it_Activity_Transition,   i18n("Activity Transition")); break;
149     case mt_Actor:                      LPMISI(it_Actor,                 i18n("Actor")); break;
150     //case mt_Actor:                      LPMISI(it_Actor,                 i18n("Actor...")); break;
151     case mt_Artifact:                   LPMISI(it_Artifact,              i18n("Artifact")); break;
152     //case mt_Artifact:                   LPMISI(it_Artifact,              i18n("Artifact...")); break;
153     case mt_Attribute:                  LPMISI(it_Public_Attribute,      i18n("Attribute")); break;
154     //case mt_Attribute:                  LPMISI(it_Public_Attribute,      i18n("Attribute...")); break;
155     case mt_Branch:                     LPMISI(it_Branch,                i18n("Branch/Merge")); break;
156     case mt_Category:                   LPMISI(it_Category,              i18n("Category")); break;
157     //case mt_Category:                   LPMISI(it_Category,              i18n("Category...")); break;
158     case mt_Change_Font:                LPMISI(it_Change_Font,           i18n("Change Font...")); break;
159     case mt_CheckConstraint:            LPMISI(it_Constraint_Check,      i18n("Check Constraint...")); break;
160     case mt_Choice:                     LPMISI(it_Choice_Rhomb,          i18n("Choice")); break;
161     case mt_Class:                      LPMISI(it_Class,                 i18nc("new class menu item", "Class...")); break;
162     case mt_Clone:                      LPMIBI(it_Duplicate,             i18nc("duplicate action", "Duplicate")); break;
163     case mt_Collapse_All:               m_actions[m] = menu->addAction(i18n("Collapse All")); break;
164     case mt_CombinedState:              LPMISI(it_State,                 i18nc("add new combined state", "Combined state...")); break;
165     case mt_Component:                  LPMISI(it_Component,             i18n("Component")); break;
166     //case mt_Component:                  LPMISI(it_Component,             i18n("Component...")); break;
167     case mt_Component_Diagram:          insertFromActionKey(m, menu, QLatin1String("new_component_diagram")); break;
168     case mt_Component_Folder:           LPMIBI(it_Folder,                i18n("Folder")); break;
169     case mt_Copy:                       LPMISI(it_Copy,                  i18n("Copy")); break;
170     case mt_Cut:                        LPMISI(it_Cut,                   i18n("Cut")); break;
171     case mt_Datatype:                   LPMISI(it_Datatype,              i18n("Datatype...")); break;
172     case mt_DeepHistory:                LPMISI(it_History_Deep,          i18n("Deep History")); break;
173     case mt_Delete:                     LPMISI(it_Delete,                i18n("Delete")); break;
174     case mt_Deployment_Diagram:         insertFromActionKey(m, menu, QLatin1String("new_deployment_diagram")); break;
175     case mt_Deployment_Folder:          LPMIBI(it_Folder,                i18n("Folder")); break;
176     case mt_EditCombinedState:          LPMISI(it_State,                 i18n("Edit combined state")); break;
177     case mt_End_Activity:               LPMISI(it_EndState,              i18n("End Activity")); break;
178     case mt_End_State:                  LPMISI(it_EndState,              i18n("End State")); break;
179     case mt_Entity:                     LPMISI(it_Entity,                i18n("Entity")); break;
180     //case mt_Entity:                     LPMISI(it_Entity,                i18n("Entity...")); break;
181     case mt_EntityAttribute:            LPMISI(it_Entity_Attribute,      i18n("Entity Attribute...")); break;
182     case mt_EntityRelationship_Diagram: insertFromActionKey(m, menu, QLatin1String("new_entityrelationship_diagram")); break;
183     case mt_EntityRelationship_Folder:  LPMIBI(it_Folder,                i18n("Folder")); break;
184     case mt_Enum:                       LPMISI(it_Enum,                  i18n("Enum...")); break;
185     case mt_EnumLiteral:                LPMISI(it_Enum_Literal,          i18n("Enum Literal...")); break;
186     case mt_Exception:                  LPMISI(it_Exception,             i18n("Exception")); break;
187     case mt_Expand_All:                 m_actions[m] = menu->addAction(i18n("Expand All")); break;
188     case mt_Export_Image:               LPMISI(it_Export_Picture,        i18n("Export as Picture...")); break;
189     case mt_Externalize_Folder:         m_actions[m] = menu->addAction(i18n("Externalize Folder...")); break;
190     case mt_Fill_Color:                 LPMISI(it_Color_Fill,            i18n("Fill Color...")); break;
191     case mt_Final_Activity:             LPMISI(it_Activity_Final,        i18n("Final Activity")); break;
192     case mt_FlipHorizontal:             m_actions[m] = menu->addAction(i18n("Flip Horizontal")); break;
193     case mt_FlipVertical:               m_actions[m] = menu->addAction(i18n("Flip Vertical")); break;
194     case mt_FloatText:                  LPMISI(it_Text,                  i18n("Text Line...")); break;
195     case mt_ForeignKeyConstraint:       LPMISI(it_Constraint_ForeignKey, i18n("Foreign Key Constraint...")); break;
196     case mt_Fork:                       LPMISI(it_Fork_Join,             i18n("Fork")); break;
197     case mt_GoToStateDiagram:           LPMISI(it_Remove,                i18n("Go to state diagram")); break;
198     case mt_Hide_Destruction_Box:       LPMISI(it_Message_Destroy,       i18n("Hide destruction box")); break;
199     case mt_Import_Class:               LPMIBI(it_Import_File,           i18n("Import File(s)...")); break;
200     case mt_Import_Project:             LPMIBI(it_Import_Project,        i18n("Import from Directory...")); break;
201     case mt_Import_from_File:           LPMISI(it_Import_File,           i18n("from file...")); break;
202     case mt_Initial_Activity:           LPMISI(it_InitialState,          i18n("Initial Activity")); break;
203     case mt_Initial_State:              LPMISI(it_InitialState,          i18n("Initial State")); break;
204     case mt_Instance:                   LPMISI(it_Instance,              i18nc("new instance menu item", "Instance...")); break;
205     case mt_InstanceAttribute:          LPMISI(it_Attribute_New,         i18n("New Attribute...")); break;
206     case mt_Interface:                  LPMISI(it_Interface,             i18n("Interface")); break;
207     case mt_InterfaceComponent:         LPMISI(it_Interface_Provider,    i18n("Interface")); break;
208     case mt_InterfaceProvided:          LPMISI(it_Interface_Provider,    i18n("Provided interface")); break;
209     case mt_InterfaceRequired:          LPMISI(it_Interface_Requirement, i18n("Required interface")); break;
210     case mt_Internalize_Folder:         m_actions[m] = menu->addAction(i18n("Internalize Folder")); break;
211     case mt_Junction:                   LPMISI(it_Junction,              i18n("Junction")); break;
212     case mt_Line_Color:                 LPMISI(it_Color_Line,            i18n("Line Color...")); break;
213     case mt_Logical_Folder:             LPMIBI(it_Folder,                i18n("Folder")); break;
214     case mt_MessageAsynchronous:        LPMISI(it_Message_Async,         i18n("Asynchronous Message")); break;
215     case mt_MessageCreation:            LPMISI(it_Message_Creation,      i18n("Creation Message")); break;
216     case mt_MessageDestroy:             LPMISI(it_Message_Destroy,       i18n("Destroy Message")); break;
217     case mt_MessageFound:               LPMISI(it_Message_Found,         i18n("Found Message")); break;
218     case mt_MessageLost:                LPMISI(it_Message_Lost,          i18n("Lost Message")); break;
219     case mt_MessageSynchronous:         LPMISI(it_Message_Sync,          i18n("Synchronous Message")); break;
220     case mt_New_Activity:               LPMISI(it_State_Activity,        i18n("Activity...")); break;
221     case mt_New_Attribute:              LPMISI(it_Attribute_New,         i18n("New Attribute...")); break;
222     case mt_New_EntityAttribute:        LPMISI(it_Entity_Attribute_New,  i18n("New Entity Attribute...")); break;
223     case mt_New_EnumLiteral:            LPMISI(it_Literal_New,           i18n("New Literal...")); break;
224     case mt_New_InstanceAttribute:      LPMISI(it_Attribute_New,         i18n("New Attribute...")); break;
225     case mt_New_Operation:              LPMISI(it_Operation_Public_New,  i18n("New Operation...")); break;
226     case mt_New_Parameter:              LPMISI(it_Parameter_New,         i18n("New Parameter...")); break;
227     case mt_New_Template:               LPMISI(it_Template_New,          i18n("New Template...")); break;
228     case mt_Node:                       LPMISI(it_Node,                  i18n("Node")); break;
229     //case mt_Node:                       LPMISI(it_Node,                  i18n("Node...")); break;
230     case mt_Note:                       LPMISI(it_Note,                  i18n("Note...")); break;
231     case mt_Object:                     LPMISI(it_Object,                i18n("Object...")); break;
232     case mt_Object_Node:                LPMISI(it_Object_Node,           i18n("Object Node")); break;
233     case mt_Open_File:                  LPMISI(it_File_Open,             i18n("Open file")); break;
234     case mt_Operation:                  LPMISI(it_Public_Method,         i18n("Operation")); break;
235     //case mt_Operation:                  LPMISI(it_Public_Method,       i18n("Operation...")); break;
236     case mt_Package:                    LPMISI(it_Package,               i18n("Package...")); break;
237     case mt_Paste:                      LPMISI(it_Paste,                 i18n("Paste")); break;
238     case mt_Pin:                        LPMISI(it_Pin,                   i18n("Pin")); break;
239     case mt_Port:                       LPMISI(it_Port,                  i18n("Port")); break;
240     //case mt_Port:                       LPMISI(it_Port,                  i18n("Port...")); break;
241     case mt_PrePostCondition:           LPMISI(it_Condition_PrePost,     i18n("Pre Post Condition")); break;
242     case mt_PrimaryKeyConstraint:       LPMISI(it_Constraint_PrimaryKey, i18n("Primary Key Constraint...")); break;
243     case mt_Properties:                 LPMISI(it_Properties,            i18n("Properties")); break;
244     case mt_Redo:                       LPMISI(it_Redo,                  i18n("Redo")); break;
245     case mt_Region:                     LPMISI(it_Region,                i18n("Region")); break;
246     case mt_Remove:                     LPMISI(it_Remove,                i18n("Remove")); break;
247     case mt_RemoveStateDiagram:         LPMISI(it_Remove,                i18n("Remove state diagram")); break;
248     case mt_Rename:                     LPMISI(it_Rename,                i18n("Rename...")); break;
249     case mt_Rename_Object:              insert(m, menu, i18n("Rename Object...")); break;
250     case mt_ReturnToCombinedState:      LPMISI(it_Redo,                  i18n("Return to combined state")); break;
251     case mt_ReturnToClass:              LPMISI(it_Redo,                  i18n("Return to class")); break;
252     case mt_Reset_Label_Positions:      m_actions[m] = menu->addAction(i18n("Reset Label Positions")); break;
253     case mt_Resize:                     insert(m, menu, i18n("Resize")); break;
254     case mt_SelectStateDiagram:         LPMISI(it_Remove,                i18n("Select state diagram")); break;
255     case mt_Send_Signal:                LPMISI(it_Send_Signal,           i18n("Send Signal")); break;
256     case mt_ShallowHistory:             LPMISI(it_History_Shallow,       i18n("Shallow History")); break;
257     case mt_Show:                       LPMISI(it_Show,                  i18n("Show")); break;
258     case mt_Show_Destruction_Box:       LPMISI(it_Message_Destroy,       i18n("Show destruction box")); break;
259     case mt_State:                      LPMISI(it_State,                 i18nc("add new state", "State...")); break;
260     case mt_StateFork:                  LPMISI(it_Fork_State,            i18n("Fork")); break;
261     case mt_StateJoin:                  LPMISI(it_Join,                  i18n("Join")); break;
262     case mt_StateTransition:            LPMISI(it_State_Transition,      i18n("State Transition")); break;
263     case mt_State_Diagram:              insertFromActionKey(m, menu, QLatin1String("new_state_diagram")); break;
264     case mt_Subsystem:                  LPMISI(it_Subsystem,             i18n("Subsystem")); break;
265     //case mt_Subsystem:                  LPMISI(it_Subsystem,             i18n("Subsystem...")); break;
266     case mt_Template:                   LPMISI(it_Template_Class,        i18n("Template")); break;
267     //case mt_Template:                   LPMISI(it_Template_New,          i18n("Template...")); break;
268     case mt_Undo:                       LPMISI(it_Undo,                  i18n("Undo")); break;
269     case mt_UniqueConstraint:           LPMISI(it_Constraint_Unique,     i18n("Unique Constraint...")); break;
270     case mt_UseCase:                    LPMISI(it_UseCase,               i18n("Use Case")); break;
271     //case mt_UseCase:                    LPMISI(it_UseCase,               i18n("Use Case...")); break;
272     case mt_UseCase_Diagram:            insertFromActionKey(m, menu, QLatin1String("new_use_case_diagram")); break;
273     case mt_UseCase_Folder:             LPMIBI(it_Folder,                i18n("Folder")); break;
274 
275     default:
276         uWarning() << "called on unimplemented MenuType " << toString(m);
277         break;
278     }
279 #undef LPMISI
280 #undef LPMIBI
281 }
282 
283 /**
284  * Shortcut for the frequently used addAction() calls.
285  *
286  * @param m      The MenuType for which to insert a menu item.
287  * @param icon   The icon for this action.
288  * @param text   The text for this action.
289  */
insert(const MenuType m,const QIcon & icon,const QString & text)290 void ListPopupMenu::insert(const MenuType m, const QIcon & icon, const QString & text)
291 {
292     DEBUG_AddAction(m);
293     m_actions[m] = addAction(icon, text);
294 }
295 
296 /**
297  * Shortcut for the frequently used addAction() calls.
298  *
299  * @param m           The MenuType for which to insert a menu item.
300  * @param text        The text for this action.
301  * @param checkable   Sets the action to checkable.
302  */
insert(const MenuType m,const QString & text,const bool checkable)303 void ListPopupMenu::insert(const MenuType m, const QString & text, const bool checkable)
304 {
305     insert(m, this, text, checkable);
306 }
307 
308 /**
309  * Shortcut for the frequently used addAction() calls.
310  *
311  * @param m      The MenuType for which to insert a menu item.
312  * @param menu   The KMenu for which to insert a menu item.
313  * @param icon   The icon for this action.
314  * @param text   The text for this action.
315  */
insert(const MenuType m,KMenu * menu,const QIcon & icon,const QString & text)316 void ListPopupMenu::insert(const MenuType m, KMenu* menu, const QIcon & icon, const QString & text)
317 {
318     DEBUG_AddAction(m);
319     m_actions[m] = menu->addAction(icon, text);
320 }
321 
322 /**
323  * Shortcut for the frequently used addAction() calls.
324  *
325  * @param m      The MenuType for which to insert a menu item.
326  * @param menu   The KMenu for which to insert a menu item.
327  * @param text   The text for this action.
328  * @param checkable   Sets the action to checkable.
329  */
insert(const MenuType m,KMenu * menu,const QString & text,const bool checkable)330 void ListPopupMenu::insert(const MenuType m, KMenu* menu, const QString & text, const bool checkable)
331 {
332     DEBUG_AddAction(m);
333     m_actions[m] = menu->addAction(text);
334     if (checkable) {
335         QAction* action = getAction(m);
336         if (action)
337             action->setCheckable(checkable);
338     }
339 }
340 
341 /**
342  * Shortcut for inserting standard model items (Class, Interface,
343  * Datatype, Enum, Package) as well as diagram choices.
344  *
345  * @param folders   Set this true if folders shall be included as choices.
346  * @param diagrams  Set this true if diagram types shall be included as choices.
347  * @param packages  Set this true if packages shall be included as choices.
348  */
insertContainerItems(bool folders,bool diagrams,bool packages)349 void ListPopupMenu::insertContainerItems(bool folders, bool diagrams, bool packages)
350 {
351     KMenu* menu = newMenu(i18nc("new container menu", "New"), this);
352     menu->setIcon(Icon_Utils::SmallIcon(Icon_Utils::it_New));
353     insertContainerItems(menu, folders, diagrams, packages);
354     addMenu(menu);
355 }
356 
357 /**
358  * Shortcut for inserting standard model items (Class, Interface,
359  * Datatype, Enum, Package) as well as diagram choices.
360  *
361  * @param menu       Menu to add the menu entries
362  * @param folders    Set this true if folders shall be included as choices.
363  * @param diagrams   Set this true if diagram types shall be included as choices.
364  * @param packages   Set this true if packages shall be included as choices.
365  */
insertContainerItems(KMenu * menu,bool folders,bool diagrams,bool packages)366 void ListPopupMenu::insertContainerItems(KMenu* menu, bool folders, bool diagrams, bool packages)
367 {
368     if (folders)
369         insert(mt_Logical_Folder, menu, Icon_Utils::BarIcon(Icon_Utils::it_Folder), i18n("Folder"));
370     insert(mt_Class, menu);
371     insert(mt_Interface, menu);
372     insert(mt_Datatype, menu);
373     insert(mt_Enum, menu);
374     insert(mt_Instance, menu);
375     if (packages)
376         insert(mt_Package, menu);
377     if (diagrams) {
378         insertFromActionKey(mt_Class_Diagram, menu, QLatin1String("new_class_diagram"));
379         insertFromActionKey(mt_Sequence_Diagram, menu, QLatin1String("new_sequence_diagram"));
380         insertFromActionKey(mt_Collaboration_Diagram, menu, QLatin1String("new_collaboration_diagram"));
381         insertFromActionKey(mt_State_Diagram, menu, QLatin1String("new_state_diagram"));
382         insertFromActionKey(mt_Activity_Diagram, menu, QLatin1String("new_activity_diagram"));
383     }
384 }
385 
386 /**
387  * Inserts a menu item for an association related text
388  * (such as name, role, multiplicity etc.)
389  *
390  * @param label   The menu text.
391  * @param mt      The menu type.
392  */
insertAssociationTextItem(const QString & label,MenuType mt)393 void ListPopupMenu::insertAssociationTextItem(const QString &label, MenuType mt)
394 {
395     insert(mt, label);
396     insert(mt_Change_Font);
397     insert(mt_Reset_Label_Positions);
398     insert(mt_Properties);
399 }
400 
401 /**
402  * Convenience method to extract the ListPopupMenu type from an action.
403  * @param action   the action which was called
404  * @return menu type enum value
405  */
typeFromAction(QAction * action)406 ListPopupMenu::MenuType ListPopupMenu::typeFromAction(QAction *action)
407 {
408     ListPopupMenu *menu = ListPopupMenu::menuFromAction(action);
409     if (menu) {
410         return menu->getMenuType(action);
411     }
412     else {
413         uError() << "Action's data field does not contain ListPopupMenu pointer!";
414         return mt_Undefined;
415     }
416 }
417 
418 /**
419  * Utility: Convert a MenuType value to an ObjectType value.
420  */
convert_MT_OT(MenuType mt)421 UMLObject::ObjectType ListPopupMenu::convert_MT_OT(MenuType mt)
422 {
423     UMLObject::ObjectType type =  UMLObject::ot_UMLObject;
424 
425     switch (mt) {
426     case mt_UseCase:
427         type = UMLObject::ot_UseCase;
428         break;
429     case mt_Actor:
430         type = UMLObject::ot_Actor;
431         break;
432     case mt_Class:
433         type = UMLObject::ot_Class;
434         break;
435     case mt_Datatype:
436         type = UMLObject::ot_Datatype;
437         break;
438     case mt_Attribute:
439         type = UMLObject::ot_Attribute;
440         break;
441     case mt_Interface:
442         type = UMLObject::ot_Interface;
443         break;
444     case mt_Template:
445         type = UMLObject::ot_Template;
446         break;
447     case mt_Enum:
448         type = UMLObject::ot_Enum;
449         break;
450     case mt_EnumLiteral:
451         type = UMLObject::ot_EnumLiteral;
452         break;
453     case mt_EntityAttribute:
454         type = UMLObject::ot_EntityAttribute;
455         break;
456     case mt_Operation:
457         type = UMLObject::ot_Operation;
458         break;
459     case mt_Category:
460         type = UMLObject::ot_Category;
461         break;
462     case mt_InstanceAttribute:
463         type = UMLObject::ot_InstanceAttribute;
464         break;
465     default:
466         break;
467     }
468     return type;
469 }
470 
471 /**
472  * Returns the data from the given action to the given key.
473  */
dataFromAction(DataType key,QAction * action)474 QVariant ListPopupMenu::dataFromAction(DataType key, QAction* action)
475 {
476     QVariant data = action->data();
477     QMap<QString, QVariant> map = data.toMap();
478     return map[ListPopupMenu::toString(key)];
479 }
480 
481 /**
482  * Convenience method to extract the ListPopupMenu pointer stored in QAction
483  * objects belonging to ListPopupMenu.
484  */
menuFromAction(QAction * action)485 ListPopupMenu* ListPopupMenu::menuFromAction(QAction *action)
486 {
487     if (action) {
488         QVariant value = dataFromAction(dt_MenuPointer, action);
489         if (value.canConvert<ListPopupMenu*>()) {
490             return qvariant_cast<ListPopupMenu*>(value);
491         }
492     }
493     return 0;
494 }
495 
496 /**
497  * Create the 'new' menu
498  * @return menu instance
499  */
makeNewMenu()500 KMenu *ListPopupMenu::makeNewMenu()
501 {
502     KMenu *menu = newMenu(i18nc("new sub menu", "New"), this);
503     menu->setIcon(Icon_Utils::SmallIcon(Icon_Utils::it_New));
504     return menu;
505 }
506 
507 /**
508  * Creates a popup menu for a single category Object
509  * @param category The UMLCategory for which the category menu is created
510  */
insertSubMenuCategoryType(UMLCategory * category)511 void ListPopupMenu::insertSubMenuCategoryType(UMLCategory* category)
512 {
513     KMenu* menu = newMenu(i18nc("category type sub menu", "Category Type"), this);
514     insert(mt_DisjointSpecialisation, menu, i18n("Disjoint(Specialisation)"), CHECKABLE);
515     insert(mt_OverlappingSpecialisation, menu, i18n("Overlapping(Specialisation)"), CHECKABLE);
516     insert(mt_Union, menu, i18n("Union"), CHECKABLE);
517     setActionChecked(mt_DisjointSpecialisation, category->getType()==UMLCategory::ct_Disjoint_Specialisation);
518     setActionChecked(mt_OverlappingSpecialisation, category->getType()==UMLCategory::ct_Overlapping_Specialisation);
519     setActionChecked(mt_Union, category->getType()==UMLCategory::ct_Union);
520     addMenu(menu);
521 }
522 
523 /**
524  * Get the action from the menu type as index.
525  */
getAction(MenuType idx)526 QAction* ListPopupMenu::getAction(MenuType idx)
527 {
528     return m_actions.value(idx, 0);
529 }
530 
531 // /**
532 //  * Get the MenuType from the action.
533 //  */
534 // ListPopupMenu::MenuType ListPopupMenu::getMenuType(KAction* action)
535 // {
536 //     return m_actions.key(action);
537 // }
538 
539 /**
540  * Get the MenuType from the action.
541  */
getMenuType(QAction * action)542 ListPopupMenu::MenuType ListPopupMenu::getMenuType(QAction* action)
543 {
544     QList<MenuType> keyList = m_actions.keys(action);
545     if (keyList.empty() || /* all key-value pairs are unique*/ keyList.count() > 1) {
546         return mt_Undefined;
547     } else {
548         // we return the first (only) value
549         return keyList.first();
550     }
551 }
552 
553 /**
554  * Checks the action item.
555  *
556  * @param idx     The MenuType for which to check the menu item.
557  * @param value   The value.
558  */
setActionChecked(MenuType idx,bool value)559 void ListPopupMenu::setActionChecked(MenuType idx, bool value)
560 {
561     QAction* action = getAction(idx);
562     if (action && action->isCheckable()) {
563         action->setChecked(value);
564     }
565     else {
566         DEBUG(DBG_SRC) << "called on unknown MenuType " << toString(idx);
567     }
568 }
569 
570 /**
571  * Enables the action item.
572  *
573  * @param idx     The MenuType for which to enable the menu item.
574  * @param value   The value.
575  */
setActionEnabled(MenuType idx,bool value)576 void ListPopupMenu::setActionEnabled(MenuType idx, bool value)
577 {
578     QAction* action = getAction(idx);
579     if (action) {
580         action->setEnabled(value);
581     }
582     else {
583         DEBUG(DBG_SRC) << "called on unknown MenuType " << toString(idx);
584     }
585 }
586 
587 /**
588  * Sets up actions added to the ListPopupMenu to have their data field set to
589  * pointer to this ListPopupMenu object, so that this menu pointer can be
590  * retrieved in UMLWidget::slotMenuSelection
591  *
592  * @note This might seem like an ugly hack, but this is the only solution which
593  *       helped in avoiding storage of ListPopupMenu pointer in each UMLWidget.
594  */
setupActionsData()595 void ListPopupMenu::setupActionsData()
596 {
597     foreach (QAction *action, m_actions) {
598         QMap<QString, QVariant> map = action->data().toMap();
599         map[toString(dt_MenuPointer)] = qVariantFromValue(this);
600         action->setData(QVariant(map));
601     }
602 
603 }
604 
605 /**
606  * Convert enum MenuType to string.
607  */
toString(MenuType menu)608 QString ListPopupMenu::toString(MenuType menu)
609 {
610     return QLatin1String(ENUM_NAME(ListPopupMenu, MenuType, menu));
611 }
612 
613 /**
614  * Convert enum DataType to string.
615  */
toString(DataType data)616 QString ListPopupMenu::toString(DataType data)
617 {
618     return QLatin1String(ENUM_NAME(ListPopupMenu, DataType, data));
619 }
620 
621 //QList<DebugMenu> &ListPopupMenu::debugActions()
622 //{
623 //    return d->debugActions;
624 //}
625 
626 /**
627  * dump collected actions
628  * @param title optional menu title
629  */
dumpActions(const QString & title)630 void ListPopupMenu::dumpActions(const QString &title)
631 {
632     qDebug().nospace() << title;
633     foreach(DebugMenu e, d->debugActions) {
634         if (!e.menu.isEmpty())
635             qDebug().nospace() << "  " << e.menu;
636         else
637             qDebug().nospace() << "    " << toString(e.m);
638     }
639 }
640