]> git.lyx.org Git - features.git/blob - src/frontends/qt4/GuiToolbar.cpp
cleanup GuiLayoutBox.
[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 void GuiToolbar::focusCommandBuffer()
175 {
176         if (command_buffer_)
177                 command_buffer_->setFocus();
178 }
179
180
181 Action * GuiToolbar::addItem(ToolbarItem const & item)
182 {
183         Action * act = new Action(owner_,
184                 getIcon(item.func_, false).c_str(),
185           toqstr(item.label_), item.func_, toqstr(item.label_));
186         actions_.append(act);
187         return act;
188 }
189
190
191 void GuiToolbar::add(ToolbarItem const & item)
192 {
193         switch (item.type_) {
194         case ToolbarItem::SEPARATOR:
195                 addSeparator();
196                 break;
197         case ToolbarItem::LAYOUTS:
198                 layout_ = new GuiLayoutBox(owner_);
199                 addWidget(layout_);
200                 break;
201         case ToolbarItem::MINIBUFFER:
202                 command_buffer_ = new GuiCommandBuffer(&owner_);
203                 addWidget(command_buffer_);
204                 /// \todo find a Qt4 equivalent to setHorizontalStretchable(true);
205                 //setHorizontalStretchable(true);
206                 break;
207         case ToolbarItem::TABLEINSERT: {
208                 QToolButton * tb = new QToolButton;
209                 tb->setCheckable(true);
210                 tb->setIcon(QPixmap(toqstr(getIcon(FuncRequest(LFUN_TABULAR_INSERT)))));
211                 tb->setToolTip(qt_(to_ascii(item.label_)));
212                 tb->setStatusTip(qt_(to_ascii(item.label_)));
213                 tb->setText(qt_(to_ascii(item.label_)));
214                 InsertTableWidget * iv = new InsertTableWidget(owner_, tb);
215                 connect(tb, SIGNAL(clicked(bool)), iv, SLOT(show(bool)));
216                 connect(iv, SIGNAL(visible(bool)), tb, SLOT(setChecked(bool)));
217                 connect(this, SIGNAL(updated()), iv, SLOT(updateParent()));
218                 addWidget(tb);
219                 break;
220                 }
221         case ToolbarItem::ICONPALETTE: {
222                 QToolButton * tb = new QToolButton(this);
223                 tb->setToolTip(qt_(to_ascii(item.label_)));
224                 tb->setStatusTip(qt_(to_ascii(item.label_)));
225                 tb->setText(qt_(to_ascii(item.label_)));
226                 connect(this, SIGNAL(iconSizeChanged(QSize)),
227                         tb, SLOT(setIconSize(QSize)));
228                 IconPalette * panel = new IconPalette(tb);
229                 panel->setWindowTitle(qt_(to_ascii(item.label_)));
230                 connect(this, SIGNAL(updated()), panel, SLOT(updateParent()));
231                 ToolbarInfo const * tbinfo = toolbarbackend.getDefinedToolbarInfo(item.name_);
232                 if (!tbinfo) {
233                         lyxerr << "Unknown toolbar " << item.name_ << endl;
234                         break;
235                 }
236                 ToolbarInfo::item_iterator it = tbinfo->items.begin();
237                 ToolbarInfo::item_iterator const end = tbinfo->items.end();
238                 for (; it != end; ++it)
239                         if (!getStatus(it->func_).unknown()) {
240                                 panel->addButton(addItem(*it));
241                                 // use the icon of first action for the toolbar button
242                                 if (it == tbinfo->items.begin())
243                                         tb->setIcon(QPixmap(getIcon(it->func_).c_str()));
244                         }
245                 tb->setCheckable(true);
246                 connect(tb, SIGNAL(clicked(bool)), panel, SLOT(setVisible(bool)));
247                 connect(panel, SIGNAL(visible(bool)), tb, SLOT(setChecked(bool)));
248                 addWidget(tb);
249                 break;
250                 }
251         case ToolbarItem::POPUPMENU: {
252                 QToolButton * tb = new QToolButton;
253                 tb->setPopupMode(QToolButton::InstantPopup);
254                 tb->setToolTip(qt_(to_ascii(item.label_)));
255                 tb->setStatusTip(qt_(to_ascii(item.label_)));
256                 tb->setText(qt_(to_ascii(item.label_)));
257                 FileName icon_path = libFileSearch("images/math", item.name_, "png");
258                 tb->setIcon(QIcon(toqstr(icon_path.absFilename())));
259                 connect(this, SIGNAL(iconSizeChanged(QSize)),
260                         tb, SLOT(setIconSize(QSize)));
261
262                 ButtonMenu * m = new ButtonMenu(qt_(to_ascii(item.label_)), tb);
263                 m->setWindowTitle(qt_(to_ascii(item.label_)));
264                 m->setTearOffEnabled(true);
265                 connect(this, SIGNAL(updated()), m, SLOT(updateParent()));
266                 ToolbarInfo const * tbinfo = toolbarbackend.getDefinedToolbarInfo(item.name_);
267                 if (!tbinfo) {
268                         lyxerr << "Unknown toolbar " << item.name_ << endl;
269                         break;
270                 }
271                 ToolbarInfo::item_iterator it = tbinfo->items.begin();
272                 ToolbarInfo::item_iterator const end = tbinfo->items.end();
273                 for (; it != end; ++it)
274                         if (!getStatus(it->func_).unknown())
275                                 m->add(addItem(*it));
276                 tb->setMenu(m);
277                 addWidget(tb);
278                 break;
279                 }
280         case ToolbarItem::COMMAND: {
281                 if (!getStatus(item.func_).unknown())
282                         addAction(addItem(item));
283                 break;
284                 }
285         default:
286                 break;
287         }
288 }
289
290
291 void GuiToolbar::saveInfo(ToolbarSection::ToolbarInfo & tbinfo)
292 {
293         // if tbinfo.state == auto *do not* set on/off
294         if (tbinfo.state != ToolbarSection::ToolbarInfo::AUTO) {
295                 if (GuiToolbar::isVisible())
296                         tbinfo.state = ToolbarSection::ToolbarInfo::ON;
297                 else
298                         tbinfo.state = ToolbarSection::ToolbarInfo::OFF;
299         }
300         //
301         // no need to save it here.
302         Qt::ToolBarArea loc = owner_.toolBarArea(this);
303
304         if (loc == Qt::TopToolBarArea)
305                 tbinfo.location = ToolbarSection::ToolbarInfo::TOP;
306         else if (loc == Qt::BottomToolBarArea)
307                 tbinfo.location = ToolbarSection::ToolbarInfo::BOTTOM;
308         else if (loc == Qt::RightToolBarArea)
309                 tbinfo.location = ToolbarSection::ToolbarInfo::RIGHT;
310         else if (loc == Qt::LeftToolBarArea)
311                 tbinfo.location = ToolbarSection::ToolbarInfo::LEFT;
312         else
313                 tbinfo.location = ToolbarSection::ToolbarInfo::NOTSET;
314
315         // save toolbar position. They are not used to restore toolbar position
316         // now because move(x,y) does not work for toolbar.
317         tbinfo.posx = pos().x();
318         tbinfo.posy = pos().y();
319 }
320
321
322 void GuiToolbar::updateContents()
323 {
324         // update visible toolbars only
325         if (!isVisible())
326                 return;
327         // This is a speed bottleneck because this is called on every keypress
328         // and update calls getStatus, which copies the cursor at least two times
329         for (int i = 0; i < actions_.size(); ++i)
330                 actions_[i]->update();
331
332         // emit signal
333         updated();
334 }
335
336
337 string const getIcon(FuncRequest const & f, bool unknown)
338 {
339         using frontend::find_png;
340
341         string fullname;
342
343         switch (f.action) {
344         case LFUN_MATH_INSERT:
345                 if (!f.argument().empty())
346                         fullname = find_png(to_utf8(f.argument()).substr(1));
347                 break;
348         case LFUN_MATH_DELIM:
349         case LFUN_MATH_BIGDELIM:
350                 fullname = find_png(to_utf8(f.argument()));
351                 break;
352         default:
353                 string const name = lyxaction.getActionName(f.action);
354                 string png_name = name;
355
356                 if (!f.argument().empty())
357                         png_name = subst(name + ' ' + to_utf8(f.argument()), ' ', '_');
358
359                 fullname = libFileSearch("images", png_name, "png").absFilename();
360
361                 if (fullname.empty()) {
362                         // try without the argument
363                         fullname = libFileSearch("images", name, "png").absFilename();
364                 }
365         }
366
367         if (!fullname.empty()) {
368                 LYXERR(Debug::GUI) << "Full icon name is `"
369                                    << fullname << '\'' << endl;
370                 return fullname;
371         }
372
373         LYXERR(Debug::GUI) << "Cannot find icon for command \""
374                            << lyxaction.getActionName(f.action)
375                            << '(' << to_utf8(f.argument()) << ")\"" << endl;
376         if (unknown)
377                 return libFileSearch("images", "unknown", "png").absFilename();
378         else
379                 return string();
380 }
381
382
383 } // namespace frontend
384 } // namespace lyx
385
386 #include "GuiToolbar_moc.cpp"