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