]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GToolbar.C
e79005d25de115ce880fbf14232c23abd5121345
[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                         // ENCODING, FIXME: are the backend layout strings really 
134                         // in locale encoding?
135                         row[cols_.name] = Glib::locale_to_utf8((*it)->name());
136                 }
137         combo_.set_active(current_selection);
138         internal_ = false;
139
140         // now that we've loaded something into the combobox, forget
141         // the initial fixed size and let GTK decide.
142         combo_.set_size_request(-1,-1);
143 }
144
145
146 void GLayoutBox::clear()
147 {
148         internal_ = true;
149         model_->clear();
150         internal_ = false;
151 }
152
153
154 void GLayoutBox::open()
155 {
156         combo_.popup();
157 }
158
159
160 void GLayoutBox::setEnabled(bool sensitive)
161 {
162         combo_.set_sensitive(sensitive);
163 }
164
165
166 void GLayoutBox::selected()
167 {
168         if (internal_)
169                 return;
170
171         Glib::ustring layoutGuiName = (*(combo_.get_active()))[cols_.name];
172
173         // we get two signal, one of them is empty and useless
174         if (layoutGuiName.empty())
175                 return;
176
177         layoutSelected(owner_, layoutGuiName);
178 }
179
180 } // namespace frontend
181 } // namespace lyx
182
183
184 Toolbars::ToolbarPtr make_toolbar(ToolbarBackend::Toolbar const & tbb,
185                                   LyXView & owner)
186 {
187         using lyx::frontend::GToolbar;
188         return Toolbars::ToolbarPtr(new GToolbar(tbb, owner));
189 }
190
191 namespace lyx {
192 namespace frontend {
193
194 GToolbar::GToolbar(ToolbarBackend::Toolbar const & tbb, LyXView & owner)
195         : owner_(dynamic_cast<GView &>(owner))
196 {
197         ToolbarBackend::item_iterator it = tbb.items.begin();
198         ToolbarBackend::item_iterator end = tbb.items.end();
199         for (; it != end; ++it)
200                 add(it->first, it->second);
201
202         toolbar_.set_toolbar_style(Gtk::TOOLBAR_ICONS);
203         toolbar_.show_all();
204
205         GView::Position const position = getPosition(tbb.flags);
206
207         if (position == GView::Left || position == GView::Right)
208                 toolbar_.set_orientation(Gtk::ORIENTATION_VERTICAL);
209
210         owner_.getBox(position).children().push_back(
211                 Gtk::Box_Helpers::Element(toolbar_, Gtk::PACK_SHRINK));
212
213         toolbar_.set_tooltips(true);
214 }
215
216 void GToolbar::add(FuncRequest const & func, lyx::docstring const & tooltip)
217 {
218         switch (func.action) {
219         case ToolbarBackend::SEPARATOR: {
220                 Gtk::SeparatorToolItem * space =
221                         Gtk::manage(new Gtk::SeparatorToolItem);
222                 toolbar_.append(*space);
223                 break;
224         }
225
226         case ToolbarBackend::MINIBUFFER:
227                 // Not supported yet.
228                 break;
229
230         case ToolbarBackend::LAYOUTS: {
231                 layout_.reset(new GLayoutBox(owner_, toolbar_, func));
232                 break;
233         }
234
235         default: {
236                 // ENCODING, FIXME - we assume tooltips are in locale.  No 
237                 // idea whether they actually are.
238                 // FIXME UNICODE 2: tooltip is a docstring now...
239                 Glib::ustring tip = Glib::locale_to_utf8(tooltip);
240
241                 Gtk::ToolButton * toolbutton;
242                 Gtk::Image * image = NULL;
243                 image = getGTKIcon(func, Gtk::ICON_SIZE_LARGE_TOOLBAR);
244                 if (!image) {
245                         // ENCODING, FIXME: does Gtk::Image constructer really want
246                         // filename in UTF-8 rather than filesystem encoding?
247                         // This probably won't break when filenames are ASCII.
248                         Glib::ustring xpmName =
249                                 Glib::locale_to_utf8(toolbarbackend.getIcon(func));
250                         if (xpmName.find("unknown.xpm") == Glib::ustring::npos) {
251                                 image = Gtk::manage(new Gtk::Image(xpmName));
252                         }
253                 }
254
255                 image->show();
256                 toolbutton = Gtk::manage(new Gtk::ToolButton(*image));
257                 // This code is putting a function reference into the GObject data field
258                 // named gToolData.  That's how we know how to update the status of the
259                 // toolitem later.
260                 toolbutton->set_data(gToolData,
261                         reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
262
263                 toolbutton->set_tooltip(*toolbar_.get_tooltips_object(),tip);
264
265                 toolbutton->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,
266                         &GToolbar::clicked), FuncRequest(func)));
267                 toolbar_.append(*toolbutton);
268                 break;
269         }
270
271         }
272 }
273
274
275 void GToolbar::clicked(FuncRequest func)
276 {
277         owner_.dispatch(func);
278 }
279
280
281 void GToolbar::hide(bool)
282 {
283         toolbar_.hide();
284 }
285
286
287 void GToolbar::show(bool)
288 {
289         toolbar_.show();
290 }
291
292
293 void GToolbar::update()
294 {
295         int const items = toolbar_.get_n_items();
296
297         for (int i = 0; i < items; ++i) {
298                 Gtk::ToolItem * item = toolbar_.get_nth_item(i);
299
300                 FuncRequest const * func = reinterpret_cast<FuncRequest *>(
301                         item->get_data(gToolData));
302                 if (func) {
303                         FuncStatus const status = lyx::getStatus(*func);
304                         item->set_sensitive(status.enabled());
305                 }
306         }
307 }
308
309 } // namespace frontend
310 } // namespace lyx