]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiToolbar.cpp
Consider class-provided citation engines
[lyx.git] / src / frontends / qt4 / GuiToolbar.cpp
1 /**
2  * \file qt4/GuiToolbar.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author John Levon
8  * \author Jean-Marc Lasgouttes
9  * \author Angus Leeming
10  * \author Stefan Schimanski
11  * \author Abdelrazak Younes
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "GuiToolbar.h"
19
20 #include "Action.h"
21 #include "GuiApplication.h"
22 #include "GuiCommandBuffer.h"
23 #include "GuiView.h"
24 #include "IconPalette.h"
25 #include "InsertTableWidget.h"
26 #include "LayoutBox.h"
27 #include "qt_helpers.h"
28 #include "Toolbars.h"
29
30 #include "FuncRequest.h"
31 #include "FuncStatus.h"
32 #include "KeyMap.h"
33 #include "LyX.h"
34 #include "LyXRC.h"
35 #include "Session.h"
36
37 #include "support/debug.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
40
41 #include <QSettings>
42 #include <QShowEvent>
43 #include <QString>
44 #include <QToolBar>
45 #include <QToolButton>
46
47 #include "support/lassert.h"
48
49 using namespace std;
50 using namespace lyx::support;
51
52 namespace lyx {
53 namespace frontend {
54
55 GuiToolbar::GuiToolbar(ToolbarInfo const & tbinfo, GuiView & owner)
56         : QToolBar(toqstr(tbinfo.gui_name), &owner), visibility_(0),
57           owner_(owner), command_buffer_(0), tbinfo_(tbinfo), filled_(false),
58           restored_(false)
59 {
60         setIconSize(owner.iconSize());
61         connect(&owner, SIGNAL(iconSizeChanged(QSize)), this,
62                 SLOT(setIconSize(QSize)));
63
64         // This is used by QMainWindow::restoreState for proper main window state
65         // restauration.
66         setObjectName(toqstr(tbinfo.name));
67         restoreSession();
68 }
69
70
71 void GuiToolbar::setVisible(bool visible)
72 {
73         // This is a hack to find out which toolbars have been restored by
74         // MainWindow::restoreState and which toolbars should be initialized
75         // by us (i.e., new toolbars)
76         restored_ = true;
77         QToolBar::setVisible(visible);
78 }
79
80
81 bool GuiToolbar::isRestored() const
82 {
83         return restored_;
84 }
85
86
87 void GuiToolbar::fill()
88 {
89         if (filled_)
90                 return;
91         ToolbarInfo::item_iterator it = tbinfo_.items.begin();
92         ToolbarInfo::item_iterator end = tbinfo_.items.end();
93         for (; it != end; ++it)
94                 add(*it);
95         filled_ = true;
96 }
97
98
99 void GuiToolbar::showEvent(QShowEvent * ev)
100 {
101         fill();
102         ev->accept();
103 }
104
105
106 void GuiToolbar::setVisibility(int visibility)
107 {
108         visibility_ = visibility;
109 }
110
111
112 Action * GuiToolbar::addItem(ToolbarItem const & item)
113 {
114         QString text = toqstr(item.label_);
115         // Get the keys bound to this action, but keep only the
116         // first one later
117         KeyMap::Bindings bindings = theTopLevelKeymap().findBindings(*item.func_);
118         if (!bindings.empty())
119                 text += " [" + toqstr(bindings.begin()->print(KeySequence::ForGui)) + "]";
120
121         Action * act = new Action(item.func_, getIcon(*item.func_, false), text,
122                                   text, this);
123         actions_.append(act);
124         return act;
125 }
126
127 namespace {
128
129 class PaletteButton : public QToolButton
130 {
131 private:
132         GuiToolbar * bar_;
133         ToolbarItem const & tbitem_;
134         bool initialized_;
135 public:
136         PaletteButton(GuiToolbar * bar, ToolbarItem const & item)
137                 : QToolButton(bar), bar_(bar), tbitem_(item), initialized_(false)
138         {
139                 QString const label = qt_(to_ascii(tbitem_.label_));
140                 setToolTip(label);
141                 setStatusTip(label);
142                 setText(label);
143                 connect(bar_, SIGNAL(iconSizeChanged(QSize)),
144                         this, SLOT(setIconSize(QSize)));
145                 setCheckable(true);
146                 ToolbarInfo const * tbinfo = guiApp->toolbars().info(tbitem_.name_);
147                 if (tbinfo)
148                         // use the icon of first action for the toolbar button
149                         setIcon(getIcon(*tbinfo->items.begin()->func_, true));
150         }
151
152         void mousePressEvent(QMouseEvent * e)
153         {
154                 if (initialized_) {
155                         QToolButton::mousePressEvent(e);
156                         return;
157                 }
158
159                 initialized_ = true;
160
161                 ToolbarInfo const * tbinfo = guiApp->toolbars().info(tbitem_.name_);
162                 if (!tbinfo) {
163                         LYXERR0("Unknown toolbar " << tbitem_.name_);
164                         return;
165                 }
166                 IconPalette * panel = new IconPalette(this);
167                 QString const label = qt_(to_ascii(tbitem_.label_));
168                 panel->setWindowTitle(label);
169                 connect(this, SIGNAL(clicked(bool)), panel, SLOT(setVisible(bool)));
170                 connect(panel, SIGNAL(visible(bool)), this, SLOT(setChecked(bool)));
171                 ToolbarInfo::item_iterator it = tbinfo->items.begin();
172                 ToolbarInfo::item_iterator const end = tbinfo->items.end();
173                 for (; it != end; ++it)
174                         if (!getStatus(*it->func_).unknown())
175                                 panel->addButton(bar_->addItem(*it));
176
177                 QToolButton::mousePressEvent(e);
178         }
179 };
180
181 } // namespace
182
183
184 MenuButton::MenuButton(GuiToolbar * bar, ToolbarItem const & item, bool const sticky)
185         : QToolButton(bar), bar_(bar), tbitem_(item)
186 {
187         setPopupMode(QToolButton::InstantPopup);
188         QString const label = qt_(to_ascii(tbitem_.label_));
189         setToolTip(label);
190         setStatusTip(label);
191         setText(label);
192         QString const name = toqstr(tbitem_.name_);
193         QStringList imagedirs;
194         imagedirs << "images/math/" << "images/";
195         for (int i = 0; i < imagedirs.size(); ++i) {
196                 QString imagedir = imagedirs.at(i);
197                 FileName const fname = imageLibFileSearch(imagedir, name, "svgz,png",
198                         theGuiApp()->imageSearchMode());
199                 if (fname.exists()) {
200                         setIcon(QIcon(getPixmap(imagedir, name, "svgz,png")));
201                         break;
202                 }
203         }
204         if (sticky)
205                 connect(this, SIGNAL(triggered(QAction *)),
206                         this, SLOT(actionTriggered(QAction *)));
207         connect(bar, SIGNAL(iconSizeChanged(QSize)),
208                 this, SLOT(setIconSize(QSize)));
209         initialize();
210 }
211
212
213 void MenuButton::initialize()
214 {
215         QString const label = qt_(to_ascii(tbitem_.label_));
216         ButtonMenu * m = new ButtonMenu(label, this);
217         m->setWindowTitle(label);
218         m->setTearOffEnabled(true);
219         connect(bar_, SIGNAL(updated()), m, SLOT(updateParent()));
220         connect(bar_, SIGNAL(updated()), this, SLOT(updateTriggered()));
221         ToolbarInfo const * tbinfo = guiApp->toolbars().info(tbitem_.name_);
222         if (!tbinfo) {
223                 LYXERR0("Unknown toolbar " << tbitem_.name_);
224                 return;
225         }
226         ToolbarInfo::item_iterator it = tbinfo->items.begin();
227         ToolbarInfo::item_iterator const end = tbinfo->items.end();
228         for (; it != end; ++it)
229                 if (!getStatus(*it->func_).unknown())
230                         m->add(bar_->addItem(*it));
231         setMenu(m);
232 }
233
234
235 void MenuButton::actionTriggered(QAction * action)
236 {
237         QToolButton::setDefaultAction(action);
238         setPopupMode(QToolButton::DelayedPopup);
239 }
240
241
242 void MenuButton::updateTriggered()
243 {
244         if (!menu())
245                 return;
246
247         bool enabled = false;
248         QList<QAction *> acts = menu()->actions();
249         for (int i = 0; i < acts.size(); ++i)
250                 if (acts[i]->isEnabled()) {
251                         enabled = true;
252                         break;
253                 }
254         // Enable the MenuButton if at least one menu item is enabled
255         setEnabled(enabled);
256         // If a disabled item is default, switch to InstantPopup
257         // (this can happen if a user selects e.g. DVI and then
258         // turns non-TeX fonts on)
259         if (defaultAction() && !defaultAction()->isEnabled())
260                 setPopupMode(QToolButton::InstantPopup);
261 }
262
263
264 void GuiToolbar::add(ToolbarItem const & item)
265 {
266         switch (item.type_) {
267         case ToolbarItem::SEPARATOR:
268                 addSeparator();
269                 break;
270         case ToolbarItem::LAYOUTS: {
271                 LayoutBox * layout = owner_.getLayoutDialog();
272                 QObject::connect(this, SIGNAL(iconSizeChanged(QSize)),
273                         layout, SLOT(setIconSize(QSize)));
274                 QAction * action = addWidget(layout);
275                 action->setVisible(true);
276                 break;
277         }
278         case ToolbarItem::MINIBUFFER:
279                 command_buffer_ = new GuiCommandBuffer(&owner_);
280                 addWidget(command_buffer_);
281                 /// \todo find a Qt4 equivalent to setHorizontalStretchable(true);
282                 //setHorizontalStretchable(true);
283                 break;
284         case ToolbarItem::TABLEINSERT: {
285                 QToolButton * tb = new QToolButton;
286                 tb->setCheckable(true);
287                 tb->setIcon(getIcon(FuncRequest(LFUN_TABULAR_INSERT), true));
288                 QString const label = qt_(to_ascii(item.label_));
289                 tb->setToolTip(label);
290                 tb->setStatusTip(label);
291                 tb->setText(label);
292                 InsertTableWidget * iv = new InsertTableWidget(tb);
293                 connect(tb, SIGNAL(clicked(bool)), iv, SLOT(show(bool)));
294                 connect(iv, SIGNAL(visible(bool)), tb, SLOT(setChecked(bool)));
295                 connect(this, SIGNAL(updated()), iv, SLOT(updateParent()));
296                 addWidget(tb);
297                 break;
298                 }
299         case ToolbarItem::ICONPALETTE:
300                 addWidget(new PaletteButton(this, item));
301                 break;
302
303         case ToolbarItem::POPUPMENU: {
304                 addWidget(new MenuButton(this, item, false));
305                 break;
306                 }
307         case ToolbarItem::STICKYPOPUPMENU: {
308                 addWidget(new MenuButton(this, item, true));
309                 break;
310                 }
311         case ToolbarItem::COMMAND: {
312                 if (!getStatus(*item.func_).unknown())
313                         addAction(addItem(item));
314                 break;
315                 }
316         default:
317                 break;
318         }
319 }
320
321
322 void GuiToolbar::update(int context)
323 {
324         if (visibility_ & Toolbars::AUTO) {
325                 setVisible(visibility_ & context & Toolbars::ALLOWAUTO);
326                 if (isVisible() && commandBuffer() && (context & Toolbars::MINIBUFFER_FOCUS))
327                         commandBuffer()->setFocus();
328         }
329
330         // update visible toolbars only
331         if (!isVisible())
332                 return;
333
334         // This is a speed bottleneck because this is called on every keypress
335         // and update calls getStatus, which copies the cursor at least two times
336         for (int i = 0; i < actions_.size(); ++i)
337                 actions_[i]->update();
338
339         LayoutBox * layout = owner_.getLayoutDialog();
340         if (layout)
341                 layout->setEnabled(lyx::getStatus(FuncRequest(LFUN_LAYOUT)).enabled());
342
343         // emit signal
344         updated();
345 }
346
347
348 QString GuiToolbar::sessionKey() const
349 {
350         return "views/" + QString::number(owner_.id()) + "/" + objectName();
351 }
352
353
354 void GuiToolbar::saveSession(QSettings & settings) const
355 {
356         settings.setValue(sessionKey() + "/visibility", visibility_);
357         settings.setValue(sessionKey() + "/movability", isMovable());
358 }
359
360
361 void GuiToolbar::restoreSession()
362 {
363         QSettings settings;
364         int const error_val = -1;
365         int visibility =
366                 settings.value(sessionKey() + "/visibility", error_val).toInt();
367         if (visibility == error_val || visibility == 0) {
368                 // This should not happen, but in case we use the defaults
369                 LYXERR(Debug::GUI, "Session settings could not be found! Defaults are used instead.");
370                 visibility =
371                         guiApp->toolbars().defaultVisibility(fromqstr(objectName()));
372         }
373         setVisibility(visibility);
374
375         int movability = settings.value(sessionKey() + "/movability", true).toBool();
376         setMovable(movability);
377 }
378
379
380 void GuiToolbar::toggle()
381 {
382         docstring state;
383         if (visibility_ & Toolbars::ALLOWAUTO) {
384                 if (!(visibility_ & Toolbars::AUTO)) {
385                         visibility_ |= Toolbars::AUTO;
386                         hide();
387                         state = _("auto");
388                 } else {
389                         visibility_ &= ~Toolbars::AUTO;
390                         if (isVisible()) {
391                                 hide();
392                                 state = _("off");
393                         } else {
394                                 show();
395                                 state = _("on");
396                         }
397                 }
398         } else {
399                 if (isVisible()) {
400                         hide();
401                         state = _("off");
402                 } else {
403                         show();
404                         state = _("on");
405                 }
406         }
407
408         owner_.message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
409                 qstring_to_ucs4(windowTitle()), state));
410 }
411
412 void GuiToolbar::movable(bool silent)
413 {
414         // toggle movability
415         setMovable(!isMovable());
416
417         // manual update avoids bug in qt that the drag handle is not removed
418         // properly, e.g. in Windows
419         Q_EMIT update();
420
421         // silence for toggling of many toolbars for performance
422         if (!silent) {
423                 docstring state;
424                 if (isMovable())
425                         state = _("movable");
426                 else
427                         state = _("immovable");
428                 owner_.message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
429                         qstring_to_ucs4(windowTitle()), state));
430         }
431 }
432
433 } // namespace frontend
434 } // namespace lyx
435
436 #include "moc_GuiToolbar.cpp"