/***************************************************************************
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   copyright (C) 2002-2020                                               *
 *   Umbrello UML Modeller Authors <umbrello-devel@kde.org>                *
 ***************************************************************************/

// own header
#include "listpopupmenu.h"

// app includes
#include "activitywidget.h"
#include "associationline.h"
#include "associationwidget.h"
#include "category.h"
#include "classifier.h"
#include "classifierwidget.h"
#include "combinedfragmentwidget.h"
#include "debug_utils.h"
#include "floatingtextwidget.h"
#include "folder.h"
#include "forkjoinwidget.h"
#include "layoutgenerator.h"
#include "model_utils.h"
#include "objectnodewidget.h"
#include "objectwidget.h"
#include "notewidget.h"
#include "pinportbase.h"
#include "preconditionwidget.h"
#include "signalwidget.h"
#include "statewidget.h"
#include "uml.h"
#include "umldoc.h"
#include "umlscene.h"
#include "umlview.h"
#include "umllistview.h"
#include "umllistviewitem.h"
#include "widget_utils.h"
#include "widgetbase.h"

// kde includes
#include <KLocalizedString>
#include <kactioncollection.h>

DEBUG_REGISTER_DISABLED(ListPopupMenu)

static const bool CHECKABLE = true;

// uncomment to see not handled switch cases
//#define CHECK_SWITCH

class DebugMenu {
public:
    DebugMenu(ListPopupMenu::MenuType _m) : m(_m) {}
    DebugMenu(const QString & _m) : menu(_m) {}
    ListPopupMenu::MenuType m{ListPopupMenu::mt_Undefined};
    QString menu;
};

class ListPopupMenuPrivate {
public:
    QList<DebugMenu> debugActions;
    ~ListPopupMenuPrivate()
    {
        debugActions.clear();
    }
};

#define DEBUG_AddAction(m) d->debugActions.append(DebugMenu(m))
#define DEBUG_StartMenu(m) d->debugActions.append(DebugMenu(m->title() + QLatin1String(" - start")))
#define DEBUG_EndMenu(m) d->debugActions.append(DebugMenu(m->title() + QLatin1String(" - end")))

/**
 * Constructs the popup menu
 *
 * @param parent   The parent to ListPopupMenu.
 */
ListPopupMenu::ListPopupMenu(QWidget *parent)
  : KMenu(parent),
    d(new ListPopupMenuPrivate)
{
}

/**
 * Standard destructor.
 */
ListPopupMenu::~ListPopupMenu()
{
    foreach (QAction* action, m_actions) {
        delete action;
    }
    m_actions.clear();
    delete d;
}

KMenu *ListPopupMenu::newMenu(const QString &title, QWidget *widget)
{
    KMenu *menu = new KMenu(title, widget);
    DEBUG_StartMenu(menu);
    return menu;
}

void ListPopupMenu::addMenu(KMenu *menu)
{
    KMenu::addMenu(menu);
    DEBUG_EndMenu(menu);
}

/**
 * Shortcut for the frequently used addAction() calls.
 *
 * @param m   The MenuType for which to insert a menu item.
 */
void ListPopupMenu::insert(MenuType m)
{
    insert(m, this);
}

/**
 * Shortcut for the frequently used addAction() calls.
 *
 * @param m      The MenuType for which to insert a menu item.
 * @param menu   The KMenu for which to insert a menu item.
 * @param s      The entry to be inserted from the action collection
 */
void ListPopupMenu::insertFromActionKey(const MenuType m, KMenu *menu, const QString &s)
{
    QAction* action = UMLApp::app()->actionCollection()->action(s);
    insert(m, menu, action->icon(), action->text());
}

/**
 * Shortcut for the frequently used addAction() calls.
 *
 * @param m      The MenuType for which to insert a menu item.
 * @param menu   The KMenu for which to insert a menu item.
 */
