]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiToolbar.cpp
Search for toolbar images in the filesystem and afterwards in the resource.
[lyx.git] / src / frontends / qt4 / GuiToolbar.cpp
index 44bddb907091deb39195cb1d3f07a8230d20a8b7..4d19f6dc26cd97ee878e5a248df56b928de8437e 100644 (file)
@@ -21,6 +21,7 @@
 #include "FuncStatus.h"
 #include "gettext.h"
 #include "IconPalette.h"
+#include "Layout.h"
 #include "LyXFunc.h"
 #include "ToolbarBackend.h"
 
@@ -34,8 +35,7 @@
 
 #include "support/filetools.h"
 #include "support/lstrings.h"
-
-#include "controllers/ControlMath.h"
+#include "support/lyxalgo.h" // sorted
 
 #include <QComboBox>
 #include <QToolBar>
 #include <QAction>
 #include <QPixmap>
 
+
+static void initializeResources()
+{
+       static bool initialized = false;
+       if (!initialized) {
+               Q_INIT_RESOURCE(Resources); 
+               initialized = true;
+       }
+}
+
+
 namespace lyx {
+namespace frontend {
 
 using std::string;
 using std::endl;
-using support::FileName;
+
 using support::libFileSearch;
 using support::subst;
+using support::compare;
+
+
+namespace {
+
+struct PngMap {
+       char const * key;
+       char const * value;
+};
+
+
+bool operator<(PngMap const & lhs, PngMap const & rhs)
+{
+               return compare(lhs.key, rhs.key) < 0;
+}
+
+
+class CompareKey {
+public:
+       CompareKey(string const & name) : name_(name) {}
+       bool operator()(PngMap const & other) const { return other.key == name_; }
+private:
+       string const name_;
+};
+
+
+PngMap sorted_png_map[] = {
+       { "Bumpeq", "bumpeq2" },
+       { "Cap", "cap2" },
+       { "Cup", "cup2" },
+       { "Delta", "delta2" },
+       { "Downarrow", "downarrow2" },
+       { "Gamma", "gamma2" },
+       { "Lambda", "lambda2" },
+       { "Leftarrow", "leftarrow2" },
+       { "Leftrightarrow", "leftrightarrow2" },
+       { "Longleftarrow", "longleftarrow2" },
+       { "Longleftrightarrow", "longleftrightarrow2" },
+       { "Longrightarrow", "longrightarrow2" },
+       { "Omega", "omega2" },
+       { "Phi", "phi2" },
+       { "Pi", "pi2" },
+       { "Psi", "psi2" },
+       { "Rightarrow", "rightarrow2" },
+       { "Sigma", "sigma2" },
+       { "Subset", "subset2" },
+       { "Supset", "supset2" },
+       { "Theta", "theta2" },
+       { "Uparrow", "uparrow2" },
+       { "Updownarrow", "updownarrow2" },
+       { "Upsilon", "upsilon2" },
+       { "Vdash", "vdash3" },
+       { "Xi", "xi2" },
+       { "nLeftarrow", "nleftarrow2" },
+       { "nLeftrightarrow", "nleftrightarrow2" },
+       { "nRightarrow", "nrightarrow2" },
+       { "nVDash", "nvdash3" },
+       { "nvDash", "nvdash2" },
+       { "textrm \\AA", "textrm_AA"},
+       { "textrm \\O", "textrm_Oe"},
+       { "vDash", "vdash2" }
+};
+
+size_t const nr_sorted_png_map = sizeof(sorted_png_map) / sizeof(PngMap);
+
+
+string const find_png(string const & name)
+{
+       PngMap const * const begin = sorted_png_map;
+       PngMap const * const end = begin + nr_sorted_png_map;
+       BOOST_ASSERT(sorted(begin, end));
+
+       PngMap const * const it = std::find_if(begin, end, CompareKey(name));
+
+       string png_name;
+       if (it != end)
+               png_name = it->value;
+       else {
+               png_name = subst(name, "_", "underscore");
+               png_name = subst(png_name, ' ', '_');
+
+               // This way we can have "math-delim { }" on the toolbar.
+               png_name = subst(png_name, "(", "lparen");
+               png_name = subst(png_name, ")", "rparen");
+               png_name = subst(png_name, "[", "lbracket");
+               png_name = subst(png_name, "]", "rbracket");
+               png_name = subst(png_name, "{", "lbrace");
+               png_name = subst(png_name, "}", "rbrace");
+               png_name = subst(png_name, "|", "bars");
+               png_name = subst(png_name, ",", "thinspace");
+               png_name = subst(png_name, ":", "mediumspace");
+               png_name = subst(png_name, ";", "thickspace");
+               png_name = subst(png_name, "!", "negthinspace");
+       }
+
+       LYXERR(Debug::GUI) << "find_png(" << name << ")\n"
+                          << "Looking for math PNG called \""
+                          << png_name << '"' << std::endl;
+       return png_name;
+}
+
+} // namespace anon
+
+
+/// return a icon for the given action
+static QIcon getIcon(FuncRequest const & f, bool unknown)
+{
+       initializeResources();
+       QPixmap pm;
+       string name1;
+       string name2;
+       string path;
+       string fullname;
+
+       switch (f.action) {
+       case LFUN_MATH_INSERT:
+               if (!f.argument().empty()) {
+                       path = "math/";
+                       name1 = find_png(to_utf8(f.argument()).substr(1));
+               }
+               break;
+       case LFUN_MATH_DELIM:
+       case LFUN_MATH_BIGDELIM:
+               path = "math/";
+               name1 = find_png(to_utf8(f.argument()));
+               break;
+       default:
+               name2 = lyxaction.getActionName(f.action);
+               name1 = name2;
+
+               if (!f.argument().empty())
+                       name1 = subst(name2 + ' ' + to_utf8(f.argument()), ' ', '_');
+       }
+
+       fullname = libFileSearch("images/" + path, name1, "png").absFilename();
+       if (pm.load(toqstr(fullname)))
+               return pm;
+
+       fullname = libFileSearch("images/" + path, name2, "png").absFilename();
+       if (pm.load(toqstr(fullname)))
+               return pm;
+
+       if (pm.load(":/images/" + toqstr(path + name1) + ".png"))
+               return pm;
+
+       if (pm.load(":/images/" + toqstr(path + name2) + ".png"))
+               return pm;
+
+       LYXERR(Debug::GUI) << "Cannot find icon for command \""
+                          << lyxaction.getActionName(f.action)
+                          << '(' << to_utf8(f.argument()) << ")\"" << endl;
+       if (unknown)
+               pm.load(":/images/unknown.png");
+
+       return pm;
+}
 
-namespace frontend {
 
 static TextClass const & textClass(LyXView const & lv)
 {
@@ -65,19 +232,16 @@ static TextClass const & textClass(LyXView const & lv)
 //
 /////////////////////////////////////////////////////////////////////
 
-GuiLayoutBox::GuiLayoutBox(QToolBar * toolbar, GuiViewBase & owner)
+GuiLayoutBox::GuiLayoutBox(GuiViewBase & owner)
        : owner_(owner)
 {
-       combo_ = new QComboBox;
-       combo_->setSizeAdjustPolicy(QComboBox::AdjustToContents);
-       combo_->setFocusPolicy(Qt::ClickFocus);
-       combo_->setMinimumWidth(combo_->sizeHint().width());
-       combo_->setMaxVisibleItems(100);
+       setSizeAdjustPolicy(QComboBox::AdjustToContents);
+       setFocusPolicy(Qt::ClickFocus);
+       setMinimumWidth(sizeHint().width());
+       setMaxVisibleItems(100);
 
-       QObject::connect(combo_, SIGNAL(activated(QString)),
+       QObject::connect(this, SIGNAL(activated(QString)),
                         this, SLOT(selected(QString)));
-
-       toolbar->addWidget(combo_);
 }
 
 
@@ -88,72 +252,61 @@ void GuiLayoutBox::set(docstring const & layout)
        QString const & name = toqstr(translateIfPossible(tc[layout]->name()));
 
        int i = 0;
-       for (; i < combo_->count(); ++i) {
-               if (name == combo_->itemText(i))
+       for (; i < count(); ++i) {
+               if (name == itemText(i))
                        break;
        }
 
-       if (i == combo_->count()) {
+       if (i == count()) {
                lyxerr << "Trying to select non existent layout type "
                        << fromqstr(name) << endl;
                return;
        }
 
-       combo_->setCurrentIndex(i);
+       setCurrentIndex(i);
 }
 
 
-void GuiLayoutBox::update()
+void GuiLayoutBox::updateContents()
 {
        TextClass const & tc = textClass(owner_);
 
-       combo_->setUpdatesEnabled(false);
-       combo_->clear();
+       setUpdatesEnabled(false);
+       clear();
 
        TextClass::const_iterator it = tc.begin();
        TextClass::const_iterator const end = tc.end();
        for (; it != end; ++it) {
                // ignore obsolete entries
-               if ((*it)->obsoleted_by().empty())
-                       combo_->addItem(toqstr(translateIfPossible((*it)->name())));
+               addItem(toqstr(translateIfPossible((*it)->name())));
        }
 
        // needed to recalculate size hint
-       combo_->hide();
-       combo_->setMinimumWidth(combo_->sizeHint().width());
-       combo_->show();
+       hide();
+       setMinimumWidth(sizeHint().width());
+       show();
 
-       combo_->setUpdatesEnabled(true);
-       combo_->update();
-}
-
-
-void GuiLayoutBox::clear()
-{
-       combo_->clear();
-}
-
-
-void GuiLayoutBox::open()
-{
-       combo_->showPopup();
-}
-
-
-void GuiLayoutBox::setEnabled(bool enable)
-{
-       // Workaround for Qt bug where setEnabled(true) closes
-       // the popup
-       if (enable != combo_->isEnabled())
-               combo_->setEnabled(enable);
+       setUpdatesEnabled(true);
 }
 
 
 void GuiLayoutBox::selected(const QString & str)
 {
        owner_.setFocus();
-
-       layoutSelected(owner_, qstring_to_ucs4(str));
+       TextClass const & tc = owner_.buffer()->params().getTextClass();
+       docstring const name = qstring_to_ucs4(str);
+       TextClass::const_iterator it  = tc.begin();
+       TextClass::const_iterator const end = tc.end();
+       for (; it != end; ++it) {
+               docstring const & itname = (*it)->name();
+               if (translateIfPossible(itname) == name) {
+                       FuncRequest const func(LFUN_LAYOUT, itname,
+                                              FuncRequest::TOOLBAR);
+                       owner_.dispatch(func);
+                       return;
+               }
+       }
+       lyxerr << "ERROR (layoutSelected): layout not found!" << endl;
 }
 
 
@@ -182,17 +335,10 @@ GuiToolbar::GuiToolbar(ToolbarInfo const & tbinfo, GuiViewBase & owner)
 }
 
 
-void GuiToolbar::focusCommandBuffer()
-{
-       if (command_buffer_)
-               command_buffer_->setFocus();
-}
-
-
 Action * GuiToolbar::addItem(ToolbarItem const & item)
 {
        Action * act = new Action(owner_,
-               getIcon(item.func_, false).c_str(),
+               getIcon(item.func_, false),
          toqstr(item.label_), item.func_, toqstr(item.label_));
        actions_.append(act);
        return act;
@@ -206,7 +352,8 @@ void GuiToolbar::add(ToolbarItem const & item)
                addSeparator();
                break;
        case ToolbarItem::LAYOUTS:
-               layout_ = new GuiLayoutBox(this, owner_);
+               layout_ = new GuiLayoutBox(owner_);
+               addWidget(layout_);
                break;
        case ToolbarItem::MINIBUFFER:
                command_buffer_ = new GuiCommandBuffer(&owner_);
@@ -217,7 +364,7 @@ void GuiToolbar::add(ToolbarItem const & item)
        case ToolbarItem::TABLEINSERT: {
                QToolButton * tb = new QToolButton;
                tb->setCheckable(true);
-               tb->setIcon(QPixmap(toqstr(getIcon(FuncRequest(LFUN_TABULAR_INSERT)))));
+               tb->setIcon(getIcon(FuncRequest(LFUN_TABULAR_INSERT), true));
                tb->setToolTip(qt_(to_ascii(item.label_)));
                tb->setStatusTip(qt_(to_ascii(item.label_)));
                tb->setText(qt_(to_ascii(item.label_)));
@@ -250,7 +397,7 @@ void GuiToolbar::add(ToolbarItem const & item)
                                panel->addButton(addItem(*it));
                                // use the icon of first action for the toolbar button
                                if (it == tbinfo->items.begin())
-                                       tb->setIcon(QPixmap(getIcon(it->func_).c_str()));
+                                       tb->setIcon(getIcon(it->func_, true));
                        }
                tb->setCheckable(true);
                connect(tb, SIGNAL(clicked(bool)), panel, SLOT(setVisible(bool)));
@@ -264,8 +411,7 @@ void GuiToolbar::add(ToolbarItem const & item)
                tb->setToolTip(qt_(to_ascii(item.label_)));
                tb->setStatusTip(qt_(to_ascii(item.label_)));
                tb->setText(qt_(to_ascii(item.label_)));
-               FileName icon_path = libFileSearch("images/math", item.name_, "png");
-               tb->setIcon(QIcon(toqstr(icon_path.absFilename())));
+               tb->setIcon(QPixmap(":images/math/" + toqstr(item.name_) + ".png"));
                connect(this, SIGNAL(iconSizeChanged(QSize)),
                        tb, SLOT(setIconSize(QSize)));
 
@@ -298,24 +444,6 @@ void GuiToolbar::add(ToolbarItem const & item)
 }
 
 
-void GuiToolbar::hide(bool)
-{
-       QToolBar::hide();
-}
-
-
-void GuiToolbar::show(bool)
-{
-       QToolBar::show();
-}
-
-
-bool GuiToolbar::isVisible() const
-{
-       return QToolBar::isVisible();
-}
-
-
 void GuiToolbar::saveInfo(ToolbarSection::ToolbarInfo & tbinfo)
 {
        // if tbinfo.state == auto *do not* set on/off
@@ -347,8 +475,11 @@ void GuiToolbar::saveInfo(ToolbarSection::ToolbarInfo & tbinfo)
 }
 
 
-void GuiToolbar::update()
+void GuiToolbar::updateContents()
 {
+       // update visible toolbars only
+       if (!isVisible())
+               return;
        // This is a speed bottleneck because this is called on every keypress
        // and update calls getStatus, which copies the cursor at least two times
        for (int i = 0; i < actions_.size(); ++i)
@@ -359,52 +490,6 @@ void GuiToolbar::update()
 }
 
 
-string const getIcon(FuncRequest const & f, bool unknown)
-{
-       using frontend::find_png;
-
-       string fullname;
-
-       switch (f.action) {
-       case LFUN_MATH_INSERT:
-               if (!f.argument().empty())
-                       fullname = find_png(to_utf8(f.argument()).substr(1));
-               break;
-       case LFUN_MATH_DELIM:
-       case LFUN_MATH_BIGDELIM:
-               fullname = find_png(to_utf8(f.argument()));
-               break;
-       default:
-               string const name = lyxaction.getActionName(f.action);
-               string png_name = name;
-
-               if (!f.argument().empty())
-                       png_name = subst(name + ' ' + to_utf8(f.argument()), ' ', '_');
-
-               fullname = libFileSearch("images", png_name, "png").absFilename();
-
-               if (fullname.empty()) {
-                       // try without the argument
-                       fullname = libFileSearch("images", name, "png").absFilename();
-               }
-       }
-
-       if (!fullname.empty()) {
-               LYXERR(Debug::GUI) << "Full icon name is `"
-                                  << fullname << '\'' << endl;
-               return fullname;
-       }
-
-       LYXERR(Debug::GUI) << "Cannot find icon for command \""
-                          << lyxaction.getActionName(f.action)
-                          << '(' << to_utf8(f.argument()) << ")\"" << endl;
-       if (unknown)
-               return libFileSearch("images", "unknown", "png").absFilename();
-       else
-               return string();
-}
-
-
 } // namespace frontend
 } // namespace lyx