1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * Pan - A Newsreader for Gtk+
4  * Copyright (C) 2002-2006  Charles Kerr <charles@rebelbase.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include <config.h>
21 #include <glib/gi18n.h>
22 #include <glib.h>
23 #include "gtk-compat.h"
24 #ifdef HAVE_GTKSPELL
25 #include <enchant/enchant.h>
26 #endif
27 #include <pan/general/debug.h>
28 #include <pan/general/macros.h>
29 #include <pan/data/data.h>
30 #include "e-charset-combo-box.h"
31 #include "group-prefs-dialog.h"
32 #include "hig.h"
33 #include "pad.h"
34 #include "pan-file-entry.h"
35 #include "gtk-compat.h"
36 #include "pan-colors.h"
37 
38 #include <iostream>
39 
40 using namespace pan;
41 
42 
43 namespace
44 {
45 
46   struct Langs
47   {
48     GList* langs;
49   };
50 
51   static void
dict_describe_cb(const char * const lang_tag,const char * const provider_name,const char * const provider_desc,const char * const provider_file,void * user_data)52   dict_describe_cb(const char * const lang_tag,
53 		 const char * const provider_name,
54 		 const char * const provider_desc,
55 		 const char * const provider_file,
56 		 void * user_data)
57   {
58     Langs *langs = (Langs *)user_data;
59     langs->langs = g_list_insert_sorted(langs->langs, g_strdup(lang_tag), (GCompareFunc) strcmp);
60   }
61 
62 #ifdef HAVE_GTKSPELL
63   static EnchantBroker *broker = NULL;
64   static GList *langs = NULL;
65   static GtkTextView* view = NULL;
66   Langs l;
67 #endif
init_spell()68   void init_spell()
69   {
70 #ifdef HAVE_GTKSPELL
71     view = GTK_TEXT_VIEW(gtk_text_view_new());
72     broker = enchant_broker_init();
73     l.langs = langs;
74     enchant_broker_list_dicts(broker, dict_describe_cb, &l);
75 #endif
76   }
77 
deinit_spell()78   void deinit_spell()
79   {
80 #ifdef HAVE_GTKSPELL
81     if (view) g_object_ref_sink(view);
82     if (broker) enchant_broker_free(broker);
83 #endif
84   }
85 
delete_dialog(gpointer castme)86   void delete_dialog (gpointer castme)
87   {
88     delete static_cast<GroupPrefsDialog*>(castme);
89   }
90 }
91 
92 void
save_from_gui()93 GroupPrefsDialog :: save_from_gui ()
94 {
95   // charset...
96   const char * tmp = e_charset_combo_box_get_charset (E_CHARSET_COMBO_BOX(_charset));
97   foreach_const (quarks_v, _groups, it)
98     _group_prefs.set_string (*it, "character-encoding", tmp);
99 
100   // posting profile...
101   std::string profile;
102   if (gtk_widget_get_sensitive (_profile)) {
103     char * pch (gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT(_profile)));
104     foreach_const (quarks_v, _groups, it)
105       _group_prefs.set_string (*it, "posting-profile", pch);
106     g_free (pch);
107   }
108 
109   // save path...
110   const char * pch (file_entry_get (_save_path));
111   foreach_const (quarks_v, _groups, it)
112     _group_prefs.set_string (*it, "default-group-save-path", pch);
113 
114   // spellchecker language
115 #ifdef HAVE_GTKSPELL
116   GtkTreeIter iter;
117   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX(_spellchecker_language), &iter))
118 		return;
119 
120   gchar* name(0);
121 	GtkTreeModel* model = gtk_combo_box_get_model (GTK_COMBO_BOX(_spellchecker_language));
122 	gtk_tree_model_get (model, &iter, 0, &name, -1);
123 
124   if (name)
125   {
126     foreach_const (quarks_v, _groups, it)
127 	  _group_prefs.set_string (*it, "spellcheck-language", name);
128     g_free(name);
129   }
130 #endif
131 
132   _group_prefs.save () ;
133 
134 }
135 
136 void
response_cb(GtkDialog * dialog,int,gpointer user_data)137 GroupPrefsDialog :: response_cb (GtkDialog  * dialog,
138                                  int          ,
139                                  gpointer     user_data)
140 {
141   static_cast<GroupPrefsDialog*>(user_data)->save_from_gui ();
142   gtk_widget_destroy (GTK_WIDGET(dialog));
143 }
144 
145 namespace
146 {
147   GtkWidget*
create_profiles_combo_box(const Data & data,const quarks_v & groups,const GroupPrefs & group_prefs)148   create_profiles_combo_box (const Data       & data,
149                              const quarks_v   & groups,
150                              const GroupPrefs & group_prefs)
151   {
152     GtkWidget * w = gtk_combo_box_text_new ();
153     GtkComboBoxText * combo (GTK_COMBO_BOX_TEXT (w));
154 
155     typedef std::set<std::string> unique_strings_t;
156     const unique_strings_t profiles (data.get_profile_names ());
157 
158     if (profiles.empty())
159     {
160       gtk_combo_box_text_append_text (combo, _("No Profiles defined in Edit → Posting Profiles."));
161       gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
162       gtk_widget_set_sensitive (w, false);
163     }
164     else
165     {
166       const std::string s (group_prefs.get_string (groups[0], "posting-profile", ""));
167       int i(0), sel_index (0);
168       foreach_const (unique_strings_t, profiles, it) {
169         if (*it == s)
170           sel_index = i;
171         ++i;
172         gtk_combo_box_text_append_text (combo, it->c_str());
173       }
174       gtk_combo_box_set_active (GTK_COMBO_BOX(combo), sel_index);
175     }
176 
177     return w;
178   }
179 
180   GtkWidget*
create_spellcheck_combo_box(const Quark & group,const GroupPrefs & group_prefs)181   create_spellcheck_combo_box ( const Quark      & group,
182                                 const GroupPrefs & group_prefs)
183   {
184     GtkWidget * w(NULL);
185 
186 #ifdef HAVE_GTKSPELL
187     init_spell();
188     deinit_spell();
189 
190     GtkTreeModel *model;
191     GtkListStore * store = gtk_list_store_new (1, G_TYPE_STRING);
192     GtkTreeIter iter, storeit;
193     bool valid(false);
194 
195 
196     std::string lang = group_prefs.get_string(group, "spellcheck-language","");
197 
198     while (l.langs)
199     {
200       gchar* data = (gchar*)l.langs->data;
201       if (data)
202       {
203         gtk_list_store_append (store, &iter);
204         gtk_list_store_set (store, &iter, 0, data, -1);
205         if (g_strcmp0 ((const char*)l.langs->data,lang.c_str())==0) { storeit = iter; valid=true; }
206       }
207       l.langs = l.langs->next;
208     }
209     model = GTK_TREE_MODEL(store);
210     w = gtk_combo_box_new_with_model (model);
211     g_object_unref(store);
212 
213     GtkCellRenderer * renderer (gtk_cell_renderer_text_new ());
214     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (w), renderer, TRUE);
215     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (w), renderer, "text", 0, NULL);
216 
217     if (valid) gtk_combo_box_set_active_iter (GTK_COMBO_BOX(w), &storeit);
218 
219     if (l.langs) g_list_free(l.langs);
220 #endif
221     return w;
222   }
223 
224 //  void color_set_cb (GtkColorButton* b, gpointer p)
225 //  {
226 //    GroupPrefsDialog* dialog = static_cast<GroupPrefsDialog*>(p);
227 //	  GdkColor col;
228 //	  gtk_color_button_get_color (b, &col);
229 //	  dialog->_color = col;
230 //  }
231 
color_set_cb(GtkColorButton * b,gpointer p)232   void color_set_cb (GtkColorButton* b, gpointer p)
233   {
234     GroupPrefsDialog* dialog = static_cast<GroupPrefsDialog*>(p);
235     GdkColor val;
236     gtk_color_button_get_color (b, &val);
237     {
238       foreach_const (quarks_v, dialog->get_groups(), it)
239         dialog->get_prefs().set_group_color(*it, val);
240     }
241   }
242 
243 
new_color_button(const Quark & group,Prefs & prefs,GroupPrefs & gprefs,GroupPrefsDialog * dialog,GtkWidget * w)244   GtkWidget* new_color_button (const Quark& group, Prefs& prefs, GroupPrefs& gprefs, GroupPrefsDialog* dialog, GtkWidget* w)
245   {
246 
247     const PanColors& colors (PanColors::get());
248     const std::string& def_fg (colors.def_fg);
249     const std::string& fg (prefs.get_color_str("group-pane-color-fg", def_fg));
250     const GdkColor& val (gprefs.get_group_color (group, fg));
251 
252     GtkWidget * b = gtk_color_button_new_with_color (&val);
253     g_signal_connect (b, "color-set", G_CALLBACK(color_set_cb), dialog);
254 
255     return b;
256   }
257 
258 }
259 
260 
GroupPrefsDialog(Data & data,const quarks_v & groups,Prefs & prefs,GroupPrefs & group_prefs,GtkWindow * parent_window)261 GroupPrefsDialog :: GroupPrefsDialog (Data            & data,
262                                       const quarks_v  & groups,
263                                       Prefs           & prefs,
264                                       GroupPrefs      & group_prefs,
265                                       GtkWindow       * parent_window):
266   _groups (groups),
267   _prefs(prefs),
268   _group_prefs (group_prefs)
269 {
270 
271   GtkWidget * dialog = gtk_dialog_new_with_buttons (_("Pan: Group Preferences"),
272                                                     parent_window,
273                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
274                                                     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
275                                                     NULL);
276   gtk_window_set_role (GTK_WINDOW(dialog), "pan-group-dialog");
277   g_signal_connect (dialog, "response", G_CALLBACK(response_cb), this);
278   g_signal_connect_swapped (dialog, "destroy", G_CALLBACK(delete_dialog), this);
279 
280   int row (0);
281   GtkWidget *t, *w, *l;
282   t = HIG :: workarea_create ();
283 
284   char buf[512];
285   if (groups.size() != 1)
286     g_snprintf (buf, sizeof(buf), _("Properties for Groups"));
287   else
288     g_snprintf (buf, sizeof(buf), _("Properties for %s"), groups[0].c_str());
289 
290   HIG::workarea_add_section_title (t, &row, buf);
291     HIG :: workarea_add_section_spacer (t, row, 4);
292     w = _charset = e_charset_combo_box_new( );
293     const char* cs = _group_prefs.get_string (groups[0], "character-encoding", "UTF-8").c_str();
294     e_charset_combo_box_set_charset( E_CHARSET_COMBO_BOX(w), cs ? cs : "");
295 
296     HIG :: workarea_add_row (t, &row, _("Character _encoding:"), w);
297 
298     w = _save_path = file_entry_new (_("Directory for Saving Attachments"));
299     char * pch = g_build_filename (g_get_home_dir(), "News", NULL);
300     std::string dir (_prefs.get_string ("default-save-attachments-path", pch));
301     if (groups.size() == 1)
302       dir = _group_prefs.get_string (groups[0], "default-group-save-path", dir);
303     g_free (pch);
304     file_entry_set (w, dir.c_str());
305 
306     HIG :: workarea_add_row (t, &row, _("Directory for _saving attachments:"), w);
307     w = _profile = create_profiles_combo_box (data, groups, group_prefs);
308     l = HIG :: workarea_add_row (t, &row, _("Posting _profile:"), w);
309 
310     gtk_widget_set_sensitive (l, gtk_widget_get_sensitive(w));
311 #ifdef HAVE_GTKSPELL
312     w = _spellchecker_language = create_spellcheck_combo_box ( groups[0], group_prefs);
313     HIG :: workarea_add_row (t, &row, _("Spellchecker _language:"), w);
314 #endif
315     w = _group_color = new_color_button (groups[0], _prefs, _group_prefs, this, dialog);
316     HIG :: workarea_add_row(t, &row, _("Group color:"), w);
317 
318   gtk_box_pack_start ( GTK_BOX( gtk_dialog_get_content_area( GTK_DIALOG( dialog))), t, true, true, 0);
319   _root = dialog;
320   gtk_widget_show_all (t);
321 
322 }
323