1 /* gobby - A GTKmm driven libobby client
2 * Copyright (C) 2005 0x539 dev group
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cstring>
20 #include <stdexcept>
21 #include <gtkmm/stock.h>
22 #include <gtkmm/messagedialog.h>
23
24 #include <obby/format_string.hpp>
25
26 #include "common.hpp"
27 #include "preferencesdialog.hpp"
28
29 namespace
30 {
lang_sort(gconstpointer first,gconstpointer second)31 gint lang_sort(gconstpointer first, gconstpointer second)
32 {
33 return strcmp(
34 gtk_source_language_get_name(GTK_SOURCE_LANGUAGE(first)),
35 gtk_source_language_get_name(GTK_SOURCE_LANGUAGE(second))
36 );
37 }
38
rownum_to_toolstyle(int rownum)39 Gtk::ToolbarStyle rownum_to_toolstyle(int rownum)
40 {
41 switch(rownum)
42 {
43 case 0: return Gtk::TOOLBAR_TEXT;
44 case 1: return Gtk::TOOLBAR_ICONS;
45 case 3: return Gtk::TOOLBAR_BOTH_HORIZ;
46 case 2: default: return Gtk::TOOLBAR_BOTH;
47 }
48 }
49 }
50
Page()51 Gobby::PreferencesDialog::Page::Page():
52 Gtk::Frame()
53 {
54 // Remove shadow - use the frame just as container
55 set_shadow_type(Gtk::SHADOW_NONE);
56 set_border_width(10);
57 }
58
59 #ifndef GTKMM_DISABLE_DEPRECATED
Editor(const Preferences & preferences,Gtk::Tooltips & tooltips)60 Gobby::PreferencesDialog::Editor::Editor(const Preferences& preferences,
61 Gtk::Tooltips& tooltips):
62 #else
63 Gobby::PreferencesDialog::Editor::Editor(const Preferences& preferences):
64 #endif
65 m_frame_tab(_("Tab Stops") ),
66 m_frame_indentation(_("Indentation") ),
67 m_frame_homeend(_("Home/End behaviour") ),
68 m_lbl_tab_width(_("Tab width:"), Gtk::ALIGN_RIGHT),
69 m_btn_tab_spaces(_("Insert spaces instead of tabs") ),
70 m_btn_indentation_auto(_("Enable automatic indentation") ),
71 m_btn_homeend_smart(_("Smart home/end") )
72 {
73 unsigned int tab_width = preferences.editor.tab_width;
74 bool tab_spaces = preferences.editor.tab_spaces;
75 bool indentation_auto = preferences.editor.indentation_auto;
76 bool homeend_smart = preferences.editor.homeend_smart;
77
78 m_ent_tab_width.set_range(1, 8);
79 m_ent_tab_width.set_value(tab_width);
80 m_ent_tab_width.set_increments(1, 1);
81
82 #ifndef GTKMM_DISABLE_DEPRECATED
83 // TODO: Improve this description
84 tooltips.set_tip(m_btn_homeend_smart,
85 _("With this option enabled, Home/End keys move to first/last "
86 "character before going to the start/end of the line.") );
87 #endif
88
89 m_box_tab_width.set_spacing(5);
90 m_box_tab_width.pack_start(m_lbl_tab_width, Gtk::PACK_SHRINK);
91 m_box_tab_width.pack_start(m_ent_tab_width, Gtk::PACK_EXPAND_WIDGET);
92
93 m_btn_tab_spaces.set_active(tab_spaces);
94 m_btn_indentation_auto.set_active(indentation_auto);
95 m_btn_homeend_smart.set_active(homeend_smart);
96
97 m_box_tab.set_spacing(5);
98 m_box_tab.set_border_width(5);
99 m_box_tab.pack_start(m_box_tab_width, Gtk::PACK_SHRINK);
100 m_box_tab.pack_start(m_btn_tab_spaces, Gtk::PACK_SHRINK);
101
102 m_box_indentation.set_spacing(5);
103 m_box_indentation.set_border_width(5);
104 m_box_indentation.pack_start(m_btn_indentation_auto, Gtk::PACK_SHRINK);
105
106 m_box_homeend.set_spacing(5);
107 m_box_homeend.set_border_width(5);
108 m_box_homeend.pack_start(m_btn_homeend_smart, Gtk::PACK_SHRINK);
109
110 m_frame_tab.add(m_box_tab);
111 m_frame_indentation.add(m_box_indentation);
112 m_frame_homeend.add(m_box_homeend);
113
114 m_box.set_spacing(5);
115 m_box.pack_start(m_frame_tab, Gtk::PACK_SHRINK);
116 m_box.pack_start(m_frame_indentation, Gtk::PACK_SHRINK);
117 m_box.pack_start(m_frame_homeend, Gtk::PACK_SHRINK);
118
119 add(m_box);
120 }
121
set(Preferences::Editor & editor) const122 void Gobby::PreferencesDialog::Editor::set(Preferences::Editor& editor) const
123 {
124 editor.tab_width = m_ent_tab_width.get_value_as_int();
125 editor.tab_spaces = m_btn_tab_spaces.get_active();
126 editor.indentation_auto = m_btn_indentation_auto.get_active();
127 editor.homeend_smart = m_btn_homeend_smart.get_active();
128 }
129
View(const Preferences & preferences)130 Gobby::PreferencesDialog::View::View(const Preferences& preferences):
131 m_frame_wrap(_("Text wrapping") ),
132 m_frame_linenum(_("Line numbers") ),
133 m_frame_curline(_("Current line") ),
134 m_frame_margin(_("Right margin") ),
135 m_frame_bracket(_("Bracket matching") ),
136 m_btn_wrap_text(_("Enable text wrapping") ),
137 m_btn_wrap_words(_("Do not split words over two lines") ),
138 m_btn_linenum_display(_("Display line numbers") ),
139 m_btn_curline_highlight(_("Highlight current line") ),
140 m_btn_margin_display(_("Display right margin") ),
141 m_lbl_margin_pos(_("Right margin at column:") ),
142 m_btn_bracket_highlight(_("Highlight matching bracket") )
143 {
144 bool wrap_text = preferences.view.wrap_text;
145 bool wrap_words = preferences.view.wrap_words;
146 bool linenum_display = preferences.view.linenum_display;
147 bool curline_highlight = preferences.view.curline_highlight;
148 bool margin_display = preferences.view.margin_display;
149 unsigned int margin_pos = preferences.view.margin_pos;
150 bool bracket_highlight = preferences.view.bracket_highlight;
151
152 m_btn_margin_display.signal_toggled().connect(
153 sigc::mem_fun(*this, &View::on_margin_display_toggled) );
154
155 m_ent_margin_pos.set_range(1, 1024);
156 m_ent_margin_pos.set_value(margin_pos);
157 m_ent_margin_pos.set_increments(1, 16);
158
159 m_btn_wrap_text.set_active(wrap_text);
160 m_btn_wrap_words.set_active(!wrap_words);
161 m_btn_linenum_display.set_active(linenum_display);
162 m_btn_curline_highlight.set_active(curline_highlight);
163 m_btn_margin_display.set_active(margin_display);
164 m_btn_bracket_highlight.set_active(bracket_highlight);
165
166 m_box_margin_pos.set_spacing(5);
167 m_box_margin_pos.pack_start(m_lbl_margin_pos, Gtk::PACK_SHRINK);
168 m_box_margin_pos.pack_start(m_ent_margin_pos, Gtk::PACK_EXPAND_WIDGET);
169 m_box_wrap.set_spacing(5);
170 m_box_wrap.set_border_width(5);
171 m_box_wrap.pack_start(m_btn_wrap_text, Gtk::PACK_SHRINK);
172 m_box_wrap.pack_start(m_btn_wrap_words, Gtk::PACK_SHRINK);
173
174 m_box_linenum.set_spacing(5);
175 m_box_linenum.set_border_width(5);
176 m_box_linenum.pack_start(m_btn_linenum_display, Gtk::PACK_SHRINK);
177
178 m_box_curline.set_spacing(5);
179 m_box_curline.set_border_width(5);
180 m_box_curline.pack_start(m_btn_curline_highlight, Gtk::PACK_SHRINK);
181
182 m_box_margin.set_spacing(5);
183 m_box_margin.set_border_width(5);
184 m_box_margin.pack_start(m_btn_margin_display, Gtk::PACK_SHRINK);
185 m_box_margin.pack_start(m_box_margin_pos, Gtk::PACK_SHRINK);
186
187 m_box_bracket.set_spacing(5);
188 m_box_bracket.set_border_width(5);
189 m_box_bracket.pack_start(m_btn_bracket_highlight, Gtk::PACK_SHRINK);
190
191 m_frame_wrap.add(m_box_wrap);
192 m_frame_linenum.add(m_box_linenum);
193 m_frame_curline.add(m_box_curline);
194 m_frame_margin.add(m_box_margin);
195 m_frame_bracket.add(m_box_bracket);
196
197 m_box.set_spacing(5);
198 m_box.pack_start(m_frame_wrap, Gtk::PACK_SHRINK);
199 m_box.pack_start(m_frame_linenum, Gtk::PACK_SHRINK);
200 m_box.pack_start(m_frame_curline, Gtk::PACK_SHRINK);
201 m_box.pack_start(m_frame_margin, Gtk::PACK_SHRINK);
202 m_box.pack_start(m_frame_bracket, Gtk::PACK_SHRINK);
203
204 add(m_box);
205 }
206
set(Preferences::View & view) const207 void Gobby::PreferencesDialog::View::set(Preferences::View& view) const
208 {
209 view.wrap_text = m_btn_wrap_text.get_active();
210 view.wrap_words = !m_btn_wrap_words.get_active();
211 view.linenum_display = m_btn_linenum_display.get_active();
212 view.curline_highlight = m_btn_curline_highlight.get_active();
213 view.margin_display = m_btn_margin_display.get_active();
214 view.margin_pos = m_ent_margin_pos.get_value_as_int();
215 view.bracket_highlight = m_btn_bracket_highlight.get_active();
216 }
217
on_margin_display_toggled()218 void Gobby::PreferencesDialog::View::on_margin_display_toggled()
219 {
220 m_box_margin_pos.set_sensitive(m_btn_margin_display.get_active() );
221 }
222
223 Gobby::PreferencesDialog::Appearance::
Appearance(const Gobby::Preferences & preferences)224 Appearance(const Gobby::Preferences& preferences):
225 m_frame_toolbar(_("Toolbar") ),
226 m_frame_windows(_("Windows") ),
227 m_btn_remember(_("Remember the positions and states") ),
228 m_btn_urgency_hint(
229 _("Highlight the window on incoming chat messages") )
230 {
231 Gtk::ToolbarStyle style = preferences.appearance.toolbar_show;
232 bool remember = preferences.appearance.remember;
233 bool urgency_hint = preferences.appearance.urgency_hint;
234
235 m_cmb_toolbar_style.append_text(_("Show text only") );
236 m_cmb_toolbar_style.append_text(_("Show icons only") );
237 m_cmb_toolbar_style.append_text(_("Show both icons and text") );
238 m_cmb_toolbar_style.append_text(_("Show text besides icons") );
239
240 switch(style)
241 {
242 case Gtk::TOOLBAR_TEXT: m_cmb_toolbar_style.set_active(0); break;
243 case Gtk::TOOLBAR_ICONS: m_cmb_toolbar_style.set_active(1); break;
244 case Gtk::TOOLBAR_BOTH: m_cmb_toolbar_style.set_active(2); break;
245 case Gtk::TOOLBAR_BOTH_HORIZ: m_cmb_toolbar_style.set_active(3); break;
246 default: break; // Avoids compiler warnings
247 }
248
249 m_box_toolbar.set_spacing(5);
250 m_box_toolbar.set_border_width(5);
251 m_box_toolbar.pack_start(m_cmb_toolbar_style, Gtk::PACK_SHRINK);
252
253 m_frame_toolbar.add(m_box_toolbar);
254
255 m_box_windows.set_spacing(5);
256 m_box_windows.set_border_width(5);
257 m_btn_remember.set_active(remember);
258 m_btn_urgency_hint.set_active(urgency_hint);
259 m_box_windows.pack_start(m_btn_remember, Gtk::PACK_SHRINK);
260 m_box_windows.pack_start(m_btn_urgency_hint, Gtk::PACK_SHRINK);
261
262 m_frame_windows.add(m_box_windows);
263
264 m_box.set_spacing(5);
265 m_box.pack_start(m_frame_toolbar, Gtk::PACK_SHRINK);
266 m_box.pack_start(m_frame_windows, Gtk::PACK_SHRINK);
267
268 add(m_box);
269 }
270
271 void Gobby::PreferencesDialog::Appearance::
set(Preferences::Appearance & appearance) const272 set(Preferences::Appearance& appearance) const
273 {
274 appearance.toolbar_show = rownum_to_toolstyle(
275 m_cmb_toolbar_style.get_active_row_number()
276 );
277
278 appearance.remember = m_btn_remember.get_active();
279 appearance.urgency_hint = m_btn_urgency_hint.get_active();
280 }
281
Font(const Preferences & preferences)282 Gobby::PreferencesDialog::Font::Font(const Preferences& preferences):
283 m_init_font(preferences.font.desc.to_string() )
284 {
285 // Call to set_font_name does not work before realization of the
286 // font selection widget
287 m_font_sel.signal_realize().connect(
288 sigc::mem_fun(*this, &Font::on_fontsel_realize)
289 );
290
291 add(m_font_sel);
292 }
293
on_fontsel_realize()294 void Gobby::PreferencesDialog::Font::on_fontsel_realize()
295 {
296 m_font_sel.set_font_name(m_init_font);
297 m_init_font.clear();
298 }
299
set(Preferences::Font & font) const300 void Gobby::PreferencesDialog::Font::set(Preferences::Font& font) const
301 {
302 if(m_init_font.empty() )
303 font.desc = Pango::FontDescription(m_font_sel.get_font_name());
304 else
305 font.desc = Pango::FontDescription(m_init_font);
306 }
307
Behaviour(const Preferences & preferences)308 Gobby::PreferencesDialog::Behaviour::Behaviour(const Preferences& preferences):
309 m_frame_documents(_("Document management") ),
310 m_btn_auto_open(_("Open new remotely-created documents automatically") )
311 {
312 bool auto_open = preferences.behaviour.auto_open_new_documents;
313
314 m_btn_auto_open.set_active(auto_open);
315 m_box_documents.set_spacing(5);
316 m_box_documents.set_border_width(5);
317 m_box_documents.pack_start(m_btn_auto_open, Gtk::PACK_SHRINK);
318 m_frame_documents.add(m_box_documents);
319
320 m_box.pack_start(m_frame_documents, Gtk::PACK_SHRINK);
321
322 add(m_box);
323 }
324
set(Preferences::Behaviour & preferences) const325 void Gobby::PreferencesDialog::Behaviour::set(
326 Preferences::Behaviour& preferences) const
327 {
328 preferences.auto_open_new_documents = m_btn_auto_open.get_active();
329 }
330
LanguageColumns()331 Gobby::PreferencesDialog::FileList::LanguageColumns::LanguageColumns()
332 {
333 add(language);
334 add(language_name);
335 }
336
FileColumns()337 Gobby::PreferencesDialog::FileList::FileColumns::FileColumns()
338 {
339 add(pattern);
340 add(mime_type);
341 add(language);
342 }
343
FileList(Gtk::Window & parent,const Preferences & preferences,GtkSourceLanguageManager * lang_mgr)344 Gobby::PreferencesDialog::FileList::FileList(Gtk::Window& parent,
345 const Preferences& preferences,
346 GtkSourceLanguageManager* lang_mgr):
347 m_parent(parent), m_lang_mgr(lang_mgr),
348 m_viewcol_pattern(_("Pattern"), file_columns.pattern),
349 m_viewcol_lang(_("Language"), m_renderer_lang),
350 m_viewcol_mimetype(_("Mime type"), file_columns.mime_type),
351 m_intro(
352 _("This is a list of all recognized file types"),
353 Gtk::ALIGN_LEFT
354 ),
355 m_hbox(Gtk::BUTTONBOX_END, 12),
356 m_btn_add(Gtk::Stock::ADD), m_btn_remove(Gtk::Stock::REMOVE),
357 m_lang_list(Gtk::ListStore::create(lang_columns) ),
358 m_file_list(Gtk::ListStore::create(file_columns) )
359 {
360 #ifdef WITH_GTKSOURCEVIEW2
361 GSList* languages = NULL;
362 const gchar* const* ids = gtk_source_language_manager_get_language_ids(lang_mgr);
363 if(ids != NULL)
364 {
365 for(const gchar* const* id = ids; *id != NULL; ++ id)
366 {
367 GtkSourceLanguage* language = gtk_source_language_manager_get_language(lang_mgr, *id);
368 if(gtk_source_language_get_hidden(language)) continue;
369
370 languages = g_slist_prepend(languages, language);
371 }
372 }
373 #else
374 const GSList* list =
375 gtk_source_languages_manager_get_available_languages(lang_mgr);
376 GSList* languages = g_slist_copy(const_cast<GSList*>(list));
377 #endif
378
379 languages = g_slist_sort(languages, &lang_sort);
380
381 for(GSList* iter = languages; iter != NULL; iter = iter->next)
382 {
383 Gtk::TreeIter tree_it = m_lang_list->append();
384 (*tree_it)[lang_columns.language] = GTK_SOURCE_LANGUAGE(iter->data);
385 (*tree_it)[lang_columns.language_name] =
386 gtk_source_language_get_name(GTK_SOURCE_LANGUAGE(iter->data));
387
388 m_lang_map[GTK_SOURCE_LANGUAGE(iter->data)] = tree_it;
389 }
390
391 g_slist_free(languages);
392
393 m_renderer_pattern = static_cast<Gtk::CellRendererText*>(
394 m_viewcol_pattern.get_first_cell_renderer()
395 );
396
397 m_renderer_mimetype = static_cast<Gtk::CellRendererText*>(
398 m_viewcol_mimetype.get_first_cell_renderer()
399 );
400
401 m_renderer_pattern->property_editable() = true;
402 m_renderer_pattern->signal_edited().connect(
403 sigc::mem_fun(*this, &FileList::on_pattern_edited)
404 );
405
406 m_renderer_mimetype->property_editable() = true;
407 m_renderer_mimetype->signal_edited().connect(
408 sigc::mem_fun(*this, &FileList::on_mimetype_edited)
409 );
410
411 m_renderer_lang.property_has_entry() = false;
412 m_renderer_lang.property_model() = m_lang_list;
413 m_renderer_lang.property_text_column() = 1;
414 m_renderer_lang.property_editable() = true;
415 m_renderer_lang.signal_edited().connect(
416 sigc::mem_fun(*this, &FileList::on_language_edited)
417 );
418
419 m_viewcol_lang.set_cell_data_func(
420 m_renderer_lang,
421 sigc::mem_fun(*this, &FileList::cell_data_file_language)
422 );
423
424
425 m_viewcol_pattern.set_sort_column(file_columns.pattern);
426 //m_viewcol_lang.set_sort_column(file_columns.language);
427 m_viewcol_mimetype.set_sort_column(file_columns.mime_type);
428
429 const Preferences::FileList& filelist = preferences.files;
430
431 for(Preferences::FileList::iterator iter = filelist.begin();
432 iter != filelist.end();
433 ++ iter)
434 {
435 /* std::list<Glib::ustring> mime_types =
436 iter.language()->get_mime_types();*/
437
438 Gtk::TreeIter tree_it = m_file_list->append();
439 (*tree_it)[file_columns.pattern] = iter.pattern();
440 set_language(tree_it, iter.language() );
441 }
442
443 m_view.set_model(m_file_list);
444
445 m_view.append_column(m_viewcol_pattern);
446 m_view.append_column(m_viewcol_lang);
447 //m_view.append_column(m_viewcol_mimetype);
448
449 m_view.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
450 m_view.get_selection()->signal_changed().connect(
451 sigc::mem_fun(*this, &FileList::on_selection_changed)
452 );
453
454 m_view.set_rules_hint(true);
455
456 m_btn_add.signal_clicked().connect(
457 sigc::mem_fun(*this, &FileList::on_file_add)
458 );
459
460 m_btn_remove.signal_clicked().connect(
461 sigc::mem_fun(*this, &FileList::on_file_remove)
462 );
463
464 m_hbox.add(m_btn_remove);
465 m_hbox.add(m_btn_add);
466
467 m_wnd.add(m_view);
468 m_wnd.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
469 m_wnd.set_shadow_type(Gtk::SHADOW_IN);
470
471 m_vbox.pack_start(m_intro, Gtk::PACK_SHRINK);
472 m_vbox.pack_start(m_wnd, Gtk::PACK_EXPAND_WIDGET);
473 m_vbox.pack_start(m_hbox, Gtk::PACK_SHRINK);
474 m_vbox.set_spacing(8);
475
476 add(m_vbox);
477
478 on_selection_changed();
479 }
480
set(Preferences::FileList & files) const481 void Gobby::PreferencesDialog::FileList::set(Preferences::FileList& files) const
482 {
483 Gtk::TreeNodeChildren children = m_file_list->children();
484 for(Gtk::TreeIter iter = children.begin();
485 iter != children.end();
486 ++ iter)
487 {
488 Gtk::TreeIter lang_it = (*iter)[file_columns.language];
489 files.add(
490 (*iter)[file_columns.pattern],
491 (*lang_it)[lang_columns.language]
492 );
493 }
494 }
495
496 void Gobby::PreferencesDialog::FileList::
cell_data_file_language(Gtk::CellRenderer * renderer,const Gtk::TreeIter & iter)497 cell_data_file_language(Gtk::CellRenderer* renderer,
498 const Gtk::TreeIter& iter)
499 {
500 Gtk::TreeIter lang_it = (*iter)[file_columns.language];
501 static_cast<Gtk::CellRendererText*>(renderer)->property_text() =
502 (*lang_it)[lang_columns.language_name];
503 }
504
505 void Gobby::PreferencesDialog::FileList::
on_pattern_edited(const Glib::ustring & path,const Glib::ustring & new_text)506 on_pattern_edited(const Glib::ustring& path,
507 const Glib::ustring& new_text)
508 {
509 if(new_text.empty() )
510 {
511 Gtk::MessageDialog dlg(
512 m_parent,
513 _("Pattern must not be empty."),
514 false,
515 Gtk::MESSAGE_ERROR,
516 Gtk::BUTTONS_OK,
517 true
518 );
519
520 dlg.run();
521
522 // TODO: Take iterator at beginning and remove here back to
523 // path to avoid borkage
524 /*m_view.set_cursor(
525 Gtk::TreePath(path),
526 m_viewcol_pattern,
527 true
528 );*/
529 }
530 else
531 {
532 Gtk::TreeIter iter = m_file_list->get_iter(Gtk::TreePath(path));
533 (*iter)[file_columns.pattern] = new_text;
534 }
535 }
536
537 void Gobby::PreferencesDialog::FileList::
on_mimetype_edited(const Glib::ustring & path,const Glib::ustring & new_text)538 on_mimetype_edited(const Glib::ustring& path,
539 const Glib::ustring& new_text)
540 {
541 #ifdef WITH_GTKSOURCEVIEW2
542 const gchar* const* ids = gtk_source_language_manager_get_language_ids(m_lang_mgr);
543
544 GtkSourceLanguage* lang = NULL;
545
546 if(ids != NULL)
547 {
548 for(const gchar* const* id = ids; *id != NULL; ++ id)
549 {
550 GtkSourceLanguage* language = gtk_source_language_manager_get_language(m_lang_mgr, *id);
551 if(gtk_source_language_get_hidden(language)) continue;
552
553 gchar** mime_types = gtk_source_language_get_mime_types(language);
554 for(gchar** mime_type = mime_types; *mime_type != NULL; ++ mime_type)
555 {
556 if(strcmp(*mime_type, new_text.c_str()) == 0)
557 {
558 lang = language;
559 break;
560 }
561 }
562
563 g_strfreev(mime_types);
564 if(lang != NULL) break;
565 }
566 }
567 #else
568 GtkSourceLanguage* lang =
569 gtk_source_languages_manager_get_language_from_mime_type(
570 m_lang_mgr, new_text.c_str());
571 #endif
572
573 if(!lang)
574 {
575 obby::format_string str(
576 _("There is no language with the mime type '%0%'.")
577 );
578
579 str << new_text.raw();
580
581 Gtk::MessageDialog dlg(
582 m_parent,
583 str.str(),
584 false,
585 Gtk::MESSAGE_ERROR,
586 Gtk::BUTTONS_OK,
587 true
588 );
589
590 dlg.run();
591 }
592 else
593 {
594 set_language(m_file_list->get_iter(Gtk::TreePath(path)), lang);
595 }
596 }
597
598 void Gobby::PreferencesDialog::FileList::
on_language_edited(const Glib::ustring & path,const Glib::ustring & new_text)599 on_language_edited(const Glib::ustring& path,
600 const Glib::ustring& new_text)
601 {
602 // We do not get an iterator/path/whatever that points to the
603 // chosen language in the language list.
604 GtkSourceLanguage* lang = NULL;
605 Gtk::TreeNodeChildren children = m_lang_list->children();
606
607 for(Gtk::TreeIter iter = children.begin();
608 iter != children.end();
609 ++ iter)
610 {
611 if( (*iter)[lang_columns.language_name] == new_text)
612 {
613 lang = (*iter)[lang_columns.language];
614 break;
615 }
616 }
617
618 if(!lang)
619 {
620 // The language must exist since we added all available
621 // languages to that list
622 throw std::logic_error(
623 "Gobby::PreferencesDialog::FileList::"
624 "on_language_edited:\n"
625 "Chosen language is not in language list"
626 );
627 }
628
629 set_language(m_file_list->get_iter(Gtk::TreePath(path)), lang);
630 }
631
on_selection_changed()632 void Gobby::PreferencesDialog::FileList::on_selection_changed()
633 {
634 std::list<Gtk::TreePath> list =
635 m_view.get_selection()->get_selected_rows();
636
637 m_btn_remove.set_sensitive(list.begin() != list.end() );
638 }
639
on_file_add()640 void Gobby::PreferencesDialog::FileList::on_file_add()
641 {
642 Gtk::TreeIter iter = m_file_list->append();
643 set_language(iter, m_lang_map.begin()->first);
644
645 m_view.set_cursor(
646 m_file_list->get_path(iter),
647 m_viewcol_pattern,
648 true
649 );
650 }
651
on_file_remove()652 void Gobby::PreferencesDialog::FileList::on_file_remove()
653 {
654 std::list<Gtk::TreePath> list =
655 m_view.get_selection()->get_selected_rows();
656
657 std::list<Gtk::TreeIter> iter_list;
658
659 // Path offsets get borked when removing multiple rows, so we
660 // convert all paths to iterators before
661 for(std::list<Gtk::TreePath>::const_iterator iter = list.begin();
662 iter != list.end();
663 ++ iter)
664 {
665 iter_list.push_back(m_file_list->get_iter(*iter) );
666 }
667
668 for(std::list<Gtk::TreeIter>::const_iterator iter = iter_list.begin();
669 iter != iter_list.end();
670 ++ iter)
671 {
672 m_file_list->erase(*iter);
673 }
674 }
675
set_language(const Gtk::TreeIter & row,GtkSourceLanguage * lang)676 void Gobby::PreferencesDialog::FileList::set_language(const Gtk::TreeIter& row,
677 GtkSourceLanguage* lang)
678 {
679 map_type::const_iterator lang_it = m_lang_map.find(lang);
680 if(lang_it == m_lang_map.end() )
681 {
682 throw std::logic_error(
683 "Gobby::PreferencesDialog::FileList::set_language:\n"
684 "Given language is not in language map"
685 );
686 }
687
688 (*row)[file_columns.language] = lang_it->second;
689 #ifdef WITH_GTKSOURCEVIEW2
690 gchar** mime_types = gtk_source_language_get_mime_types(lang);
691
692 if(mime_types && *mime_types)
693 (*row)[file_columns.mime_type] = *mime_types;
694
695 g_strfreev(mime_types);
696 #else
697 GSList* mime_types = gtk_source_language_get_mime_types(lang);
698 for(GSList* cur = mime_types; cur != NULL; cur = cur->next)
699 {
700 if(cur == mime_types)
701 (*row)[file_columns.mime_type] =
702 static_cast<gchar*>(cur->data);
703 g_free(cur->data);
704 }
705 g_slist_free(mime_types);
706 #endif
707 }
708
PreferencesDialog(Gtk::Window & parent,const Preferences & preferences,GtkSourceLanguageManager * lang_mgr,bool local)709 Gobby::PreferencesDialog::PreferencesDialog(Gtk::Window& parent,
710 const Preferences& preferences,
711 GtkSourceLanguageManager* lang_mgr,
712 bool local)
713 : Gtk::Dialog(_("Preferences"), parent, true),
714 #ifndef GTKMM_DISABLE_DEPRECATED
715 m_page_editor(preferences, m_tooltips),
716 #else
717 m_page_editor(preferences),
718 #endif
719 m_page_view(preferences),
720 m_page_appearance(preferences),
721 m_page_font(preferences),
722 m_page_behaviour(preferences),
723 m_page_files(*this, preferences, lang_mgr)
724 {
725 m_notebook.append_page(m_page_editor, _("Editor") );
726 m_notebook.append_page(m_page_view, _("View") );
727
728 // Appearance only affects the global Gobby window
729 if(!local) m_notebook.append_page(m_page_appearance, _("Appearance") );
730 m_notebook.append_page(m_page_font, _("Font") );
731 if(!local) m_notebook.append_page(m_page_behaviour, _("Behaviour") );
732 if(!local) m_notebook.append_page(m_page_files, _("Files") );
733
734 get_vbox()->set_spacing(5);
735 get_vbox()->pack_start(m_notebook, Gtk::PACK_EXPAND_WIDGET);
736
737 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
738 add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
739
740 set_border_width(10);
741 set_default_size(350, 400);
742 //set_resizable(false);
743
744 show_all();
745 }
746
set(Preferences & preferences) const747 void Gobby::PreferencesDialog::set(Preferences& preferences) const
748 {
749 m_page_editor.set(preferences.editor);
750 m_page_view.set(preferences.view);
751 m_page_appearance.set(preferences.appearance);
752 m_page_font.set(preferences.font);
753 m_page_behaviour.set(preferences.behaviour);
754 m_page_files.set(preferences.files);
755 }
756
757