void ListPopupMenu::insert(const MenuType m, KMenu* menu)
{
    DEBUG_AddAction(m);
    Q_ASSERT(menu != 0);
    switch (m) {
    case mt_Accept_Signal: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Accept_Signal), i18n("Accept Signal")); break;
    case mt_Accept_Time_Event: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Accept_TimeEvent), i18n("Accept Time Event")); break;
    case mt_Activity: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_UseCase), i18n("Activity...")); break;
    case mt_Activity_Transition: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Activity_Transition), i18n("Activity Transition")); break;
    case mt_Actor: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Actor), i18n("Actor")); break;
    //case mt_Actor: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Actor), i18n("Actor...")); break;
    case mt_Artifact: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Artifact), i18n("Artifact")); break;
    //case mt_Artifact: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Artifact), i18n("Artifact...")); break;
    case mt_Attribute: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Public_Attribute), i18n("Attribute")); break;
    //case mt_Attribute: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Public_Attribute), i18n("Attribute...")); break;
    case mt_Branch: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Branch), i18n("Branch/Merge")); break;
    case mt_Category: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Category), i18n("Category")); break;
    //case mt_Category: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Category), i18n("Category...")); break;
    case mt_Change_Font: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Change_Font), i18n("Change Font...")); break;
    case mt_CheckConstraint: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Constraint_Check), i18n("Check Constraint...")); break;
    case mt_Choice: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Choice_Rhomb), i18n("Choice")); break;
    case mt_Class: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Class), i18nc("new class menu item", "Class...")); break;
    case mt_Clone: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Duplicate), i18nc("duplicate action", "Duplicate")); break;
    case mt_Collapse_All: m_actions[m] = menu->addAction(i18n("Collapse All")); break;
    case mt_CombinedState: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_State), i18nc("add new combined state", "Combined state...")); break;
    case mt_Component: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Component), i18n("Component")); break;
    //case mt_Component: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Component), i18n("Component...")); break;
    case mt_Component_Diagram: insertFromActionKey(m, menu, QLatin1String("new_component_diagram")); break;
    case mt_Component_Folder: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Folder), i18n("Folder")); break;
    case mt_Copy: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Copy), i18n("Copy")); break;
    case mt_Cut: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Cut), i18n("Cut")); break;
    case mt_Datatype: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Datatype), i18n("Datatype...")); break;
    case mt_DeepHistory: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_History_Deep), i18n("Deep History")); break;
    case mt_Delete: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Delete), i18n("Delete")); break;
    case mt_Deployment_Diagram: insertFromActionKey(m, menu, QLatin1String("new_deployment_diagram")); break;
    case mt_Deployment_Folder: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Folder), i18n("Folder")); break;
    case mt_EditCombinedState: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_State), i18n("Edit combined state")); break;
    case mt_End_Activity: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_EndState), i18n("End Activity")); break;
    case mt_End_State: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_EndState), i18n("End State")); break;
    case mt_Entity: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Entity), i18n("Entity")); break;
    //case mt_Entity: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Entity), i18n("Entity...")); break;
    case mt_EntityAttribute: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Entity_Attribute), i18n("Entity Attribute...")); break;
    case mt_EntityRelationship_Diagram: insertFromActionKey(m, menu, QLatin1String("new_entityrelationship_diagram")); break;
    case mt_EntityRelationship_Folder: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Folder), i18n("Folder")); break;
    case mt_Enum: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Enum), i18n("Enum...")); break;
    case mt_EnumLiteral: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Enum_Literal), i18n("Enum Literal...")); break;
    case mt_Exception: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Exception), i18n("Exception")); break;
    case mt_Expand_All: m_actions[m] = menu->addAction(i18n("Expand All")); break;
    case mt_Export_Image: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Export_Picture), i18n("Export as Picture...")); break;
    case mt_Externalize_Folder: m_actions[m] = menu->addAction(i18n("Externalize Folder...")); break;
    case mt_Fill_Color: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Color_Fill), i18n("Fill Color...")); break;
    case mt_Final_Activity: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Activity_Final), i18n("Final Activity")); break;
    case mt_FlipHorizontal: m_actions[m] = menu->addAction(i18n("Flip Horizontal")); break;
    case mt_FlipVertical: m_actions[m] = menu->addAction(i18n("Flip Vertical")); break;
    case mt_FloatText: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Text), i18n("Text Line...")); break;
    case mt_ForeignKeyConstraint: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Constraint_ForeignKey), i18n("Foreign Key Constraint...")); break;
    case mt_Fork: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Fork_Join), i18n("Fork")); break;
    case mt_GoToStateDiagram: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Remove), i18n("Go to state diagram")); break;
    case mt_Hide_Destruction_Box: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Destroy), i18n("Hide destruction box")); break;
    case mt_Import_Class: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Import_File), i18n("Import File(s)...")); break;
    case mt_Import_Project: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Import_Project), i18n("Import from Directory...")); break;
    case mt_Import_from_File: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Import_File), i18n("from file...")); break;
    case mt_Initial_Activity: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_InitialState), i18n("Initial Activity")); break;
    case mt_Initial_State: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_InitialState), i18n("Initial State")); break;
    case mt_Instance: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Instance), i18nc("new instance menu item", "Instance...")); break;
    case mt_InstanceAttribute: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Attribute_New), i18n("New Attribute...")); break;
    case mt_Interface: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Interface), i18n("Interface")); break;
    case mt_InterfaceComponent: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Interface_Provider), i18n("Interface")); break;
    case mt_InterfaceProvided: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Interface_Provider), i18n("Provided interface")); break;
    case mt_InterfaceRequired: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Interface_Requirement), i18n("Required interface")); break;
    case mt_Internalize_Folder: m_actions[m] = menu->addAction(i18n("Internalize Folder")); break;
    case mt_Junction: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Junction), i18n("Junction")); break;
    case mt_Line_Color: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Color_Line), i18n("Line Color...")); break;
    case mt_Logical_Folder: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Folder), i18n("Folder")); break;
    case mt_MessageAsynchronous: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Async), i18n("Asynchronous Message")); break;
    case mt_MessageCreation: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Creation), i18n("Creation Message")); break;
    case mt_MessageDestroy: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Destroy), i18n("Destroy Message")); break;
    case mt_MessageFound: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Found), i18n("Found Message")); break;
    case mt_MessageLost: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Lost), i18n("Lost Message")); break;
    case mt_MessageSynchronous: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Sync), i18n("Synchronous Message")); break;
    case mt_New_Activity: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_State_Activity), i18n("Activity...")); break;
    case mt_New_Attribute: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Attribute_New), i18n("New Attribute...")); break;
    case mt_New_EntityAttribute: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Entity_Attribute_New), i18n("New Entity Attribute...")); break;
    case mt_New_EnumLiteral: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Literal_New), i18n("New Literal...")); break;
    case mt_New_InstanceAttribute: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Attribute_New), i18n("New Attribute...")); break;
    case mt_New_Operation: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Operation_Public_New), i18n("New Operation...")); break;
    case mt_New_Parameter: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Parameter_New), i18n("New Parameter...")); break;
    case mt_New_Template: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Template_New), i18n("New Template...")); break;
    case mt_Node: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Node), i18n("Node")); break;
    //case mt_Node: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Node), i18n("Node...")); break;
    case mt_Note: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Note), i18n("Note...")); break;
    //case mt_Note: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Note), i18n("Note...")); break;
    case mt_Object: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Object), i18n("Object...")); break;
    case mt_Object_Node: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Object_Node), i18n("Object Node")); break;
    case mt_Open_File: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_File_Open), i18n("Open file")); break;
    case mt_Operation: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Public_Method), i18n("Operation")); break;
    //case mt_Operation: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Public_Method), i18n("Operation...")); break;
    case mt_Package: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Package), i18n("Package...")); break;
    case mt_Paste: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Paste), i18n("Paste")); break;
    case mt_Pin: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Pin), i18n("Pin")); break;
    case mt_Port: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Port), i18n("Port")); break;
    //case mt_Port: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Port), i18n("Port...")); break;
    case mt_PrePostCondition: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Condition_PrePost), i18n("Pre Post Condition")); break;
    case mt_PrimaryKeyConstraint: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Constraint_PrimaryKey), i18n("Primary Key Constraint...")); break;
    case mt_Properties: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Properties), i18n("Properties")); break;
    case mt_Redo: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Redo), i18n("Redo")); break;
    case mt_Region: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Region), i18n("Region")); break;
    case mt_Remove: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Remove), i18n("Remove")); break;
    case mt_RemoveStateDiagram: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Remove), i18n("Remove state diagram")); break;
    case mt_Rename: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Rename), i18n("Rename...")); break;
    case mt_Rename_Object: insert(m, menu, i18n("Rename Object...")); break;
    case mt_ReturnToCombinedState: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Redo), i18n("Return to combined state")); break;
    case mt_ReturnToClass: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Redo), i18n("Return to class")); break;
    case mt_Reset_Label_Positions: m_actions[m] = menu->addAction(i18n("Reset Label Positions")); break;
    case mt_Resize: insert(m, menu, i18n("Resize")); break;
    case mt_SelectStateDiagram: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Remove), i18n("Select state diagram")); break;
    case mt_Send_Signal: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Send_Signal), i18n("Send Signal")); break;
    case mt_ShallowHistory: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_History_Shallow), i18n("Shallow History")); break;
    case mt_Show: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Show), i18n("Show")); break;
    case mt_Show_Destruction_Box: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Message_Destroy), i18n("Show destruction box")); break;
    case mt_State: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_State), i18nc("add new state", "State...")); break;
    case mt_StateFork: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Fork_State), i18n("Fork")); break;
    case mt_StateJoin: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Join), i18n("Join")); break;
    case mt_StateTransition: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_State_Transition), i18n("State Transition")); break;
    case mt_State_Diagram: insertFromActionKey(m, menu, QLatin1String("new_state_diagram")); break;
    case mt_Subsystem: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Subsystem), i18n("Subsystem")); break;
    //case mt_Subsystem: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Subsystem), i18n("Subsystem...")); break;
    case mt_Template: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Template_Class), i18n("Template")); break;
    //case mt_Template: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Template_New), i18n("Template...")); break;
    case mt_Undo: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Undo), i18n("Undo")); break;
    case mt_UniqueConstraint: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Constraint_Unique), i18n("Unique Constraint...")); break;
    case mt_UseCase: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_UseCase), i18n("Use Case")); break;
    //case mt_UseCase: m_actions[m] = menu->addAction(Icon_Utils::SmallIcon(Icon_Utils::it_UseCase), i18n("Use Case...")); break;
    case mt_UseCase_Diagram: insertFromActionKey(m, menu, QLatin1String("new_use_case_diagram")); break;
    case mt_UseCase_Folder: m_actions[m] = menu->addAction(Icon_Utils::BarIcon(Icon_Utils::it_Folder), i18n("Folder")); break;

    default:
        uWarning() << "called on unimplemented MenuType " << toString(m);
        break;
    }
}

