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