/* * TextMenu.hpp * * Created on: Nov 5, 2010 * Author: heber */ #ifndef TEXTMENU_HPP_ #define TEXTMENU_HPP_ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include #include #include "CodePatterns/MemDebug.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Verbose.hpp" #include "Menu/Menu.hpp" #include "Menu/MenuInterface.hpp" #include "Actions/Action.hpp" #include "Actions/ActionQueue.hpp" #include "Actions/ActionTrait.hpp" #include "Menu/getLastPosition.hpp" #include "Menu/TextMenu/TxMenuLeaveAction.hpp" #include "Menu/TextMenu/ActionMenuItem.hpp" #include "Menu/TextMenu/SeparatorMenuItem.hpp" #include "Menu/TextMenu/SubMenuItem.hpp" /** TextMenu is a specialization of MenuInterface to access TxMenu-like menus. * * Basically, this class is to be used in the MainWindow class of the TextUI. * There, we simply instantiate the class and call init() in order to add all * MenuItem's from MenuDescriptions and Action's ActionRegistry. * * \sa QtMenu. */ template class TextMenu : virtual public MenuInterface, public Menu { public: /** Constructor for class TextMenu. * Initializes outputter and token and takes note whether to delete the * MenuInstance or not. */ TextMenu(std::ostream &_outputter, const std::string &_token) : MenuInterface(_token), Menu(_token), MenuInstance(new T(_outputter, _token)), outputter(_outputter), deleteMenu(true), lastposition(MoleCuilder::ActionQueue::getInstance().getListOfActions()) {} explicit TextMenu(T *_MenuInstance) : Menu(_MenuInstance->getTitle()), MenuInstance(_MenuInstance), outputter(_MenuInstance->getOutputter()), deleteMenu(false), lastposition(MoleCuilder::ActionQueue::getInstance().getListOfActions()) {} /** Destructor of MenuInstance. * */ virtual ~TextMenu() { ShortcutMap.clear(); if (deleteMenu) delete MenuInstance; for (typename SubmenuList::iterator iter = Submenus.begin(); !Submenus.empty(); iter = Submenus.begin()) { delete(*iter); Submenus.erase(iter); } } /** Display this MenuInstance. * */ void display() { MenuInstance->display(); } /** Returns a pointer to the contained/wrapped MenuInstance. * \return pointer to template class pointer */ T * const getMenuInstance() { return MenuInstance; } /** Reserves a specific trigger key such that it is not used during init(). * \param trigger trigger key * \param &name token given for reference. */ void reserveShortcut(char trigger, const std::string &name) { ShortcutMap.insert( std::pair < char, std::string> (trigger, name) ); } protected: // We need to have a reference of the Menu, as Qt returns reference to added menu as well T *MenuInstance; std::ostream &outputter; private: bool deleteMenu; //!> internal functor to get last used position in menu of actions getLastPosition lastposition; typedef std::map MenuShortcutMap; MenuShortcutMap ShortcutMap; typedef std::list< TextMenu *> SubmenuList; SubmenuList Submenus; /** Adds an ActionItem by simply creating a new one. * \param &token token of Action (token in ActionRegistry) * \param &description descriptive text to be shown */ virtual void addActionItem(const std::string &token, const std::string &description) { new ActionMenuItem(getSuitableShortForm(description), description, MenuInstance, token); } /** Adds a (dead) separator item. * */ virtual void addSeparatorItem() { new SeparatorMenuItem(MenuInstance); } /** Adds a Menu to this current Menu. * We also create here a leave action for this submenu to be able to return * to the current one again * \param &token token of the menu * \param &description descriptive text */ virtual void addSubmenuItem(const std::string &token, const std::string &description) { TextMenu *NewMenu = new TextMenu(outputter, token); Submenus.push_back(NewMenu); new SubMenuItem(getSuitableShortForm(description), description, MenuInstance, NewMenu->getMenuInstance()); NewMenu->reserveShortcut('q',"leave"+token); MoleCuilder::ActionTrait leaveTrait( MoleCuilder::OptionTrait("leave"+token, &typeid(void), "leave menu "+token), token, lastposition(token)+2); // have a separator in between MoleCuilder::Action *_action = new TxMenu::LeaveAction(NewMenu->getMenuInstance(), leaveTrait); MoleCuilder::ActionQueue::getInstance().registerAction(_action); NewMenu->init(); new ActionMenuItem('q',"leave"+token,NewMenu->getMenuInstance(),"leave"+token); } /** Return the next available trigger key suitable to this name. * This function is used internally to make sure that each key is unique to * each Action/Menu. The chosen trigger key is also stored in an internal ShortcutMap. * \param &name text shown in menu * \return trigger key */ char getSuitableShortForm(const std::string &name) { for (std::string::const_iterator CharRunner = name.begin(); CharRunner != name.end(); ++CharRunner) { if (ShortcutMap.find(*CharRunner) == ShortcutMap.end()) { ShortcutMap.insert( std::pair < char, std::string> (*CharRunner, name) ); return *CharRunner; } } // if no letter matches, take digits int i=0; for (;i<10;++i) { if (ShortcutMap.find((char)i + '0') == ShortcutMap.end()) break; } if (i != 10) { ShortcutMap.insert( std::pair < char, std::string > ((char)i + '0', name)); return ((char)i + '0'); } else { ELOG(1, "Could not find a suitable shortform for " << name << "."); return '#'; } } }; #endif /* TEXTMENU_HPP_ */