/**
 * Shortcut for the frequently used addAction() calls.
 *
 * @param m      The MenuType for which to insert a menu item.
 * @param icon   The icon for this action.
 * @param text   The text for this action.
 */
void ListPopupMenu::insert(const MenuType m, const QIcon & icon, const QString & text)
{
    DEBUG_AddAction(m);
    m_actions[m] = addAction(icon, text);
}

/**
 * Shortcut for the frequently used addAction() calls.
 *
 * @param m           The MenuType for which to insert a menu item.
 * @param text        The text for this action.
 * @param checkable   Sets the action to checkable.
 */
void ListPopupMenu::insert(const MenuType m, const QString & text, const bool checkable)
{
    insert(m, this, text, checkable);
}

/**
 * Shortcut for the frequently used addAction() calls.
 *
 * @param m      The MenuType for which to insert a menu item.
 * @param menu   The KMenu for which to insert a menu item.
 * @param icon   The icon for this action.
 * @param text   The text for this action.
 */
void ListPopupMenu::insert(const MenuType m, KMenu* menu, const QIcon & icon, const QString & text)
{
    DEBUG_AddAction(m);
    m_actions[m] = menu->addAction(icon, text);
}

/**
 * Shortcut for the frequently used addAction() calls.
 *
 * @param m      The MenuType for which to insert a menu item.
 * @param menu   The KMenu for which to insert a menu item.
 * @param text   The text for this action.
 * @param checkable   Sets the action to checkable.
 */
