]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiToolbar.cpp
Fix forward search with okular
[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
36 #include "support/debug.h"
37 #include "support/gettext.h"
38 #include "support/lstrings.h"
39
40 #include <QSettings>
41 #include <QShowEvent>
42 #include <QString>
43 #include <QToolBar>
44 #include <QToolButton>
45
46 #include "support/lassert.h"
47
48 using namespace std;
49 using namespace lyx::support;
50
51 namespace lyx {
52 namespace frontend {
53
54 GuiToolbar::GuiToolbar(ToolbarInfo const & tbinfo, GuiView & owner)
55         : QToolBar(toqstr(tbinfo.gui_name), &owner), visibility_(0),
56           owner_(owner), command_buffer_(0), tbinfo_(tbinfo), filled_(false)
57 {
58         setIconSize(owner.iconSize());
59         connect(&owner, SIGNAL(iconSizeChanged(QSize)), this,
60                 SLOT(setIconSize(QSize)));
61
62         // Toolbar dragging is allowed.
63         setMovable(true);
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::fill()
72 {
73         if (filled_)
74                 return;
75         ToolbarInfo::item_iterator it = tbinfo_.items.begin();
76         ToolbarInfo::item_iterator end = tbinfo_.items.end();
77         for (; it != end; ++it)
78                 add(*it);       
79         filled_ = true;
80 }
81
82
83 void GuiToolbar::showEvent(QShowEvent * ev)
84 {
85         fill();
86         ev->accept();
87 }
88
89
90 void GuiToolbar::setVisibility(int visibility)
91 {
92         visibility_ = visibility;
93 }
94
95
96 Action * GuiToolbar::addItem(ToolbarItem const & item)
97 {
98         QString text = toqstr(item.label_);
99         // Get the keys bound to this action, but keep only the
100         // first one later
101         KeyMap::Bindings bindings = theTopLevelKeymap().findBindings(item.func_);
102         if (bindings.size())
103                 text += " [" + toqstr(bindings.begin()->print(KeySequence::ForGui)) + "]";
104
105         Action * act = new Action(&owner_, getIcon(item.func_, false),
106                 text, item.func_, text, this);
107         actions_.append(act);
108         return act;
109 }
110
111 namespace {
112
113 class PaletteButton : public QToolButton
114 {
115 private:
116         GuiToolbar * bar_;
117         ToolbarItem const & tbitem_;
118         bool initialized_;
119 public:
120         PaletteButton(GuiToolbar * bar, ToolbarItem const & item)
121                 : QToolButton(bar), bar_(bar), tbitem_(item), initialized_(false)
122         {
123                 QString const label = qt_(to_ascii(tbitem_.label_));
124                 setToolTip(label);
125                 setStatusTip(label);
126                 setText(label);
127                 connect(bar_, SIGNAL(iconSizeChanged(QSize)),
128                         this, SLOT(setIconSize(QSize)));
129                 setCheckable(true);
130                 ToolbarInfo const * tbinfo = guiApp->toolbars().info(tbitem_.name_);
131                 if (tbinfo)
132                         // use the icon of first action for the toolbar button
133                         setIcon(getIcon(tbinfo->items.begin()->func_, true));
134         }
135
136         void mousePressEvent(QMouseEvent * e)
137         {
138                 if (initialized_) {
139                         QToolButton::mousePressEvent(e);
140                         return;
141                 }
142
143                 initialized_ = true;
144
145                 ToolbarInfo const * tbinfo = guiApp->toolbars().info(tbitem_.name_);
146                 if (!tbinfo) {
147                         LYXERR0("Unknown toolbar " << tbitem_.name_);
148                         return;
149                 }
150                 IconPalette * panel = new IconPalette(this);
151                 QString const label = qt_(to_ascii(tbitem_.label_));
152                 panel->setWindowTitle(label);
153                 connect(this, SIGNAL(clicked(bool)), panel, SLOT(setVisible(bool)));
154                 connect(panel, SIGNAL(visible(bool)), this, SLOT(setChecked(bool)));
155                 ToolbarInfo::item_iterator it = tbinfo->items.begin();
156                 ToolbarInfo::item_iterator const end = tbinfo->items.end();
157                 for (; it != end; ++it)
158                         if (!getStatus(it->func_).unknown())
159                                 panel->addButton(bar_->addItem(*it));
160
161                 QToolButton::mousePressEvent(e);
162         }
163 };
164
165 }
166
167
168 MenuButton::MenuButton(GuiToolbar * bar, ToolbarItem const & item, bool const sticky)
169         : QToolButton(bar), bar_(bar), tbitem_(item), initialized_(false)
170 {
171         setPopupMode(QToolButton::InstantPopup);
172         QString const label = qt_(to_ascii(tbitem_.label_));
173         setToolTip(label);
174         setStatusTip(label);
175         setText(label);
176         QString const name = toqstr(tbitem_.name_);
177         QStringList imagedirs;
178         imagedirs << "images/math/" << "images/";
179         for (int i = 0; i < imagedirs.size(); ++i) { 
180                 QString imagedir = imagedirs.at(i);
181                 FileName const fname = imageLibFileSearch(imagedir, name, "png");
182                 if (fname.exists()) {
183                         setIcon(QIcon(getPixmap(imagedir, name, "png")));
184                         break;
185                 }
186         }
187         if (sticky)
188                 connect(this, SIGNAL(triggered(QAction *)),
189                         this, SLOT(actionTriggered(QAction *)));
190         connect(bar, SIGNAL(iconSizeChanged(QSize)),
191                 this, SLOT(setIconSize(QSize)));
192 }
193
194 void MenuButton::mousePressEvent(QMouseEvent * e)
195 {
196         if (initialized_) {
197                 QToolButton::mousePressEvent(e);
198                 return;
199         }
200
201         initialized_ = true;
202
203         QString const label = qt_(to_ascii(tbitem_.label_));
204         ButtonMenu * m = new ButtonMenu(label, this);
205         m->setWindowTitle(label);
206         m->setTearOffEnabled(true);
207         connect(bar_, SIGNAL(updated()), m, SLOT(updateParent()));
208         connect(bar_, SIGNAL(updated()), this, SLOT(updateTriggered()));
209         ToolbarInfo const * tbinfo = guiApp->toolbars().info(tbitem_.name_);
210         if (!tbinfo) {
211                 LYXERR0("Unknown toolbar " << tbitem_.name_);
212                 return;
213         }
214         ToolbarInfo::item_iterator it = tbinfo->items.begin();
215         ToolbarInfo::item_iterator const end = tbinfo->items.end();
216         for (; it != end; ++it)
217                 if (!getStatus(it->func_).unknown())
218                         m->add(bar_->addItem(*it));
219         setMenu(m);
220
221         QToolButton::mousePressEvent(e);
222 }
223
224
225 void MenuButton::actionTriggered(QAction * action)
226 {
227         QToolButton::setDefaultAction(action);
228         setPopupMode(QToolButton::DelayedPopup);
229 }
230
231
232 void MenuButton::updateTriggered()
233 {
234         if (!menu())
235                 return;
236
237         bool enabled = false;
238         QList<QAction *> acts = menu()->actions();
239         for (int i = 0; i < acts.size(); ++i)
240                 if (acts[i]->isEnabled()) {
241                         enabled = true;
242                         break;
243                 }
244         // Enable the MenuButton if at least one menu item is enabled
245         setEnabled(enabled);
246         // If a disabled item is default, switch to InstantPopup
247         // (this can happen if a user selects e.g. DVI and then
248         // turns non-TeX fonts on)
249         if (defaultAction() && !defaultAction()->isEnabled())
250                 setPopupMode(QToolButton::InstantPopup);
251 }
252
253
254 void GuiToolbar::add(ToolbarItem const & item)
255 {
256         switch (item.type_) {
257         case ToolbarItem::SEPARATOR:
258                 addSeparator();
259                 break;
260         case ToolbarItem::LAYOUTS: {
261                 LayoutBox * layout = owner_.getLayoutDialog();
262                 QObject::connect(this, SIGNAL(iconSizeChanged(QSize)),
263                         layout, SLOT(setIconSize(QSize)));
264                 QAction * action = addWidget(layout);
265                 action->setVisible(true);
266                 break;
267         }
268         case ToolbarItem::MINIBUFFER:
269                 command_buffer_ = new GuiCommandBuffer(&owner_);
270                 addWidget(command_buffer_);
271                 /// \todo find a Qt4 equivalent to setHorizontalStretchable(true);
272                 //setHorizontalStretchable(true);
273                 break;
274         case ToolbarItem::TABLEINSERT: {
275                 QToolButton * tb = new QToolButton;
276                 tb->setCheckable(true);
277                 tb->setIcon(getIcon(FuncRequest(LFUN_TABULAR_INSERT), true));
278                 QString const label = qt_(to_ascii(item.label_));
279                 tb->setToolTip(label);
280                 tb->setStatusTip(label);
281                 tb->setText(label);
282                 InsertTableWidget * iv = new InsertTableWidget(owner_, tb);
283                 connect(tb, SIGNAL(clicked(bool)), iv, SLOT(show(bool)));
284                 connect(iv, SIGNAL(visible(bool)), tb, SLOT(setChecked(bool)));
285                 connect(this, SIGNAL(updated()), iv, SLOT(updateParent()));
286                 addWidget(tb);
287                 break;
288                 }
289         case ToolbarItem::ICONPALETTE:
290                 addWidget(new PaletteButton(this, item));
291                 break;
292
293         case ToolbarItem::POPUPMENU: {
294                 addWidget(new MenuButton(this, item, false));
295                 break;
296                 }
297         case ToolbarItem::STICKYPOPUPMENU: {
298                 addWidget(new MenuButton(this, item, true));
299                 break;
300                 }
301         case ToolbarItem::COMMAND: {
302                 if (!getStatus(item.func_).unknown())
303                         addAction(addItem(item));
304                 break;
305                 }
306         default:
307                 break;
308         }
309 }
310
311
312 void GuiToolbar::update(bool in_math, bool in_table, bool in_review, 
313         bool in_mathmacrotemplate, bool in_ipa)
314 {
315         if (visibility_ & Toolbars::AUTO) {
316                 bool show_it = (in_math && (visibility_ & Toolbars::MATH))
317                         || (in_table && (visibility_ & Toolbars::TABLE))
318                         || (in_review && (visibility_ & Toolbars::REVIEW))
319                         || (in_mathmacrotemplate && (visibility_ & Toolbars::MATHMACROTEMPLATE))
320                         || (in_ipa && (visibility_ & Toolbars::IPA));
321                 setVisible(show_it);
322         }
323
324         // update visible toolbars only
325         if (!isVisible())
326                 return;
327
328         // This is a speed bottleneck because this is called on every keypress
329         // and update calls getStatus, which copies the cursor at least two times
330         for (int i = 0; i < actions_.size(); ++i)
331                 actions_[i]->update();
332
333         LayoutBox * layout = owner_.getLayoutDialog();
334         if (layout)
335                 layout->setEnabled(lyx::getStatus(FuncRequest(LFUN_LAYOUT)).enabled());
336
337         // emit signal
338         updated();
339 }
340
341
342 QString GuiToolbar::sessionKey() const
343 {
344         return "views/" + QString::number(owner_.id()) + "/" + objectName();
345 }
346
347
348 void GuiToolbar::saveSession() const
349 {
350         QSettings settings;
351         settings.setValue(sessionKey() + "/visibility", visibility_);
352 }
353
354
355 void GuiToolbar::restoreSession()
356 {
357         QSettings settings;
358         int const error_val = -1;
359         int visibility =
360                 settings.value(sessionKey() + "/visibility", error_val).toInt();
361         if (visibility == error_val || visibility == 0) {
362                 // This should not happen, but in case we use the defaults
363                 LYXERR(Debug::GUI, "Session settings could not be found! Defaults are used instead.");
364                 visibility = 
365                         guiApp->toolbars().defaultVisibility(fromqstr(objectName()));
366         }
367         setVisibility(visibility);
368 }
369
370
371 void GuiToolbar::toggle()
372 {
373         docstring state;
374         if (visibility_ & Toolbars::ALLOWAUTO) {
375                 if (!(visibility_ & Toolbars::AUTO)) {
376                         visibility_ |= Toolbars::AUTO;
377                         hide();
378                         state = _("auto");
379                 } else {
380                         visibility_ &= ~Toolbars::AUTO;
381                         if (isVisible()) {
382                                 hide();
383                                 state = _("off");
384                         } else {
385                                 show();
386                                 state = _("on");
387                         }
388                 }
389         } else {
390                 if (isVisible()) {
391                         hide();
392                         state = _("off");
393                 } else {
394                         show();
395                         state = _("on");
396                 }
397         }
398
399         owner_.message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
400                 qstring_to_ucs4(windowTitle()), state));
401 }
402
403 } // namespace frontend
404 } // namespace lyx
405
406 #include "moc_GuiToolbar.cpp"