The attached patch almost works. (Details like the icon are not yet
there.) There are some big problems, however, which seem to derive from
the fact that the whole menu and toolbar setup is not really designed to
be modified on the fly.
The problem here seems to trace to how FuncRequest objects are handled
by our Action class. Namely, when an Action is created, it retains a
const & to a FuncRequest. So one can't pass a temporary. This means that
I have to create a kind of cache for these objects. The idea was to keep
them around as long as we need them. But it turns out that we need them
rather a long time. If you look at the FIXME in the patch, you will see
what I mean. Clearing the menu is supposed to delete any actions it owns:
void QMenu::clear ()
Removes all the menu's actions. Actions owned by the menu and not shown
in any other widget are deleted.
In fact, however, they seem still to be around, and if we clear the
cache we eventually segfault. If we don't clear the cache, we are
effectively leaking memory.
I can make this work by changing the Action class so it makes a copy of
the FuncRequest. But I worry that this is just hiding the real problem,
and that all these Action objects we're creating are leaking, or at
least being retained for no good reason.
Help wanted!
Richard
>From 13a9c8f7571f4451e3ffef16dc19bdd08be86add Mon Sep 17 00:00:00 2001
From: Richard Heck <rgh...@lyx.org>
Date: Fri, 24 Jun 2016 17:47:30 -0400
Subject: [PATCH] Attempt to do the inset thing with a menu.
---
lib/ui/stdtoolbars.inc | 2 +
src/frontends/qt4/GuiToolbar.cpp | 120 +++++++++++++++++++++++++++++++++++++++
src/frontends/qt4/GuiToolbar.h | 24 ++++++++
src/frontends/qt4/GuiView.cpp | 2 +-
src/frontends/qt4/GuiView.h | 2 +
src/frontends/qt4/Toolbars.cpp | 9 ++-
src/frontends/qt4/Toolbars.h | 4 +-
7 files changed, 160 insertions(+), 3 deletions(-)
diff --git a/lib/ui/stdtoolbars.inc b/lib/ui/stdtoolbars.inc
index d375afa..c504e4a 100644
--- a/lib/ui/stdtoolbars.inc
+++ b/lib/ui/stdtoolbars.inc
@@ -95,6 +95,8 @@ ToolbarSet
Item "Toggle outline" "dialog-toggle toc"
Item "Toggle math toolbar" "toolbar-toggle math"
Item "Toggle table toolbar" "toolbar-toggle table"
+ Separator
+ Insets
End
Toolbar "view/update" "View/Update"
diff --git a/src/frontends/qt4/GuiToolbar.cpp b/src/frontends/qt4/GuiToolbar.cpp
index 77471c9..094617d 100644
--- a/src/frontends/qt4/GuiToolbar.cpp
+++ b/src/frontends/qt4/GuiToolbar.cpp
@@ -25,19 +25,27 @@
#include "InsertTableWidget.h"
#include "LayoutBox.h"
#include "qt_helpers.h"
+#include "TextClass.h"
#include "Toolbars.h"
+#include "Buffer.h"
+#include "BufferParams.h"
+#include "BufferView.h"
+#include "Cursor.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "KeyMap.h"
#include "LyX.h"
#include "LyXRC.h"
#include "Session.h"
+#include "Text.h"
#include "support/debug.h"
#include "support/gettext.h"
#include "support/lstrings.h"
+#include <list>
+
#include <QSettings>
#include <QShowEvent>
#include <QString>
@@ -263,6 +271,114 @@ void MenuButton::updateTriggered()
}
+class InsetMenuButton::Private
+{
+ /// noncopyable
+ Private(Private const &);
+ void operator=(Private const &);
+public:
+ Private() : inset_(0)
+ {}
+
+ /// since Action retains a reference to the
+ /// FuncRequest, we need to keep these around
+ typedef std::list<FuncRequest> FuncCache;
+ ///
+ DocumentClassConstPtr text_class_;
+ ///
+ InsetText const * inset_;
+ ///
+ FuncCache fcache_;
+};
+
+
+InsetMenuButton::InsetMenuButton(GuiToolbar * bar)
+ : QToolButton(bar), bar_(bar), d(new Private())
+{
+ setPopupMode(QToolButton::InstantPopup);
+ QString const label = qt_("Add Custom Inset");
+ setToolTip(label);
+ setStatusTip(label);
+ setText(label);
+ connect(bar, SIGNAL(iconSizeChanged(QSize)),
+ this, SLOT(setIconSize(QSize)));
+ initialize();
+}
+
+
+void InsetMenuButton::initialize()
+{
+ QString const label = qt_("Add Custom Inset");
+
+ QMenu * m = new QMenu(label, this);
+ m->setWindowTitle(label);
+ m->setTearOffEnabled(true);
+ setMenu(m);
+
+ connect(bar_, SIGNAL(updated()), this, SLOT(updateTriggered()));
+ updateTriggered();
+}
+
+
+void InsetMenuButton::updateTriggered()
+{
+ GuiView const & owner = bar_->owner();
+ BufferView const * bv = owner.currentBufferView();
+ QMenu * m = menu();
+ if (!bv) {
+ if (m)
+ m->clear();
+ setEnabled(false);
+ setMinimumWidth(sizeHint().width());
+ d->text_class_.reset();
+ d->inset_ = 0;
+ d->fcache_.clear();
+ return;
+ }
+
+ // we'll only update the inset list if the text class has changed
+ // or we've moved from one inset to another
+ DocumentClassConstPtr text_class = bv->buffer().params().documentClassPtr();
+ InsetText const * inset = &(bv->cursor().innerText()->inset());
+ if (d->text_class_ == text_class && d->inset_ == inset)
+ return;
+
+ if (m)
+ m->clear();
+ d->inset_ = inset;
+ d->text_class_ = text_class;
+ // FIXME If this is uncommented, then we crash.
+ // Presumably, the Action objects are still active
+ // for some reason, even though they have been
+ // removed from the menu.
+ //d->fcache_.clear();
+
+ TextClass::InsetLayouts const & insetLayouts = d->text_class_->insetLayouts();
+ TextClass::InsetLayouts::const_iterator iit = insetLayouts.begin();
+ TextClass::InsetLayouts::const_iterator ien = insetLayouts.end();
+
+ for (; iit != ien; ++iit) {
+ InsetLayout const & il = iit->second;
+ if (il.lyxtype() != InsetLayout::CUSTOM)
+ continue;
+
+ docstring const name = iit->first;
+ QString const loc_item = toqstr(translateIfPossible(
+ prefixIs(name, from_ascii("Flex:")) ?
+ name.substr(5) : name));
+
+ FuncRequest const func(LFUN_FLEX_INSERT,
+ from_ascii("\"") + name + from_ascii("\""), FuncRequest::TOOLBAR);
+ d->fcache_.push_back(func);
+ FuncRequest const & cfunc = d->fcache_.back();
+ Action * act =
+ new Action(getIcon(cfunc, false), loc_item, cfunc, loc_item, this);
+ m->addAction(act);
+ }
+ setEnabled(!d->fcache_.empty());
+}
+
+
void GuiToolbar::add(ToolbarItem const & item)
{
switch (item.type_) {
@@ -277,6 +393,10 @@ void GuiToolbar::add(ToolbarItem const & item)
action->setVisible(true);
break;
}
+ case ToolbarItem::INSETS: {
+ addWidget(new InsetMenuButton(this));
+ break;
+ }
case ToolbarItem::MINIBUFFER:
command_buffer_ = new GuiCommandBuffer(&owner_);
addWidget(command_buffer_);
diff --git a/src/frontends/qt4/GuiToolbar.h b/src/frontends/qt4/GuiToolbar.h
index caad355..83d5b29 100644
--- a/src/frontends/qt4/GuiToolbar.h
+++ b/src/frontends/qt4/GuiToolbar.h
@@ -61,6 +61,28 @@ private Q_SLOTS:
+class InsetMenuButton : public QToolButton
+{
+ Q_OBJECT
+public:
+ ///
+ InsetMenuButton(GuiToolbar * bar);
+
+private:
+ ///
+ void initialize();
+ ///
+ GuiToolbar * bar_;
+ ///
+ class Private;
+ Private * d;
+
+private Q_SLOTS:
+ ///
+ void updateTriggered();
+};
+
+
class GuiToolbar : public QToolBar
{
Q_OBJECT
@@ -102,6 +124,8 @@ public:
///
Action * addItem(ToolbarItem const & item);
+ ///
+ GuiView const & owner() { return owner_; }
Q_SIGNALS:
///
diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp
index 87ee553..fbfbb53 100644
--- a/src/frontends/qt4/GuiView.cpp
+++ b/src/frontends/qt4/GuiView.cpp
@@ -1344,7 +1344,7 @@ void GuiView::setBusy(bool busy)
return;
}
QApplication::restoreOverrideCursor();
- updateLayoutList();
+ updateLayoutList();
}
diff --git a/src/frontends/qt4/GuiView.h b/src/frontends/qt4/GuiView.h
index c3ccdbd..eed736b 100644
--- a/src/frontends/qt4/GuiView.h
+++ b/src/frontends/qt4/GuiView.h
@@ -46,6 +46,7 @@ class Dialog;
class LayoutBox;
class GuiToolbar;
class GuiWorkArea;
+class InsetCombo;
class TabWorkArea;
class TocModels;
class ToolbarInfo;
@@ -149,6 +150,7 @@ public:
///
LayoutBox * getLayoutDialog() const;
+ InsetCombo * getInsetCombo() const;
/// hides the workarea and makes sure it is clean
bool hideWorkArea(GuiWorkArea * wa);
diff --git a/src/frontends/qt4/Toolbars.cpp b/src/frontends/qt4/Toolbars.cpp
index 20eee93..05f3269 100644
--- a/src/frontends/qt4/Toolbars.cpp
+++ b/src/frontends/qt4/Toolbars.cpp
@@ -74,7 +74,8 @@ ToolbarInfo & ToolbarInfo::read(Lexer & lex)
TO_EXPORTFORMATS,
TO_IMPORTFORMATS,
TO_UPDATEFORMATS,
- TO_VIEWFORMATS
+ TO_VIEWFORMATS,
+ TO_INSETS
};
struct LexerKeyword toolTags[] = {
@@ -82,6 +83,7 @@ ToolbarInfo & ToolbarInfo::read(Lexer & lex)
{ "exportformats", TO_EXPORTFORMATS },
{ "iconpalette", TO_ICONPALETTE },
{ "importformats", TO_IMPORTFORMATS },
+ { "insets", TO_INSETS },
{ "item", TO_COMMAND },
{ "layouts", TO_LAYOUTS },
{ "minibuffer", TO_MINIBUFFER },
@@ -178,6 +180,11 @@ ToolbarInfo & ToolbarInfo::read(Lexer & lex)
FuncRequest(FuncCode(ToolbarItem::LAYOUTS))));
break;
+ case TO_INSETS: {
+ add(ToolbarItem(ToolbarItem::INSETS, "Hi"));
+ break;
+ }
+
case TO_TABLEINSERT:
if (lex.next(true)) {
docstring const tooltip = lex.getDocString();
diff --git a/src/frontends/qt4/Toolbars.h b/src/frontends/qt4/Toolbars.h
index 02d0ebe..01d4679 100644
--- a/src/frontends/qt4/Toolbars.h
+++ b/src/frontends/qt4/Toolbars.h
@@ -43,7 +43,9 @@ public:
/// a button that expands a menu but remembers the last choice
STICKYPOPUPMENU,
///
- ICONPALETTE
+ ICONPALETTE,
+ ///
+ INSETS
};
ToolbarItem(Type type,
--
2.5.0