void ListPopupMenu::insert(const MenuType m, KMenu* menu, const QString & text, const bool checkable)
{
    DEBUG_AddAction(m);
    m_actions[m] = menu->addAction(text);
    if (checkable) {
        QAction* action = getAction(m);
        if (action)
            action->setCheckable(checkable);
    }
}

/**
 * Shortcut for inserting standard model items (Class, Interface,
 * Datatype, Enum, Package) as well as diagram choices.
 *
 * @param folderAndDiagrams Set this true if folders and diagram
 *                          types shall be included as choices.
 * @param packages          Set this true if packages
 *                          shall be included as choices.
 */
void ListPopupMenu::insertContainerItems(bool folderAndDiagrams, bool packages)
{
    KMenu* menu = newMenu(i18nc("new container menu", "New"), this);
    menu->setIcon(Icon_Utils::SmallIcon(Icon_Utils::it_New));
    insertContainerItems(menu, folderAndDiagrams, packages);
    addMenu(menu);
}

/**
 * Shortcut for inserting standard model items (Class, Interface,
 * Datatype, Enum, Package) as well as diagram choices.
 *
 * @param menu              Menu to add the menu entries
 * @param folderAndDiagrams Set this true if folders and diagram
 *                          types shall be included as choices.
 * @param packages          Set this true if packages
 *                          shall be included as choices.
 */
