]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GToolbar.C
some tabular fixes for the problems reported by Helge
[lyx.git] / src / frontends / gtk / GToolbar.C
1 /**
2  * \file GToolbar.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Huang Ying
7  * \author John Spray
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 // Too hard to make concept checks work with this file
15 #ifdef _GLIBCXX_CONCEPT_CHECKS
16 #undef _GLIBCXX_CONCEPT_CHECKS
17 #endif
18 #ifdef _GLIBCPP_CONCEPT_CHECKS
19 #undef _GLIBCPP_CONCEPT_CHECKS
20 #endif
21
22 #include "GToolbar.h"
23 #include "GView.h"
24
25 #include "ghelpers.h"
26
27 #include "buffer.h"
28 #include "bufferparams.h"
29 #include "debug.h"
30 #include "funcrequest.h"
31 #include "FuncStatus.h"
32 #include "lyxfunc.h"
33
34 using std::string;
35
36 namespace lyx {
37 namespace frontend {
38
39 namespace {
40
41 GView::Position getPosition(ToolbarBackend::Flags const & flags)
42 {
43         if (flags & ToolbarBackend::TOP)
44                 return GView::Top;
45         if (flags & ToolbarBackend::BOTTOM)
46                 return GView::Bottom;
47         if (flags & ToolbarBackend::LEFT)
48                 return GView::Left;
49         if (flags & ToolbarBackend::RIGHT)
50                 return GView::Right;
51         return GView::Top;
52 }
53
54
55 LyXTextClass const & getTextClass(LyXView const & lv)
56 {
57         return lv.buffer()->params().getLyXTextClass();
58 }
59
60 char const * gToolData = "tool_data";
61
62 } // namespace anon
63
64
65 GLayoutBox::GLayoutBox(LyXView & owner,
66                        Gtk::Toolbar & toolbar,
67                        FuncRequest const & func)
68         : owner_(owner),
69           internal_(false)
70 {
71         combo_.signal_changed().connect(
72                 sigc::mem_fun(*this,&GLayoutBox::selected));
73
74         model_ = Gtk::ListStore::create(cols_);
75         combo_.set_model(model_);
76         Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
77         combo_.pack_start(*cell, true);
78         combo_.add_attribute(*cell,"text",0);
79         combo_.set_wrap_width(2);
80         // Initially there's nothing in the liststore, so set the size
81         // to avoid it jumping too much when the user does something that
82         // causes the first update()
83         combo_.set_size_request(130,-1);
84
85         combo_.set_data(
86                 gToolData,
87                 reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
88
89         Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox);
90         vbox->pack_end(combo_, Gtk::PACK_EXPAND_PADDING);
91
92         Gtk::ToolItem * toolitem = Gtk::manage(new Gtk::ToolItem);
93         toolitem->add(*vbox);
94         toolbar.append(*toolitem);
95 }
96
97 void GLayoutBox::set(string const & layout)
98 {
99         LyXTextClass const & tc = getTextClass(owner_);
100         string const target = tc[layout]->name();
101
102         internal_ = true;
103         Gtk::TreeModel::iterator it = model_->children().begin();
104         Gtk::TreeModel::iterator end = model_->children().end();
105         for (; it != end; ++it) {
106                 if ((*it)[cols_.name] == target){
107                         combo_.set_active(it);
108                         internal_ = false;
109                         return;
110                 }
111         }
112         internal_ = false;
113
114         lyxerr << "ERROR (GLayoutBox::set): layout not found! name: "
115                << target << std::endl;
116 }
117
118
119 void GLayoutBox::update()
120 {
121         int const current_selection = combo_.get_active_row_number();
122         clear();
123
124         LyXTextClass const & tc = getTextClass(owner_);
125         LyXTextClass::const_iterator it = tc.begin();
126         LyXTextClass::const_iterator const end = tc.end();
127
128         internal_ = true;
129         for (; it != end; ++it)
130                 if ((*it)->obsoleted_by().empty()) {
131                         Gtk::TreeModel::iterator iter = model_->append();
132                         Gtk::TreeModel::Row row = *iter;
133                         row[cols_.name] = Glib::locale_to_utf8((*it)->name());
134                 }
135         combo_.set_active(current_selection);
136         internal_ = false;
137
138         // now that we've loaded something into the combobox, forget
139         // the initial fixed size and let GTK decide.
140         combo_.set_size_request(-1,-1);
141 }
142
143
144 void GLayoutBox::clear()
145 {
146         internal_ = true;
147         model_->clear();
148         internal_ = false;
149 }
150
151
152 void GLayoutBox::open()
153 {
154         combo_.popup();
155 }
156
157
158 void GLayoutBox::setEnabled(bool sensitive)
159 {
160         combo_.set_sensitive(sensitive);
161 }
162
163
164 void GLayoutBox::selected()
165 {
166         if (internal_)
167                 return;
168
169         Glib::ustring layoutGuiName = (*(combo_.get_active()))[cols_.name];
170
171         // we get two signal, one of them is empty and useless
172         if (layoutGuiName.empty())
173                 return;
174
175         layoutSelected(owner_, layoutGuiName);
176 }
177
178 } // namespace frontend
179 } // namespace lyx
180
181
182 Toolbars::ToolbarPtr make_toolbar(ToolbarBackend::Toolbar const & tbb,
183                                   LyXView & owner)
184 {
185         using lyx::frontend::GToolbar;
186         return Toolbars::ToolbarPtr(new GToolbar(tbb, owner));
187 }
188
189 namespace lyx {
190 namespace frontend {
191
192 GToolbar::GToolbar(ToolbarBackend::Toolbar const & tbb, LyXView & owner)
193         : owner_(dynamic_cast<GView &>(owner))
194 {
195         ToolbarBackend::item_iterator it = tbb.items.begin();
196         ToolbarBackend::item_iterator end = tbb.items.end();
197         for (; it != end; ++it)
198                 add(it->first, it->second);
199
200         toolbar_.set_toolbar_style(Gtk::TOOLBAR_ICONS);
201         toolbar_.show_all();
202
203         GView::Position const position = getPosition(tbb.flags);
204
205         if (position == GView::Left || position == GView::Right)
206                 toolbar_.set_orientation(Gtk::ORIENTATION_VERTICAL);
207
208         owner_.getBox(position).children().push_back(
209                 Gtk::Box_Helpers::Element(toolbar_, Gtk::PACK_SHRINK));
210
211         toolbar_.set_tooltips(true);
212 }
213
214 void GToolbar::add(FuncRequest const & func, string const & tooltip)
215 {
216         switch (func.action) {
217         case ToolbarBackend::SEPARATOR: {
218                 Gtk::SeparatorToolItem * space =
219                         Gtk::manage(new Gtk::SeparatorToolItem);
220                 toolbar_.append(*space);
221                 break;
222         }
223
224         case ToolbarBackend::MINIBUFFER:
225                 // Not supported yet.
226                 break;
227
228         case ToolbarBackend::LAYOUTS: {
229                 layout_.reset(new GLayoutBox(owner_, toolbar_, func));
230                 break;
231         }
232
233         default: {
234                 // choose an icon from the funcrequest
235                 Gtk::BuiltinStockID stockID = getGTKStockIcon(func);
236
237                 Glib::ustring tip = Glib::locale_to_utf8(tooltip);
238
239                 Gtk::ToolButton * toolbutton;
240                 if (stockID != Gtk::Stock::MISSING_IMAGE) {
241                         // Prefer stock gtk graphics
242                         Gtk::IconSize size(Gtk::ICON_SIZE_LARGE_TOOLBAR);
243                         Gtk::Image * image = Gtk::manage(new Gtk::Image(stockID, size));
244                         image->show();
245                         toolbutton = Gtk::manage(new Gtk::ToolButton(*image));
246                 } else {
247                         Glib::ustring xpmName =
248                                 Glib::locale_to_utf8(toolbarbackend.getIcon(func));
249                         Gtk::Image * image = Gtk::manage(new Gtk::Image(xpmName));
250                         image->show();
251                         toolbutton = Gtk::manage(new Gtk::ToolButton(*image));
252                 }
253
254                 // This code is putting a function reference into the GObject data field
255                 // named gToolData.  That's how we know how to update the status of the
256                 // toolitem later.
257                 toolbutton->set_data(gToolData,
258                         reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
259
260                 toolbutton->set_tooltip(*toolbar_.get_tooltips_object(),tip);
261
262                 toolbutton->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,
263                         &GToolbar::clicked), FuncRequest(func)));
264                 toolbar_.append(*toolbutton);
265                 break;
266         }
267
268         }
269 }
270
271
272 void GToolbar::clicked(FuncRequest func)
273 {
274         owner_.getLyXFunc().dispatch(func);
275 }
276
277
278 void GToolbar::hide(bool)
279 {
280         toolbar_.hide();
281 }
282
283
284 void GToolbar::show(bool)
285 {
286         toolbar_.show();
287 }
288
289
290 void GToolbar::update()
291 {
292         int const items = toolbar_.get_n_items();
293
294         for (int i = 0; i < items; ++i) {
295                 Gtk::ToolItem * item = toolbar_.get_nth_item(i);
296
297                 FuncRequest const * func = reinterpret_cast<FuncRequest *>(
298                         item->get_data(gToolData));
299                 if (func) {
300                         FuncStatus const status = owner_.getLyXFunc().getStatus(*func);
301                         item->set_sensitive(status.enabled());
302                 }
303         }
304 }
305
306 } // namespace frontend
307 } // namespace lyx