]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiToolbar.cpp
This is the last of a series of patches that merges the layout modules development...
[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 Abdelrazak Younes
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "Buffer.h"
18 #include "BufferParams.h"
19 #include "debug.h"
20 #include "FuncRequest.h"
21 #include "FuncStatus.h"
22 #include "gettext.h"
23 #include "LyXFunc.h"
24 #include "IconPalette.h"
25
26 #include "GuiView.h"
27 #include "GuiCommandBuffer.h"
28 #include "GuiToolbar.h"
29 #include "LyXAction.h"
30 #include "Action.h"
31 #include "qt_helpers.h"
32 #include "InsertTableWidget.h"
33 #include "support/filetools.h"
34 #include "support/lstrings.h"
35 #include "controllers/ControlMath.h"
36 #include "ToolbarBackend.h"
37
38 #include <QComboBox>
39 #include <QToolBar>
40 #include <QToolButton>
41 #include <QAction>
42 #include <QPixmap>
43
44 namespace lyx {
45
46 using std::string;
47 using std::endl;
48 using support::FileName;
49 using support::libFileSearch;
50 using support::subst;
51
52 namespace frontend {
53
54 static TextClass const & textClass(LyXView const & lv)
55 {
56         return lv.buffer()->params().getTextClass();
57 }
58
59
60 GuiLayoutBox::GuiLayoutBox(QToolBar * toolbar, GuiViewBase & owner)
61         : owner_(owner)
62 {
63         combo_ = new QComboBox;
64         combo_->setSizeAdjustPolicy(QComboBox::AdjustToContents);
65         combo_->setFocusPolicy(Qt::ClickFocus);
66         combo_->setMinimumWidth(combo_->sizeHint().width());
67         combo_->setMaxVisibleItems(100);
68
69         QObject::connect(combo_, SIGNAL(activated(const QString &)),
70                          this, SLOT(selected(const QString &)));
71
72         toolbar->addWidget(combo_);
73 }
74
75
76 void GuiLayoutBox::set(docstring const & layout)
77 {
78         TextClass const & tc = textClass(owner_);
79
80         QString const & name = toqstr(translateIfPossible(tc[layout]->name()));
81
82         int i = 0;
83         for (; i < combo_->count(); ++i) {
84                 if (name == combo_->itemText(i))
85                         break;
86         }
87
88         if (i == combo_->count()) {
89                 lyxerr << "Trying to select non existent layout type "
90                         << fromqstr(name) << endl;
91                 return;
92         }
93
94         combo_->setCurrentIndex(i);
95 }
96
97
98 void GuiLayoutBox::update()
99 {
100         TextClass const & tc = textClass(owner_);
101
102         combo_->setUpdatesEnabled(false);
103
104         combo_->clear();
105
106         TextClass::const_iterator it = tc.begin();
107         TextClass::const_iterator const end = tc.end();
108         for (; it != end; ++it) {
109                 // ignore obsolete entries
110                 if ((*it)->obsoleted_by().empty())
111                         combo_->addItem(toqstr(translateIfPossible((*it)->name())));
112         }
113
114         // needed to recalculate size hint
115         combo_->hide();
116         combo_->setMinimumWidth(combo_->sizeHint().width());
117         combo_->show();
118
119         combo_->setUpdatesEnabled(true);
120         combo_->update();
121 }
122
123
124 void GuiLayoutBox::clear()
125 {
126         combo_->clear();
127 }
128
129
130 void GuiLayoutBox::open()
131 {
132         combo_->showPopup();
133 }
134
135
136 void GuiLayoutBox::setEnabled(bool enable)
137 {
138         // Workaround for Qt bug where setEnabled(true) closes
139         // the popup
140         if (enable != combo_->isEnabled())
141                 combo_->setEnabled(enable);
142 }
143
144
145 void GuiLayoutBox::selected(const QString & str)
146 {
147         owner_.setFocus();
148
149         layoutSelected(owner_, qstring_to_ucs4(str));
150 }
151
152
153 GuiToolbar::GuiToolbar(ToolbarInfo const & tbinfo, GuiViewBase & owner)
154         : QToolBar(qt_(tbinfo.gui_name), &owner), command_buffer_(0), owner_(owner)
155 {
156         // give visual separation between adjacent toolbars
157         addSeparator();
158
159         // TODO: save toolbar position
160         setMovable(true);
161
162         ToolbarInfo::item_iterator it = tbinfo.items.begin();
163         ToolbarInfo::item_iterator end = tbinfo.items.end();
164         for (; it != end; ++it)
165                 add(*it);
166 }
167
168
169 void GuiToolbar::focusCommandBuffer()
170 {
171         if (command_buffer_)
172                 command_buffer_->setFocus();
173 }
174
175
176 void GuiToolbar::add(ToolbarItem const & item)
177 {
178         switch (item.type_) {
179         case ToolbarItem::SEPARATOR:
180                 addSeparator();
181                 break;
182         case ToolbarItem::LAYOUTS:
183                 layout_.reset(new GuiLayoutBox(this, owner_));
184                 break;
185         case ToolbarItem::MINIBUFFER:
186                 command_buffer_ = new GuiCommandBuffer(&owner_);
187                 addWidget(command_buffer_);
188                 /// \todo find a Qt4 equivalent to setHorizontalStretchable(true);
189                 //setHorizontalStretchable(true);
190                 break;
191         case ToolbarItem::TABLEINSERT: {
192                 QToolButton * tb = new QToolButton;
193                 tb->setCheckable(true);
194                 tb->setIcon(QPixmap(toqstr(getIcon(FuncRequest(LFUN_TABULAR_INSERT)))));
195                 tb->setToolTip(qt_(to_ascii(item.label_)));
196                 tb->setStatusTip(qt_(to_ascii(item.label_)));
197                 tb->setText(qt_(to_ascii(item.label_)));
198                 InsertTableWidget * iv = new InsertTableWidget(owner_, tb);
199                 connect(tb, SIGNAL(clicked(bool)), iv, SLOT(show(bool)));
200                 connect(iv, SIGNAL(visible(bool)), tb, SLOT(setChecked(bool)));
201                 connect(this, SIGNAL(updated()), iv, SLOT(updateParent()));
202                 addWidget(tb);
203                 break;
204                 }
205         case ToolbarItem::ICONPALETTE: {
206                 QToolButton * tb = new QToolButton(this);
207                 tb->setToolTip(qt_(to_ascii(item.label_)));
208                 tb->setStatusTip(qt_(to_ascii(item.label_)));
209                 tb->setText(qt_(to_ascii(item.label_)));
210                 connect(this, SIGNAL(iconSizeChanged(const QSize &)),
211                         tb, SLOT(setIconSize(const QSize &)));
212                 IconPalette * panel = new IconPalette(tb);
213                 panel->setWindowTitle(qt_(to_ascii(item.label_)));
214                 connect(this, SIGNAL(updated()), panel, SLOT(updateParent()));
215                 ToolbarInfo const * tbinfo = toolbarbackend.getDefinedToolbarInfo(item.name_);
216                 if (!tbinfo) {
217                         lyxerr << "Unknown toolbar " << item.name_ << endl;
218                         break;
219                 }
220                 ToolbarInfo::item_iterator it = tbinfo->items.begin();
221                 ToolbarInfo::item_iterator const end = tbinfo->items.end();
222                 for (; it != end; ++it)
223                         if (!getStatus(it->func_).unknown()) {
224                                 Action * action = new Action(owner_,
225                                         getIcon(it->func_),
226                                         it->label_,
227                                         it->func_,
228                                         it->label_);
229                                 panel->addButton(action);
230                                 ActionVector.push_back(action);
231                                 // use the icon of first action for the toolbar button
232                                 if (it == tbinfo->items.begin())
233                                         tb->setIcon(QPixmap(getIcon(it->func_).c_str()));
234                         }
235                 tb->setCheckable(true);
236                 connect(tb, SIGNAL(clicked(bool)), panel, SLOT(setVisible(bool)));
237                 connect(panel, SIGNAL(visible(bool)), tb, SLOT(setChecked(bool)));
238                 addWidget(tb);
239                 break;
240                 }
241         case ToolbarItem::POPUPMENU: {
242                 QToolButton * tb = new QToolButton;
243                 tb->setPopupMode(QToolButton::InstantPopup);
244                 tb->setToolTip(qt_(to_ascii(item.label_)));
245                 tb->setStatusTip(qt_(to_ascii(item.label_)));
246                 tb->setText(qt_(to_ascii(item.label_)));
247                 FileName icon_path = libFileSearch("images/math", item.name_, "png");
248                 tb->setIcon(QIcon(toqstr(icon_path.absFilename())));
249                 connect(this, SIGNAL(iconSizeChanged(const QSize &)),
250                         tb, SLOT(setIconSize(const QSize &)));
251
252                 ButtonMenu * m = new ButtonMenu(qt_(to_ascii(item.label_)), tb);
253                 m->setWindowTitle(qt_(to_ascii(item.label_)));
254                 m->setTearOffEnabled(true);
255                 connect(this, SIGNAL(updated()), m, SLOT(updateParent()));
256                 ToolbarInfo const * tbinfo = toolbarbackend.getDefinedToolbarInfo(item.name_);
257                 if (!tbinfo) {
258                         lyxerr << "Unknown toolbar " << item.name_ << endl;
259                         break;
260                 }
261                 ToolbarInfo::item_iterator it = tbinfo->items.begin();
262                 ToolbarInfo::item_iterator const end = tbinfo->items.end();
263                 for (; it != end; ++it)
264                         if (!getStatus(it->func_).unknown()) {
265                                 Action * action = new Action(owner_,
266                                         getIcon(it->func_, false),
267                                         it->label_,
268                                         it->func_,
269                                         it->label_);
270                                 m->add(action);
271                                 ActionVector.push_back(action);
272                         }
273                 tb->setMenu(m);
274                 addWidget(tb);
275                 break;
276                 }
277         case ToolbarItem::COMMAND: {
278                 if (getStatus(item.func_).unknown())
279                         break;
280
281                 Action * action = new Action(owner_,
282                         getIcon(item.func_),
283                         item.label_,
284                         item.func_,
285                         item.label_);
286                 addAction(action);
287                 ActionVector.push_back(action);
288                 break;
289                 }
290         default:
291                 break;
292         }
293 }
294
295
296 void GuiToolbar::hide(bool)
297 {
298         QToolBar::hide();
299 }
300
301
302 void GuiToolbar::show(bool)
303 {
304         QToolBar::show();
305 }
306
307
308 bool GuiToolbar::isVisible() const
309 {
310         return QToolBar::isVisible();
311 }
312
313
314 void GuiToolbar::saveInfo(ToolbarSection::ToolbarInfo & tbinfo)
315 {
316         // if tbinfo.state == auto *do not* set on/off
317         if (tbinfo.state != ToolbarSection::ToolbarInfo::AUTO) {
318                 if (GuiToolbar::isVisible())
319                         tbinfo.state = ToolbarSection::ToolbarInfo::ON;
320                 else
321                         tbinfo.state = ToolbarSection::ToolbarInfo::OFF;
322         }
323         //
324         // no need to save it here.
325         Qt::ToolBarArea loc = owner_.toolBarArea(this);
326
327         if (loc == Qt::TopToolBarArea)
328                 tbinfo.location = ToolbarSection::ToolbarInfo::TOP;
329         else if (loc == Qt::BottomToolBarArea)
330                 tbinfo.location = ToolbarSection::ToolbarInfo::BOTTOM;
331         else if (loc == Qt::RightToolBarArea)
332                 tbinfo.location = ToolbarSection::ToolbarInfo::RIGHT;
333         else if (loc == Qt::LeftToolBarArea)
334                 tbinfo.location = ToolbarSection::ToolbarInfo::LEFT;
335         else
336                 tbinfo.location = ToolbarSection::ToolbarInfo::NOTSET;
337
338         // save toolbar position. They are not used to restore toolbar position
339         // now because move(x,y) does not work for toolbar.
340         tbinfo.posx = pos().x();
341         tbinfo.posy = pos().y();
342 }
343
344
345 void GuiToolbar::update()
346 {
347         // This is a speed bottleneck because this is called on every keypress
348         // and update calls getStatus, which copies the cursor at least two times
349         for (size_t i = 0; i < ActionVector.size(); ++i)
350                 ActionVector[i]->update();
351
352         // emit signal
353         updated();
354 }
355
356
357 string const getIcon(FuncRequest const & f, bool unknown)
358 {
359         using frontend::find_png;
360
361         string fullname;
362
363         switch (f.action) {
364         case LFUN_MATH_INSERT:
365                 if (!f.argument().empty())
366                         fullname = find_png(to_utf8(f.argument()).substr(1));
367                 break;
368         case LFUN_MATH_DELIM:
369         case LFUN_MATH_BIGDELIM:
370                 fullname = find_png(to_utf8(f.argument()));
371                 break;
372         default:
373                 string const name = lyxaction.getActionName(f.action);
374                 string png_name = name;
375
376                 if (!f.argument().empty())
377                         png_name = subst(name + ' ' + to_utf8(f.argument()), ' ', '_');
378
379                 fullname = libFileSearch("images", png_name, "png").absFilename();
380
381                 if (fullname.empty()) {
382                         // try without the argument
383                         fullname = libFileSearch("images", name, "png").absFilename();
384                 }
385         }
386
387         if (!fullname.empty()) {
388                 LYXERR(Debug::GUI) << "Full icon name is `"
389                                    << fullname << '\'' << endl;
390                 return fullname;
391         }
392
393         LYXERR(Debug::GUI) << "Cannot find icon for command \""
394                            << lyxaction.getActionName(f.action)
395                            << '(' << to_utf8(f.argument()) << ")\"" << endl;
396         if (unknown)
397                 return libFileSearch("images", "unknown", "png").absFilename();
398         else
399                 return string();
400 }
401
402
403 } // namespace frontend
404 } // namespace lyx
405
406 #include "GuiToolbar_moc.cpp"