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