MenuManager.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QApplication>
00027 # include <QMenu>
00028 # include <QMenuBar>
00029 #endif
00030 
00031 #include "MenuManager.h"
00032 #include "Application.h"
00033 #include "MainWindow.h"
00034 #include "Command.h"
00035 
00036 using namespace Gui;
00037 
00038 
00039 MenuItem::MenuItem()
00040 {
00041 }
00042 
00043 MenuItem::MenuItem(MenuItem* item)
00044 {
00045     if (item)
00046         item->appendItem(this);
00047 }
00048 
00049 MenuItem::~MenuItem()
00050 {
00051     clear();
00052 }
00053 
00054 void MenuItem::setCommand(const std::string& name)
00055 {
00056     _name = name;
00057 }
00058 
00059 std::string MenuItem::command() const
00060 {
00061     return _name;
00062 }
00063 
00064 bool MenuItem::hasItems() const
00065 {
00066     return _items.count() > 0;
00067 }
00068 
00069 MenuItem* MenuItem::findItem(const std::string& name)
00070 {
00071     if (_name == name)
00072     {
00073         return this;
00074     }
00075     else
00076     {
00077         for (QList<MenuItem*>::Iterator it = _items.begin(); it != _items.end(); ++it)
00078         {
00079             if ((*it)->_name == name)
00080                 return *it;
00081         }
00082     }
00083 
00084     return 0;
00085 }
00086 
00087 MenuItem* MenuItem::copy() const
00088 {
00089     MenuItem* root = new MenuItem;
00090     root->setCommand(command());
00091 
00092     QList<MenuItem*> items = getItems();
00093     for (QList<MenuItem*>::ConstIterator it = items.begin(); it != items.end(); ++it)
00094     {
00095         root->appendItem((*it)->copy());
00096     }
00097 
00098     return root;
00099 }
00100 
00101 uint MenuItem::count() const
00102 {
00103     return _items.count();
00104 }
00105 
00106 void MenuItem::appendItem(MenuItem* item)
00107 {
00108     _items.push_back(item);
00109 }
00110 
00111 bool MenuItem::insertItem(MenuItem* before, MenuItem* item)
00112 {
00113     int pos = _items.indexOf(before);
00114     if (pos != -1)
00115     {
00116         _items.insert(pos, item);
00117         return true;
00118     }
00119     else
00120         return false;
00121 }
00122 
00123 void MenuItem::removeItem(MenuItem* item)
00124 {
00125     int pos = _items.indexOf(item);
00126     if (pos != -1)
00127         _items.removeAt(pos);
00128 }
00129 
00130 void MenuItem::clear()
00131 {
00132     for (QList<MenuItem*>::Iterator it = _items.begin(); it != _items.end(); ++it)
00133         delete *it;
00134     _items.clear();
00135 }
00136 
00137 MenuItem& MenuItem::operator << (const std::string& command)
00138 {
00139     MenuItem* item = new MenuItem(this);
00140     item->setCommand(command);
00141     return *this;
00142 }
00143 
00144 MenuItem& MenuItem::operator << (MenuItem* item)
00145 {
00146     appendItem(item);
00147     return *this;
00148 }
00149 
00150 QList<MenuItem*> MenuItem::getItems() const
00151 {
00152     return _items;
00153 }
00154 
00155 // -----------------------------------------------------------
00156 
00157 MenuManager* MenuManager::_instance=0;
00158 
00159 MenuManager* MenuManager::getInstance()
00160 {
00161     if ( !_instance )
00162         _instance = new MenuManager;
00163     return _instance;
00164 }
00165 
00166 void MenuManager::destruct()
00167 {
00168     delete _instance;
00169     _instance = 0;
00170 }
00171 
00172 MenuManager::MenuManager()
00173 {
00174 }
00175 
00176 MenuManager::~MenuManager()
00177 {
00178 }
00179 
00180 void MenuManager::setup(MenuItem* menuItems) const
00181 {
00182     if (!menuItems)
00183         return; // empty menu bar
00184 
00185     QMenuBar* menuBar = getMainWindow()->menuBar();
00186     //menuBar->setUpdatesEnabled(false);
00187 
00188     QList<MenuItem*> items = menuItems->getItems();
00189     QList<QAction*> actions = menuBar->actions();
00190     for (QList<MenuItem*>::ConstIterator it = items.begin(); it != items.end(); ++it)
00191     {
00192         // search for the menu action
00193         QAction* action = findAction(actions, QString::fromAscii((*it)->command().c_str()));
00194         if (!action) {
00195             // There must be not more than one separator in the menu bar, so
00196             // we can safely remove it if available and append it at the end
00197             if ((*it)->command() == "Separator") {
00198                 action = menuBar->addSeparator();
00199                 action->setObjectName(QLatin1String("Separator"));
00200             }
00201             else {
00202                 // create a new menu
00203                 std::string menuName = (*it)->command();
00204                 QMenu* menu = menuBar->addMenu(
00205                     QApplication::translate("Workbench", menuName.c_str(),
00206                                             0, QApplication::UnicodeUTF8));
00207                 action = menu->menuAction();
00208                 menu->setObjectName(QString::fromAscii(menuName.c_str()));
00209                 action->setObjectName(QString::fromAscii(menuName.c_str()));
00210             }
00211 
00212             // set the menu user data
00213             action->setData(QString::fromAscii((*it)->command().c_str()));
00214         }
00215         else {
00216             // put the menu at the end
00217             menuBar->removeAction(action);
00218             menuBar->addAction(action);
00219             action->setVisible(true);
00220             int index = actions.indexOf(action);
00221             actions.removeAt(index);
00222         }
00223 
00224         // flll up the menu
00225         if (!action->isSeparator())
00226             setup(*it, action->menu());
00227     }
00228 
00229     // hide all menus which we don't need for the moment
00230     for (QList<QAction*>::Iterator it = actions.begin(); it != actions.end(); ++it) {
00231         (*it)->setVisible(false);
00232     }
00233 
00234     // enable update again
00235     //menuBar->setUpdatesEnabled(true);
00236 }
00237 
00238 void MenuManager::setup(MenuItem* item, QMenu* menu) const
00239 {
00240     CommandManager& mgr = Application::Instance->commandManager();
00241     QList<MenuItem*> items = item->getItems();
00242     QList<QAction*> actions = menu->actions();
00243     for (QList<MenuItem*>::ConstIterator it = items.begin(); it != items.end(); ++it) {
00244         // search for the menu item
00245         QList<QAction*> used_actions = findActions(actions, QString::fromAscii((*it)->command().c_str()));
00246         if (used_actions.isEmpty()) {
00247             if ((*it)->command() == "Separator") {
00248                 QAction* action = menu->addSeparator();
00249                 action->setObjectName(QLatin1String("Separator"));
00250                 // set the menu user data
00251                 action->setData(QLatin1String("Separator"));
00252                 used_actions.append(action);
00253             }
00254             else {
00255                 if ((*it)->hasItems()) {
00256                     // Creste a submenu
00257                     std::string menuName = (*it)->command();
00258                     QMenu* submenu = menu->addMenu(
00259                         QApplication::translate("Workbench", menuName.c_str(),
00260                                                 0, QApplication::UnicodeUTF8));
00261                     QAction* action = submenu->menuAction();
00262                     submenu->setObjectName(QString::fromAscii((*it)->command().c_str()));
00263                     action->setObjectName(QString::fromAscii((*it)->command().c_str()));
00264                     // set the menu user data
00265                     action->setData(QString::fromAscii((*it)->command().c_str()));
00266                     used_actions.append(action);
00267                 }
00268                 else {
00269                     // A command can have more than one QAction
00270                     int count = menu->actions().count();
00271                     // Check if action was added successfully
00272                     if (mgr.addTo((*it)->command().c_str(), menu)) {
00273                         QList<QAction*> acts = menu->actions();
00274                         for (int i=count; i < acts.count(); i++) {
00275                             QAction* a = acts[i];
00276                             // set the menu user data
00277                             a->setData(QString::fromAscii((*it)->command().c_str()));
00278                             used_actions.append(a);
00279                         }
00280                     }
00281                 }
00282             }
00283         }
00284         else {
00285             for (QList<QAction*>::Iterator it = used_actions.begin(); it != used_actions.end(); ++it) {
00286                 // put the menu item at the end
00287                 menu->removeAction(*it);
00288                 menu->addAction(*it);
00289                 int index = actions.indexOf(*it);
00290                 actions.removeAt(index);
00291             }
00292         }
00293 
00294         // fill up the submenu
00295         if ((*it)->hasItems())
00296             setup(*it, used_actions.front()->menu());
00297     }
00298 
00299     // remove all menu items which we don't need for the moment
00300     for (QList<QAction*>::Iterator it = actions.begin(); it != actions.end(); ++it) {
00301         menu->removeAction(*it);
00302     }
00303 }
00304 
00305 void MenuManager::retranslate() const
00306 {
00307     QMenuBar* menuBar = getMainWindow()->menuBar();
00308     QList<QAction*> actions = menuBar->actions();
00309     for (QList<QAction*>::Iterator it = actions.begin(); it != actions.end(); ++it) {
00310         if ((*it)->menu())
00311             retranslate((*it)->menu());
00312     }
00313 }
00314 
00315 void MenuManager::retranslate(QMenu* menu) const
00316 {
00317     // Note: Here we search for all menus and submenus to retranslate their
00318     // titles. To ease the translation for each menu the native name is set
00319     // as user data. However, there are special menus that are created by
00320     // actions for which the name of the according command name is set. For
00321     // such menus we have to use the command's menu text instaed. Examples
00322     // for such actions are Std_RecentFiles, Std_Workbench or Std_FreezeViews.
00323     CommandManager& mgr = Application::Instance->commandManager();
00324     QByteArray menuName = menu->menuAction()->data().toByteArray();
00325     Command* cmd = mgr.getCommandByName(menuName);
00326     if (cmd) {
00327         menu->setTitle(
00328             QApplication::translate(cmd->className(),
00329                                     cmd->getMenuText(),
00330                                     0, QCoreApplication::CodecForTr));
00331     }
00332     else {
00333         menu->setTitle(
00334             QApplication::translate("Workbench",
00335                                     (const char*)menuName,
00336                                     0, QApplication::UnicodeUTF8));
00337     }
00338     QList<QAction*> actions = menu->actions();
00339     for (QList<QAction*>::Iterator it = actions.begin(); it != actions.end(); ++it) {
00340         if ((*it)->menu()) {
00341             retranslate((*it)->menu());
00342         }
00343     }
00344 }
00345 
00346 QAction* MenuManager::findAction(const QList<QAction*>& acts, const QString& item) const
00347 {
00348     for (QList<QAction*>::ConstIterator it = acts.begin(); it != acts.end(); ++it) {
00349         if ((*it)->data().toString() == item)
00350             return *it;
00351     }
00352 
00353     return 0; // no item with the user data found
00354 }
00355 
00356 QList<QAction*> MenuManager::findActions(const QList<QAction*>& acts, const QString& item) const
00357 {
00358     // It is possible that the user text of several actions match with 'item'.
00359     // But for the first match all following actions must match. For example
00360     // the Std_WindowsMenu command provides several actions with the same user
00361     // name.
00362     bool first_match = false;
00363     QList<QAction*> used;
00364     for (QList<QAction*>::ConstIterator it = acts.begin(); it != acts.end(); ++it) {
00365         if ((*it)->data().toString() == item) {
00366             used.append(*it);
00367             first_match = true;
00368             // get only one separator per request
00369             if (item == QLatin1String("Separator"))
00370                 break;
00371         }
00372         else if (first_match)
00373             break;
00374     }
00375 
00376     return used;
00377 }
00378 
00379 void MenuManager::setupContextMenu(MenuItem* item, QMenu &menu) const
00380 {
00381     setup(item, &menu);
00382 }

Generated on Wed Nov 23 19:00:22 2011 for FreeCAD by  doxygen 1.6.1