void ListPopupMenu::insertContainerItems(KMenu* menu, bool folderAndDiagrams, bool packages)
{
    if (folderAndDiagrams)
        insert(mt_Logical_Folder, menu, Icon_Utils::BarIcon(Icon_Utils::it_Folder), i18n("Folder"));
    insert(mt_Class, menu);
    insert(mt_Interface, menu);
    insert(mt_Datatype, menu);
    insert(mt_Enum, menu);
    if (packages)
        insert(mt_Package, menu);
    if (folderAndDiagrams) {
        insertFromActionKey(mt_Class_Diagram, menu, QLatin1String("new_class_diagram"));
        insertFromActionKey(mt_Sequence_Diagram, menu, QLatin1String("new_sequence_diagram"));
        insertFromActionKey(mt_Collaboration_Diagram, menu, QLatin1String("new_collaboration_diagram"));
        insertFromActionKey(mt_State_Diagram, menu, QLatin1String("new_state_diagram"));
        insertFromActionKey(mt_Activity_Diagram, menu, QLatin1String("new_activity_diagram"));
    }
}

/**
 * Inserts a menu item for an association related text
 * (such as name, role, multiplicity etc.)
 *
 * @param label   The menu text.
 * @param mt      The menu type.
 */
void ListPopupMenu::insertAssociationTextItem(const QString &label, MenuType mt)
{
    insert(mt, label);
    insert(mt_Change_Font);
    insert(mt_Reset_Label_Positions);
    insert(mt_Properties);
}

/**
 * Convenience method to extract the ListPopupMenu type from an action.
 * @param action   the action which was called
 * @return menu type enum value
 */
ListPopupMenu::MenuType ListPopupMenu::typeFromAction(QAction *action)
{
    ListPopupMenu *menu = ListPopupMenu::menuFromAction(action);
    if (menu) {
        return menu->getMenuType(action);
    }
    else {
        uError() << "Action's data field does not contain ListPopupMenu pointer!";
        return mt_Undefined;
    }
}

/**
 * Utility: Convert a MenuType value to an ObjectType value.
 */
UMLObject::ObjectType ListPopupMenu::convert_MT_OT(MenuType mt)
{
    UMLObject::ObjectType type =  UMLObject::ot_UMLObject;

    switch (mt) {
    case mt_UseCase:
        type = UMLObject::ot_UseCase;
        break;
    case mt_Actor:
        type = UMLObject::ot_Actor;
        break;
    case mt_Class:
        type = UMLObject::ot_Class;
        break;
    case mt_Datatype:
        type = UMLObject::ot_Datatype;
        break;
    case mt_Attribute:
        type = UMLObject::ot_Attribute;
        break;
    case mt_Interface:
        type = UMLObject::ot_Interface;
        break;
    case mt_Template:
        type = UMLObject::ot_Template;
        break;
    case mt_Enum:
        type = UMLObject::ot_Enum;
        break;
    case mt_EnumLiteral:
        type = UMLObject::ot_EnumLiteral;
        break;
    case mt_EntityAttribute:
        type = UMLObject::ot_EntityAttribute;
        break;
    case mt_Operation:
        type = UMLObject::ot_Operation;
        break;
    case mt_Category:
        type = UMLObject::ot_Category;
        break;
    case mt_InstanceAttribute:
        type = UMLObject::ot_InstanceAttribute;
        break;
    default:
        break;
    }
    return type;
}

/**
 * Returns the data from the given action to the given key.
 */
QVariant ListPopupMenu::dataFromAction(DataType key, QAction* action)
{
    QVariant data = action->data();
    QMap<QString, QVariant> map = data.toMap();
    return map[ListPopupMenu::toString(key)];
}

/**
 * Convenience method to extract the ListPopupMenu pointer stored in QAction
 * objects belonging to ListPopupMenu.
 */
ListPopupMenu* ListPopupMenu::menuFromAction(QAction *action)
{
    if (action) {
        QVariant value = dataFromAction(dt_MenuPointer, action);
        if (value.canConvert<ListPopupMenu*>()) {
            return qvariant_cast<ListPopupMenu*>(value);
        }
    }
    return 0;
}

/**
 * Create the 'new' menu
 * @return menu instance
 */
