Move engineabout dialog into a new python file.
[platform/upstream/ibus.git] / setup / main.py
1 # vim:set et sts=4 sw=4:
2 #
3 # ibus - The Input Bus
4 #
5 # Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2 of the License, or (at your option) any later version.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this program; if not, write to the
19 # Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 # Boston, MA  02111-1307  USA
21
22 import locale
23 import gettext
24 import os
25 import signal
26 import sys
27 import time
28 import gtk
29 import gobject
30 import pango
31 import ibus
32 import keyboardshortcut
33 from os import path
34 from xdg import BaseDirectory
35 from gtk import gdk
36 from gtk import glade
37 from enginecombobox import EngineComboBox
38 from enginetreeview import EngineTreeView
39 from engineabout import EngineAbout
40
41 _  = lambda a : gettext.dgettext("ibus", a)
42 N_ = lambda a : a
43
44 (
45     COLUMN_NAME,
46     COLUMN_ENABLE,
47     COLUMN_PRELOAD,
48     COLUMN_VISIBLE,
49     COLUMN_ICON,
50     COLUMN_DATA,
51 ) = range(6)
52
53 (
54     DATA_NAME,
55     DATA_LOCAL_NAME,
56     DATA_LANG,
57     DATA_ICON,
58     DATA_AUTHOR,
59     DATA_CREDITS,
60     DATA_EXEC,
61     DATA_STARTED,
62     DATA_PRELOAD
63 ) = range(9)
64
65 class Setup(object):
66     def __flush_gtk_events(self):
67         while gtk.events_pending():
68             gtk.main_iteration()
69
70     def __init__(self):
71         super(Setup, self).__init__()
72         locale.bind_textdomain_codeset("ibus", "UTF-8")
73         glade.textdomain("ibus")
74         glade_file = path.join(path.dirname(__file__), "./setup.glade")
75         self.__xml = glade.XML(glade_file)
76         self.__bus = None
77         self.__init_bus()
78         self.__init_ui()
79
80     def __init_ui(self):
81         # add icon search path
82         self.__window = self.__xml.get_widget("window_preferences")
83         self.__window.connect("delete-event", gtk.main_quit)
84
85         self.__button_close = self.__xml.get_widget("button_close")
86         self.__button_close.connect("clicked", gtk.main_quit)
87
88         # auto start ibus
89         self.__checkbutton_auto_start = self.__xml.get_widget("checkbutton_auto_start")
90         self.__checkbutton_auto_start.set_active(self.__is_auto_start())
91         self.__checkbutton_auto_start.connect("toggled", self.__checkbutton_auto_start_toggled_cb)
92
93         # keyboard shortcut
94         # trigger
95         self.__config = self.__bus.get_config()
96         shortcuts = self.__config.get_value(
97                         "general/hotkey", "trigger",
98                         ibus.CONFIG_GENERAL_SHORTCUT_TRIGGER_DEFAULT)
99
100         button = self.__xml.get_widget("button_trigger")
101         entry = self.__xml.get_widget("entry_trigger")
102         entry.set_text("; ".join(shortcuts))
103         button.connect("clicked", self.__shortcut_button_clicked_cb,
104                     N_("trigger"), "general/hotkey", "trigger", entry)
105
106         # next engine
107         shortcuts = self.__config.get_value(
108                         "general/hotkey", "next_engine",
109                         ibus.CONFIG_GENERAL_SHORTCUT_NEXT_ENGINE_DEFAULT)
110         button = self.__xml.get_widget("button_next_engine")
111         entry = self.__xml.get_widget("entry_next_engine")
112         entry.set_text("; ".join(shortcuts))
113         button.connect("clicked", self.__shortcut_button_clicked_cb,
114                     N_("next input method"), "general/hotkey", "next_engine", entry)
115
116         # prev engine
117         shortcuts = self.__config.get_value(
118                         "general/hotkey", "prev_engine",
119                         ibus.CONFIG_GENERAL_SHORTCUT_PREV_ENGINE_DEFAULT)
120         button = self.__xml.get_widget("button_prev_engine")
121         entry = self.__xml.get_widget("entry_prev_engine")
122         entry.set_text("; ".join(shortcuts))
123         button.connect("clicked", self.__shortcut_button_clicked_cb,
124                     N_("previous input method"), "general/hotkey", "prev_engine", entry)
125
126         # lookup table orientation
127         self.__combobox_lookup_table_orientation = self.__xml.get_widget("combobox_lookup_table_orientation")
128         self.__combobox_lookup_table_orientation.set_active(
129             self.__config.get_value("panel", "lookup_table_orientation", 0))
130         self.__combobox_lookup_table_orientation.connect("changed",
131             self.__combobox_lookup_table_orientation_changed_cb)
132
133         # auto hide
134         self.__combobox_panel_show = self.__xml.get_widget("combobox_panel_show")
135         self.__combobox_panel_show.set_active(
136             self.__config.get_value("panel", "show", 1))
137         self.__combobox_panel_show.connect("changed", self.__combobox_panel_show_changed_cb)
138
139         # custom font
140         self.__checkbutton_custom_font = self.__xml.get_widget("checkbutton_custom_font")
141         self.__checkbutton_custom_font.set_active(
142             self.__config.get_value("panel", "use_custom_font", False))
143         self.__checkbutton_custom_font.connect("toggled", self.__checkbutton_custom_font_toggled_cb)
144
145         self.__label_custom_font = self.__xml.get_widget("label_custom_font")
146         self.__fontbutton_custom_font = self.__xml.get_widget("fontbutton_custom_font")
147         if self.__config.get_value("panel", "use_custom_font", False):
148             self.__label_custom_font.set_sensitive(True)
149             self.__fontbutton_custom_font.set_sensitive(True)
150         else:
151             self.__label_custom_font.set_sensitive(False)
152             self.__fontbutton_custom_font.set_sensitive(False)
153         font_name = gtk.settings_get_default().get_property("gtk-font-name")
154         font_name = unicode(font_name, "utf-8")
155         font_name = self.__config.get_value("panel", "custom_font", font_name)
156         self.__fontbutton_custom_font.connect("notify::font-name", self.__fontbutton_custom_font_notify_cb)
157         self.__fontbutton_custom_font.set_font_name(font_name)
158
159         # init engine page
160         self.__engines = self.__bus.list_engines()
161         self.__combobox = EngineComboBox(self.__engines)
162         self.__combobox.show()
163         self.__xml.get_widget("alignment_engine_combobox").add(self.__combobox)
164
165         tmp_dict = {}
166         for e in self.__engines:
167             tmp_dict[e.name] = e
168         engine_names = self.__config.get_value("general", "preload_engines", [])
169         engines = []
170         for n in engine_names:
171             if n in tmp_dict:
172                 engines.append(tmp_dict[n])
173         self.__treeview = EngineTreeView(engines)
174         self.__treeview.show()
175         self.__xml.get_widget("scrolledwindow_engine_treeview").add(self.__treeview)
176
177         self.__treeview.connect("changed", self.__treeview_changed_cb)
178
179         button = self.__xml.get_widget("button_engine_add")
180         button.connect("clicked",
181                        lambda *args:self.__treeview.append_engine(self.__combobox.get_active_engine()))
182         button = self.__xml.get_widget("button_engine_remove")
183         button.connect("clicked", lambda *args:self.__treeview.remove_engine())
184         button = self.__xml.get_widget("button_engine_up")
185         button.connect("clicked", lambda *args:self.__treeview.move_up_engine())
186
187         button = self.__xml.get_widget("button_engine_down")
188         button.connect("clicked", lambda *args:self.__treeview.move_down_engine())
189
190         button = self.__xml.get_widget("button_engine_about")
191         button.connect("clicked", self.__button_engine_about_cb)
192
193     def __button_engine_about_cb(self, button):
194         engine = self.__treeview.get_select_engine()
195         about = EngineAbout(engine)
196         about.run()
197         about.destroy()
198
199     def __treeview_changed_cb(self, treeview):
200         engines = self.__treeview.get_engines()
201         engine_names = map(lambda e: e.name, engines)
202         self.__config.set_list("general", "preload_engines", engine_names, "s")
203
204     def __init_bus(self):
205         try:
206             self.__bus = ibus.Bus()
207             # self.__bus.connect("config-value-changed", self.__config_value_changed_cb)
208             # self.__bus.connect("config-reloaded", self.__config_reloaded_cb)
209             # self.__bus.config_add_watch("/general")
210             # self.__bus.config_add_watch("/general/hotkey")
211             # self.__bus.config_add_watch("/panel")
212         except:
213             while self.__bus == None:
214                 message = _("IBus daemon is not started. Do you want to start it now?")
215                 dlg = gtk.MessageDialog(type = gtk.MESSAGE_QUESTION,
216                         buttons = gtk.BUTTONS_YES_NO,
217                         message_format = message)
218                 id = dlg.run()
219                 dlg.destroy()
220                 self.__flush_gtk_events()
221                 if id != gtk.RESPONSE_YES:
222                     sys.exit(0)
223                 pid = os.spawnlp(os.P_NOWAIT, "ibus-daemon", "ibus-daemon")
224                 time.sleep(1)
225                 try:
226                     self.__bus = ibus.Bus()
227                 except:
228                     continue
229                 message = _("IBus has been started! "
230                     "If you can not use IBus, please add below lines in $HOME/.bashrc, and relogin your desktop.\n"
231                     "  export GTK_IM_MODULE=ibus\n"
232                     "  export XMODIFIERS=@im=ibus\n"
233                     "  export QT_IM_MODULE=ibus"
234                     )
235                 dlg = gtk.MessageDialog(type = gtk.MESSAGE_INFO,
236                                         buttons = gtk.BUTTONS_OK,
237                                         message_format = message)
238                 id = dlg.run()
239                 dlg.destroy()
240                 self.__flush_gtk_events()
241
242     def __shortcut_button_clicked_cb(self, button, name, section, _name, entry):
243         buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)
244         title = _("Select keyboard shortcut for %s") %  _(name)
245         dialog = keyboardshortcut.KeyboardShortcutSelectionDialog(buttons = buttons, title = title)
246         text = entry.get_text()
247         if text:
248             shortcuts = text.split("; ")
249         else:
250             shortcuts = None
251         dialog.set_shortcuts(shortcuts)
252         id = dialog.run()
253         shortcuts = dialog.get_shortcuts()
254         dialog.destroy()
255         if id != gtk.RESPONSE_OK:
256             return
257         self.__config.set_list(section, _name, shortcuts, "s")
258         entry.set_text("; ".join(shortcuts))
259
260
261     def __item_started_column_toggled_cb(self, cell, path_str, model):
262
263         # get toggled iter
264         iter = model.get_iter_from_string(path_str)
265         data = model.get_value(iter, COLUMN_DATA)
266
267         # do something with the value
268         if data[DATA_STARTED] == False:
269             try:
270                 self.__bus.register_start_engine(data[DATA_LANG], data[DATA_NAME])
271             except Exception, e:
272                 dlg = gtk.MessageDialog(type = gtk.MESSAGE_ERROR,
273                         buttons = gtk.BUTTONS_CLOSE,
274                         message_format = str(e))
275                 dlg.run()
276                 dlg.destroy()
277                 self.__flush_gtk_events()
278                 return
279         else:
280             try:
281                 self.__bus.register_stop_engine(data[DATA_LANG], data[DATA_NAME])
282             except Exception, e:
283                 dlg = gtk.MessageDialog(type = gtk.MESSAGE_ERROR,
284                         buttons = gtk.BUTTONS_CLOSE,
285                         message_format = str(e))
286                 dlg.run()
287                 dlg.destroy()
288                 self.__flush_gtk_events()
289                 return
290         data[DATA_STARTED] = not data[DATA_STARTED]
291
292         # set new value
293         model.set(iter, COLUMN_ENABLE, data[DATA_STARTED])
294
295     def __item_preload_column_toggled_cb(self, cell, path_str, model):
296
297         # get toggled iter
298         iter = model.get_iter_from_string(path_str)
299         data = model.get_value(iter, COLUMN_DATA)
300
301         data[DATA_PRELOAD] = not data[DATA_PRELOAD]
302         engine = "%s:%s" % (data[DATA_LANG], data[DATA_NAME])
303
304         if data[DATA_PRELOAD]:
305             if engine not in self.__preload_engines:
306                 self.__preload_engines.add(engine)
307                 self.__config.set_list("general", "preload_engines", list(self.__preload_engines), "s")
308         else:
309             if engine in self.__preload_engines:
310                 self.__preload_engines.remove(engine)
311                 self.__config.set_list("general", "preload_engines", list(self.__preload_engines), "s")
312
313         # set new value
314         model.set(iter, COLUMN_PRELOAD, data[DATA_PRELOAD])
315
316     def __is_auto_start(self):
317         link_file = path.join(BaseDirectory.xdg_config_home, "autostart/ibus.desktop")
318         ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/ibus.desktop")
319
320         if not path.exists(link_file):
321             return False
322         if not path.islink(link_file):
323             return False
324         if path.realpath(link_file) != ibus_desktop:
325             return False
326         return True
327
328     def __checkbutton_auto_start_toggled_cb(self, button):
329         auto_start_dir = path.join(BaseDirectory.xdg_config_home, "autostart")
330         if not path.isdir(auto_start_dir):
331             os.makedirs(auto_start_dir)
332
333         link_file = path.join(BaseDirectory.xdg_config_home, "autostart/ibus.desktop")
334         ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/ibus.desktop")
335         # unlink file
336         try:
337             os.unlink(link_file)
338         except:
339             pass
340         if self.__checkbutton_auto_start.get_active():
341             os.symlink(ibus_desktop, link_file)
342
343     def __combobox_lookup_table_orientation_changed_cb(self, combobox):
344         self.__config.set_value(
345             "panel", "lookup_table_orientation",
346             self.__combobox_lookup_table_orientation.get_active())
347
348     def __combobox_panel_show_changed_cb(self, combobox):
349         self.__config.set_value(
350             "panel", "show",
351             self.__combobox_panel_show.get_active())
352
353     def __checkbutton_custom_font_toggled_cb(self, button):
354         if self.__checkbutton_custom_font.get_active():
355             self.__label_custom_font.set_sensitive(True)
356             self.__fontbutton_custom_font.set_sensitive(True)
357             self.__config.set_value("panel", "use_custom_font", True)
358         else:
359             self.__label_custom_font.set_sensitive(False)
360             self.__fontbutton_custom_font.set_sensitive(False)
361             self.__config.set_value("panel", "use_custom_font", False)
362
363     def __fontbutton_custom_font_notify_cb(self, button, arg):
364         font_name = self.__fontbutton_custom_font.get_font_name()
365         font_name = unicode(font_name, "utf-8")
366         self.__config.set_value("panel", "custom_font", font_name)
367
368     def __config_value_changed_cb(self, bus, section, name, value):
369         pass
370
371     def __config_reloaded_cb(self, bus):
372         pass
373
374     def __sigusr1_cb(self, *args):
375         self.__window.present()
376
377     def run(self):
378         self.__window.show_all()
379         signal.signal(signal.SIGUSR1, self.__sigusr1_cb)
380         gtk.main()
381
382 if __name__ == "__main__":
383     setup = Setup()
384     setup.run()