OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/ui/gtk/options/languages_page_gtk.h" | |
6 | |
7 #include <set> | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/command_line.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/utf_string_conversions.h" | |
14 #include "chrome/browser/browser_process.h" | |
15 #include "chrome/browser/language_combobox_model.h" | |
16 #include "chrome/browser/language_order_table_model.h" | |
17 #include "chrome/browser/profiles/profile.h" | |
18 #include "chrome/browser/ui/gtk/gtk_util.h" | |
19 #include "chrome/common/chrome_switches.h" | |
20 #include "chrome/common/pref_names.h" | |
21 #include "chrome/common/spellcheck_common.h" | |
22 #include "grit/generated_resources.h" | |
23 #include "ui/base/gtk/gtk_signal.h" | |
24 #include "ui/base/l10n/l10n_util.h" | |
25 | |
26 namespace { | |
27 | |
28 const int kWrapWidth = 475; | |
29 | |
30 GtkWidget* NewComboboxFromModel(ui::ComboboxModel* model) { | |
31 GtkWidget* combobox = gtk_combo_box_new_text(); | |
32 int count = model->GetItemCount(); | |
33 for (int i = 0; i < count; ++i) | |
34 gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), | |
35 UTF16ToUTF8(model->GetItemAt(i)).c_str()); | |
36 return combobox; | |
37 } | |
38 | |
39 //////////////////////////////////////////////////////////////////////////////// | |
40 // AddLanguageDialog | |
41 | |
42 class AddLanguageDialog { | |
43 public: | |
44 AddLanguageDialog(Profile* profile, LanguagesPageGtk* delegate); | |
45 virtual ~AddLanguageDialog() {} | |
46 | |
47 private: | |
48 // Callback for dialog buttons. | |
49 CHROMEGTK_CALLBACK_1(AddLanguageDialog, void, OnResponse, int); | |
50 | |
51 // Callback for window destruction. | |
52 CHROMEGTK_CALLBACK_0(AddLanguageDialog, void, OnWindowDestroy); | |
53 | |
54 // The dialog window. | |
55 GtkWidget* dialog_; | |
56 | |
57 // The language chooser combobox. | |
58 GtkWidget* combobox_; | |
59 scoped_ptr<LanguageComboboxModel> accept_language_combobox_model_; | |
60 | |
61 // Used for call back to LanguagePageGtk that language has been selected. | |
62 LanguagesPageGtk* language_delegate_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(AddLanguageDialog); | |
65 }; | |
66 | |
67 AddLanguageDialog::AddLanguageDialog(Profile* profile, | |
68 LanguagesPageGtk* delegate) | |
69 : language_delegate_(delegate) { | |
70 GtkWindow* parent = GTK_WINDOW( | |
71 gtk_widget_get_toplevel(delegate->get_page_widget())); | |
72 | |
73 dialog_ = gtk_dialog_new_with_buttons( | |
74 l10n_util::GetStringUTF8( | |
75 IDS_FONT_LANGUAGE_SETTING_LANGUAGES_TAB_TITLE).c_str(), | |
76 parent, | |
77 static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), | |
78 GTK_STOCK_CANCEL, | |
79 GTK_RESPONSE_CANCEL, | |
80 GTK_STOCK_ADD, | |
81 GTK_RESPONSE_OK, | |
82 NULL); | |
83 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK); | |
84 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), | |
85 gtk_util::kContentAreaSpacing); | |
86 | |
87 const std::string app_locale = g_browser_process->GetApplicationLocale(); | |
88 std::vector<std::string> locale_codes; | |
89 l10n_util::GetAcceptLanguagesForLocale(app_locale, &locale_codes); | |
90 accept_language_combobox_model_.reset( | |
91 new LanguageComboboxModel(profile, locale_codes)); | |
92 combobox_ = NewComboboxFromModel(accept_language_combobox_model_.get()); | |
93 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_), 0); | |
94 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), combobox_); | |
95 | |
96 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); | |
97 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroyThunk), this); | |
98 | |
99 gtk_util::ShowDialog(dialog_); | |
100 } | |
101 | |
102 void AddLanguageDialog::OnResponse(GtkWidget* dialog, int response_id) { | |
103 if (response_id == GTK_RESPONSE_OK) { | |
104 int selected = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_)); | |
105 language_delegate_->OnAddLanguage( | |
106 accept_language_combobox_model_->GetLocaleFromIndex(selected)); | |
107 } | |
108 gtk_widget_destroy(dialog_); | |
109 } | |
110 | |
111 void AddLanguageDialog::OnWindowDestroy(GtkWidget* widget) { | |
112 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
113 } | |
114 | |
115 } // namespace | |
116 | |
117 //////////////////////////////////////////////////////////////////////////////// | |
118 // LanguagesPageGtk | |
119 | |
120 LanguagesPageGtk::LanguagesPageGtk(Profile* profile) | |
121 : OptionsPageBase(profile), | |
122 enable_autospellcorrect_checkbox_(NULL), | |
123 initializing_(true) { | |
124 Init(); | |
125 } | |
126 | |
127 LanguagesPageGtk::~LanguagesPageGtk() { | |
128 } | |
129 | |
130 void LanguagesPageGtk::Init() { | |
131 page_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); | |
132 gtk_container_set_border_width(GTK_CONTAINER(page_), | |
133 gtk_util::kContentAreaBorder); | |
134 | |
135 // Languages order controls. | |
136 GtkWidget* languages_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); | |
137 gtk_box_pack_start(GTK_BOX(page_), languages_vbox, | |
138 TRUE, TRUE, 0); | |
139 | |
140 GtkWidget* languages_instructions_label = gtk_label_new( | |
141 l10n_util::GetStringUTF8( | |
142 IDS_FONT_LANGUAGE_SETTING_LANGUAGES_INSTRUCTIONS).c_str()); | |
143 gtk_util::SetLabelWidth(languages_instructions_label, kWrapWidth); | |
144 gtk_box_pack_start(GTK_BOX(languages_vbox), languages_instructions_label, | |
145 FALSE, FALSE, 0); | |
146 | |
147 GtkWidget* languages_list_hbox = gtk_hbox_new(FALSE, | |
148 gtk_util::kControlSpacing); | |
149 gtk_box_pack_start(GTK_BOX(languages_vbox), languages_list_hbox, | |
150 TRUE, TRUE, 0); | |
151 | |
152 // Languages order tree. | |
153 language_order_store_ = gtk_list_store_new(COL_COUNT, | |
154 G_TYPE_STRING); | |
155 language_order_tree_ = gtk_tree_view_new_with_model( | |
156 GTK_TREE_MODEL(language_order_store_)); | |
157 g_object_unref(language_order_store_); | |
158 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(language_order_tree_), FALSE); | |
159 GtkTreeViewColumn* lang_column = gtk_tree_view_column_new_with_attributes( | |
160 "", | |
161 gtk_cell_renderer_text_new(), | |
162 "text", COL_LANG, | |
163 NULL); | |
164 gtk_tree_view_append_column(GTK_TREE_VIEW(language_order_tree_), lang_column); | |
165 language_order_selection_ = gtk_tree_view_get_selection( | |
166 GTK_TREE_VIEW(language_order_tree_)); | |
167 gtk_tree_selection_set_mode(language_order_selection_, | |
168 GTK_SELECTION_MULTIPLE); | |
169 g_signal_connect(language_order_selection_, "changed", | |
170 G_CALLBACK(OnSelectionChangedThunk), this); | |
171 GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL); | |
172 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), | |
173 GTK_POLICY_AUTOMATIC, | |
174 GTK_POLICY_AUTOMATIC); | |
175 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window), | |
176 GTK_SHADOW_ETCHED_IN); | |
177 gtk_container_add(GTK_CONTAINER(scroll_window), language_order_tree_); | |
178 gtk_box_pack_start(GTK_BOX(languages_list_hbox), scroll_window, | |
179 TRUE, TRUE, 0); | |
180 | |
181 language_order_table_model_.reset(new LanguageOrderTableModel); | |
182 language_order_table_adapter_.reset( | |
183 new gtk_tree::TableAdapter(this, language_order_store_, | |
184 language_order_table_model_.get())); | |
185 | |
186 // Languages order buttons. | |
187 GtkWidget* languages_buttons_vbox = gtk_vbox_new(FALSE, | |
188 gtk_util::kControlSpacing); | |
189 gtk_box_pack_start(GTK_BOX(languages_list_hbox), languages_buttons_vbox, | |
190 FALSE, FALSE, 0); | |
191 | |
192 add_button_ = gtk_button_new_with_label(l10n_util::GetStringUTF8( | |
193 IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_ADD_BUTTON_LABEL).c_str()); | |
194 g_signal_connect(add_button_, "clicked", | |
195 G_CALLBACK(OnAddButtonClickedThunk), this); | |
196 gtk_box_pack_start(GTK_BOX(languages_buttons_vbox), add_button_, | |
197 FALSE, FALSE, 0); | |
198 | |
199 std::string remove_button_text = l10n_util::GetStringUTF8( | |
200 IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_REMOVE_BUTTON_LABEL); | |
201 remove_button_ = gtk_button_new_with_label(remove_button_text.c_str()); | |
202 g_signal_connect(remove_button_, "clicked", | |
203 G_CALLBACK(OnRemoveButtonClickedThunk), this); | |
204 gtk_box_pack_start(GTK_BOX(languages_buttons_vbox), remove_button_, | |
205 FALSE, FALSE, 0); | |
206 | |
207 std::string move_up_button_text = l10n_util::GetStringUTF8( | |
208 IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_MOVEUP_BUTTON_LABEL); | |
209 move_up_button_ = gtk_button_new_with_label(move_up_button_text.c_str()); | |
210 g_signal_connect(move_up_button_, "clicked", | |
211 G_CALLBACK(OnMoveUpButtonClickedThunk), this); | |
212 gtk_box_pack_start(GTK_BOX(languages_buttons_vbox), move_up_button_, | |
213 FALSE, FALSE, 0); | |
214 | |
215 std::string move_down_button_text = l10n_util::GetStringUTF8( | |
216 IDS_FONT_LANGUAGE_SETTING_LANGUAGES_SELECTOR_MOVEDOWN_BUTTON_LABEL); | |
217 move_down_button_ = gtk_button_new_with_label(move_down_button_text.c_str()); | |
218 g_signal_connect(move_down_button_, "clicked", | |
219 G_CALLBACK(OnMoveDownButtonClickedThunk), this); | |
220 gtk_box_pack_start(GTK_BOX(languages_buttons_vbox), move_down_button_, | |
221 FALSE, FALSE, 0); | |
222 | |
223 // Spell checker controls. | |
224 GtkWidget* spellchecker_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); | |
225 gtk_box_pack_start(GTK_BOX(page_), spellchecker_vbox, | |
226 FALSE, FALSE, 0); | |
227 | |
228 enable_spellchecking_checkbox_ = gtk_check_button_new_with_label( | |
229 l10n_util::GetStringUTF8(IDS_OPTIONS_ENABLE_SPELLCHECK).c_str()); | |
230 g_signal_connect(enable_spellchecking_checkbox_, "toggled", | |
231 G_CALLBACK(OnEnableSpellCheckingToggledThunk), this); | |
232 gtk_box_pack_start(GTK_BOX(spellchecker_vbox), enable_spellchecking_checkbox_, | |
233 FALSE, FALSE, 0); | |
234 | |
235 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
236 if (command_line.HasSwitch(switches::kExperimentalSpellcheckerFeatures)) { | |
237 enable_autospellcorrect_checkbox_ = gtk_check_button_new_with_label( | |
238 l10n_util::GetStringUTF8( | |
239 IDS_OPTIONS_ENABLE_AUTO_SPELL_CORRECTION).c_str()); | |
240 g_signal_connect(enable_autospellcorrect_checkbox_, "toggled", | |
241 G_CALLBACK(OnEnableAutoSpellCheckingToggledThunk), this); | |
242 gtk_box_pack_start(GTK_BOX(spellchecker_vbox), | |
243 enable_autospellcorrect_checkbox_, FALSE, FALSE, 0); | |
244 } | |
245 | |
246 std::vector<std::string> spell_check_languages; | |
247 SpellCheckCommon::SpellCheckLanguages(&spell_check_languages); | |
248 dictionary_language_model_.reset(new LanguageComboboxModel(profile(), | |
249 spell_check_languages)); | |
250 dictionary_language_combobox_ = NewComboboxFromModel( | |
251 dictionary_language_model_.get()); | |
252 g_signal_connect(dictionary_language_combobox_, "changed", | |
253 G_CALLBACK(OnDictionaryLanguageChangedThunk), this); | |
254 GtkWidget* dictionary_language_control = | |
255 gtk_util::CreateLabeledControlsGroup(NULL, | |
256 l10n_util::GetStringUTF8( | |
257 IDS_OPTIONS_CHROME_DICTIONARY_LANGUAGE).c_str(), | |
258 dictionary_language_combobox_, | |
259 NULL); | |
260 gtk_box_pack_start(GTK_BOX(spellchecker_vbox), dictionary_language_control, | |
261 FALSE, FALSE, 0); | |
262 | |
263 // Initialize. | |
264 accept_languages_.Init(prefs::kAcceptLanguages, | |
265 profile()->GetPrefs(), this); | |
266 dictionary_language_.Init(prefs::kSpellCheckDictionary, | |
267 profile()->GetPrefs(), this); | |
268 enable_spellcheck_.Init(prefs::kEnableSpellCheck, | |
269 profile()->GetPrefs(), this); | |
270 enable_autospellcorrect_.Init(prefs::kEnableAutoSpellCorrect, | |
271 profile()->GetPrefs(), this); | |
272 NotifyPrefChanged(NULL); | |
273 EnableControls(); | |
274 } | |
275 | |
276 void LanguagesPageGtk::SetColumnValues(int row, GtkTreeIter* iter) { | |
277 string16 lang = language_order_table_model_->GetText(row, 0); | |
278 gtk_list_store_set(language_order_store_, iter, | |
279 COL_LANG, UTF16ToUTF8(lang).c_str(), | |
280 -1); | |
281 } | |
282 | |
283 void LanguagesPageGtk::OnAnyModelUpdate() { | |
284 if (!initializing_) | |
285 accept_languages_.SetValue(language_order_table_model_->GetLanguageList()); | |
286 EnableControls(); | |
287 } | |
288 | |
289 void LanguagesPageGtk::EnableControls() { | |
290 int num_selected = gtk_tree_selection_count_selected_rows( | |
291 language_order_selection_); | |
292 int row_count = gtk_tree_model_iter_n_children( | |
293 GTK_TREE_MODEL(language_order_store_), NULL); | |
294 gtk_widget_set_sensitive(move_up_button_, | |
295 num_selected == 1 && FirstSelectedRowNum() > 0); | |
296 gtk_widget_set_sensitive(move_down_button_, | |
297 num_selected == 1 && | |
298 FirstSelectedRowNum() < row_count - 1); | |
299 gtk_widget_set_sensitive(remove_button_, num_selected > 0); | |
300 } | |
301 | |
302 int LanguagesPageGtk::FirstSelectedRowNum() { | |
303 int row_num = -1; | |
304 GList* list = gtk_tree_selection_get_selected_rows(language_order_selection_, | |
305 NULL); | |
306 if (list) { | |
307 row_num = gtk_tree::GetRowNumForPath(static_cast<GtkTreePath*>(list->data)); | |
308 g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL); | |
309 g_list_free(list); | |
310 } | |
311 return row_num; | |
312 } | |
313 | |
314 void LanguagesPageGtk::NotifyPrefChanged(const std::string* pref_name) { | |
315 initializing_ = true; | |
316 if (!pref_name || *pref_name == prefs::kAcceptLanguages) { | |
317 language_order_table_model_->SetAcceptLanguagesString( | |
318 accept_languages_.GetValue()); | |
319 } | |
320 if (!pref_name || *pref_name == prefs::kSpellCheckDictionary) { | |
321 int index = dictionary_language_model_->GetSelectedLanguageIndex( | |
322 prefs::kSpellCheckDictionary); | |
323 | |
324 // If not found, fall back from "language-region" to "language". | |
325 if (index < 0) { | |
326 const std::string& lang_region = dictionary_language_.GetValue(); | |
327 dictionary_language_.SetValue( | |
328 SpellCheckCommon::GetLanguageFromLanguageRegion(lang_region)); | |
329 index = dictionary_language_model_->GetSelectedLanguageIndex( | |
330 prefs::kSpellCheckDictionary); | |
331 } | |
332 | |
333 gtk_combo_box_set_active(GTK_COMBO_BOX(dictionary_language_combobox_), | |
334 index); | |
335 } | |
336 if (!pref_name || *pref_name == prefs::kEnableSpellCheck) { | |
337 gtk_toggle_button_set_active( | |
338 GTK_TOGGLE_BUTTON(enable_spellchecking_checkbox_), | |
339 enable_spellcheck_.GetValue()); | |
340 } | |
341 if (!pref_name || *pref_name == prefs::kEnableAutoSpellCorrect) { | |
342 if (enable_autospellcorrect_checkbox_) { | |
343 gtk_toggle_button_set_active( | |
344 GTK_TOGGLE_BUTTON(enable_autospellcorrect_checkbox_), | |
345 enable_autospellcorrect_.GetValue()); | |
346 } | |
347 } | |
348 initializing_ = false; | |
349 } | |
350 | |
351 void LanguagesPageGtk::OnAddLanguage(const std::string& new_language) { | |
352 if (language_order_table_model_->Add(new_language)) | |
353 gtk_tree::SelectAndFocusRowNum(language_order_table_model_->RowCount() - 1, | |
354 GTK_TREE_VIEW(language_order_tree_)); | |
355 } | |
356 | |
357 void LanguagesPageGtk::OnSelectionChanged(GtkTreeSelection* selection) { | |
358 EnableControls(); | |
359 } | |
360 | |
361 void LanguagesPageGtk::OnAddButtonClicked(GtkWidget* button) { | |
362 new AddLanguageDialog(profile(), this); | |
363 } | |
364 | |
365 void LanguagesPageGtk::OnRemoveButtonClicked(GtkWidget* button) { | |
366 std::set<int> selected_rows; | |
367 gtk_tree::GetSelectedIndices(language_order_selection_, | |
368 &selected_rows); | |
369 | |
370 int selected_row = 0; | |
371 for (std::set<int>::reverse_iterator selected = selected_rows.rbegin(); | |
372 selected != selected_rows.rend(); ++selected) { | |
373 language_order_table_model_->Remove(*selected); | |
374 selected_row = *selected; | |
375 } | |
376 int row_count = language_order_table_model_->RowCount(); | |
377 if (row_count <= 0) | |
378 return; | |
379 if (selected_row >= row_count) | |
380 selected_row = row_count - 1; | |
381 gtk_tree::SelectAndFocusRowNum(selected_row, | |
382 GTK_TREE_VIEW(language_order_tree_)); | |
383 } | |
384 | |
385 void LanguagesPageGtk::OnMoveUpButtonClicked(GtkWidget* button) { | |
386 int item_selected = FirstSelectedRowNum(); | |
387 language_order_table_model_->MoveUp(item_selected); | |
388 gtk_tree::SelectAndFocusRowNum( | |
389 item_selected - 1, GTK_TREE_VIEW(language_order_tree_)); | |
390 } | |
391 | |
392 void LanguagesPageGtk::OnMoveDownButtonClicked(GtkWidget* button) { | |
393 int item_selected = FirstSelectedRowNum(); | |
394 language_order_table_model_->MoveDown(item_selected); | |
395 gtk_tree::SelectAndFocusRowNum( | |
396 item_selected + 1, GTK_TREE_VIEW(language_order_tree_)); | |
397 } | |
398 | |
399 void LanguagesPageGtk::OnEnableSpellCheckingToggled(GtkWidget* toggle_button) { | |
400 if (initializing_) | |
401 return; | |
402 enable_spellcheck_.SetValue( | |
403 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button))); | |
404 } | |
405 | |
406 void LanguagesPageGtk::OnEnableAutoSpellCheckingToggled( | |
407 GtkWidget* toggle_button) { | |
408 if (initializing_) | |
409 return; | |
410 enable_autospellcorrect_.SetValue( | |
411 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button))); | |
412 } | |
413 | |
414 void LanguagesPageGtk::OnDictionaryLanguageChanged(GtkWidget* widget) { | |
415 if (initializing_) | |
416 return; | |
417 int new_index = gtk_combo_box_get_active( | |
418 GTK_COMBO_BOX(dictionary_language_combobox_)); | |
419 | |
420 if (new_index < 0 || | |
421 new_index >= dictionary_language_model_->GetItemCount()) { | |
422 NOTREACHED(); | |
423 return; | |
424 } | |
425 | |
426 // Remove the previously added spell check language to the accept list. | |
427 if (!spellcheck_language_added_.empty()) { | |
428 int old_index = language_order_table_model_->GetIndex( | |
429 spellcheck_language_added_); | |
430 if (old_index > -1) | |
431 language_order_table_model_->Remove(old_index); | |
432 } | |
433 | |
434 // Add this new spell check language only if it is not already in the | |
435 // accept language list. | |
436 std::string language = | |
437 dictionary_language_model_->GetLocaleFromIndex(new_index); | |
438 int index = language_order_table_model_->GetIndex(language); | |
439 if (index == -1) { | |
440 // Add the new language. | |
441 OnAddLanguage(language); | |
442 spellcheck_language_added_ = language; | |
443 } else { | |
444 spellcheck_language_added_ = ""; | |
445 } | |
446 | |
447 UserMetricsRecordAction(UserMetricsAction("Options_DictionaryLanguage"), | |
448 profile()->GetPrefs()); | |
449 dictionary_language_.SetValue(language); | |
450 } | |
OLD | NEW |