KMenu *ListPopupMenu::makeNewMenu()
{
    KMenu *menu = newMenu(i18nc("new sub menu", "New"), this);
    menu->setIcon(Icon_Utils::SmallIcon(Icon_Utils::it_New));
    return menu;
}

/**
 * Creates a popup menu for a single category Object
 * @param category The UMLCategory for which the category menu is created
 */
void ListPopupMenu::insertSubMenuCategoryType(UMLCategory* category)
{
    KMenu* menu = newMenu(i18nc("category type sub menu", "Category Type"), this);
    insert(mt_DisjointSpecialisation, menu, i18n("Disjoint(Specialisation)"), CHECKABLE);
    insert(mt_OverlappingSpecialisation, menu, i18n("Overlapping(Specialisation)"), CHECKABLE);
    insert(mt_Union, menu, i18n("Union"), CHECKABLE);
    setActionChecked(mt_DisjointSpecialisation, category->getType()==UMLCategory::ct_Disjoint_Specialisation);
    setActionChecked(mt_OverlappingSpecialisation, category->getType()==UMLCategory::ct_Overlapping_Specialisation);
    setActionChecked(mt_Union, category->getType()==UMLCategory::ct_Union);
    addMenu(menu);
}

/**
 * Get the action from the menu type as index.
 */
QAction* ListPopupMenu::getAction(MenuType idx)
{
    return m_actions.value(idx, 0);
}

// /**
//  * Get the MenuType from the action.
//  */
// ListPopupMenu::MenuType ListPopupMenu::getMenuType(KAction* action)
// {
//     return m_actions.key(action);
// }

/**
 * Get the MenuType from the action.
 */
ListPopupMenu::MenuType ListPopupMenu::getMenuType(QAction* action)
{
    QList<MenuType> keyList = m_actions.keys(action);
    if (keyList.empty() || /* all key-value pairs are unique*/ keyList.count() > 1) {
        return mt_Undefined;
    } else {
        // we return the first (only) value
        return keyList.first();
    }
}

/**
 * Checks the action item.
 *
 * @param idx     The MenuType for which to check the menu item.
 * @param value   The value.
 */
void ListPopupMenu::setActionChecked(MenuType idx, bool value)
{
    QAction* action = getAction(idx);
    if (action && action->isCheckable()) {
        action->setChecked(value);
    }
    else {
        DEBUG(DBG_SRC) << "called on unknown MenuType " << toString(idx);
    }
}

/**
 * Enables the action item.
 *
 * @param idx     The MenuType for which to enable the menu item.
 * @param value   The value.
 */
void ListPopupMenu::setActionEnabled(MenuType idx, bool value)
{
    QAction* action = getAction(idx);
    if (action) {
        action->setEnabled(value);
    }
    else {
        DEBUG(DBG_SRC) << "called on unknown MenuType " << toString(idx);
    }
}

/**
 * Sets up actions added to the ListPopupMenu to have their data field set to
 * pointer to this ListPopupMenu object, so that this menu pointer can be
 * retrieved in UMLWidget::slotMenuSelection
 *
 * @note This might seem like an ugly hack, but this is the only solution which
 *       helped in avoiding storage of ListPopupMenu pointer in each UMLWidget.
 */
void ListPopupMenu::setupActionsData()
{
    foreach (QAction *action, m_actions) {
        QMap<QString, QVariant> map = action->data().toMap();
        map[toString(dt_MenuPointer)] = qVariantFromValue(this);
        action->setData(QVariant(map));
    }

}

/**
 * Convert enum MenuType to string.
 */
QString ListPopupMenu::toString(MenuType menu)
{
    return QLatin1String(ENUM_NAME(ListPopupMenu, MenuType, menu));
}

/**
 * Convert enum DataType to string.
 */
QString ListPopupMenu::toString(DataType data)
{
    return QLatin1String(ENUM_NAME(ListPopupMenu, DataType, data));
}

//QList<DebugMenu> &ListPopupMenu::debugActions()
//{
//    return d->debugActions;
//}

/**
 * dump collected actions
 * @param title optional menu title
 */
void ListPopupMenu::dumpActions(const QString &title)
{
    qDebug().nospace() << title;
    foreach(DebugMenu e, d->debugActions) {
        if (!e.menu.isEmpty())
            qDebug().nospace() << "  " << e.menu;
        else
            qDebug().nospace() << "    " << toString(e.m);
    }
}
