diff options
-rw-r--r-- | activity.py | 84 | ||||
-rw-r--r-- | activity/activity.info | 2 | ||||
-rw-r--r-- | pippy_app.py | 349 | ||||
-rw-r--r-- | wordsactivity.py | 267 |
4 files changed, 268 insertions, 434 deletions
diff --git a/activity.py b/activity.py deleted file mode 100644 index 061187e..0000000 --- a/activity.py +++ /dev/null @@ -1,84 +0,0 @@ -from sugar.activity import activity - -class ViewSourceActivity(activity.Activity): - """Activity subclass which handles the 'view source' key.""" - def __init__(self, handle): - super(ViewSourceActivity, self).__init__(handle) - self.__source_object_id = None # XXX: persist this across invocations? - self.connect('key-press-event', self._key_press_cb) - def _key_press_cb(self, widget, event): - import gtk - if gtk.gdk.keyval_name(event.keyval) == 'XF86Start': - self.view_source() - return True - return False - def view_source(self): - """Implement the 'view source' key by saving pippy_app.py to the - datastore, and then telling the Journal to view it.""" - if self.__source_object_id is None: - from sugar import profile - from sugar.datastore import datastore - from sugar.activity.activity import get_bundle_name, get_bundle_path - from gettext import gettext as _ - import os.path - jobject = datastore.create() - metadata = { - 'title': _('%s Source') % get_bundle_name(), - 'title_set_by_user': '1', - 'suggested_filename': 'pippy_app.py', - 'icon-color': profile.get_color().to_string(), - 'mime_type': 'text/x-python', - } - for k, v in metadata.items(): - jobject.metadata[k] = v # dict.update method is missing =( - jobject.file_path = os.path.join(get_bundle_path(), 'pippy_app.py') - datastore.write(jobject) - self.__source_object_id = jobject.object_id - jobject.destroy() - self.journal_show_object(self.__source_object_id) - def journal_show_object(self, object_id): - """Invoke journal_show_object from sugar.activity.activity if it - exists.""" - try: - from sugar.activity.activity import show_object_in_journal - show_object_in_journal(object_id) - except ImportError: - pass # no love from sugar. - -class VteActivity(ViewSourceActivity): - def __init__(sfelf, handle): - import gtk, pango, vte - super(VteActivity, self).__init__(handle) - toolbox = activity.ActivityToolbox(self) - self.set_toolbox(toolbox) - toolbox.show() - - # creates vte widget - self._vte = vte.Terminal() - self._vte.set_size(30, 5) - self._vte.set_size_request(200, 300) - font = 'Monospace 10' - self._vte.set_font(pango.FontDescription(font)) - self._vte.set_colors(gtk.gdk.color_parse ('#000000'), - gtk.gdk.color_parse ('#E7E7E7'), - []) - # ...and its scrollbar - vtebox = gtk.HBox() - vtebox.pack_start(self._vte) - vtesb = gtk.VScrollbar(self._vte.get_adjustment()) - vtesb.show() - vtebox.pack_start(vtesb, False, False, 0) - self.set_canvas(vtebox) - self.show_all() - - # now start subprocess. - self._vte.grab_focus() - bundle_path = activity.get_bundle_path() - # the 'sleep 1' works around a bug with the command dying before - # the vte widget manages to snarf the last bits of its output - self._pid = self._vte.fork_command \ - (command='/bin/sh', - argv=['/bin/sh','-c', - 'python %s/pippy_app.py; sleep 1' % bundle_path], - envv=["PYTHONPATH=%s/library" % bundle_path], - directory=bundle_path) diff --git a/activity/activity.info b/activity/activity.info index 43fd48e..be2269c 100644 --- a/activity/activity.info +++ b/activity/activity.info @@ -1,7 +1,7 @@ [Activity] name = Words bundle_id = org.laptop.Words -class = pippy_app.WordsActivity +class = wordsactivity.WordsActivity icon = activity-icon activity_version = 10 show_launcher = yes diff --git a/pippy_app.py b/pippy_app.py deleted file mode 100644 index 52750c2..0000000 --- a/pippy_app.py +++ /dev/null @@ -1,349 +0,0 @@ -# Copyright 2008 Chris Ball. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -"""Words Activity: A multi-lingual dictionary with speech synthesis.""" -"""Actividad Palabras: Un diccionario multi-lengua con sintesis de habla""" - -import gtk -import logging -import pango -import re -import os -import os.path -import subprocess - -from gettext import gettext as _ -from dbus.service import method, signal - -from activity import ViewSourceActivity -from sugar.activity.activity import ActivityToolbox, \ - get_bundle_path, get_bundle_name - -from sugar.graphics.toolbutton import ToolButton - -# logging -logger = logging.getLogger('Words') - -SERVICE = "org.laptop.Words" -IFACE = SERVICE -PATH = "/org/laptop/Words" - -class WordsActivity(ViewSourceActivity): - """Words Activity as specified in activity.info""" - def __init__(self, handle): - """Set up the Words activity.""" - super(WordsActivity, self).__init__(handle) - self._logger = logging.getLogger('words-activity') - - from sugar.graphics.menuitem import MenuItem - from sugar.graphics.icon import Icon - - # Instantiate a language model. - # FIXME: We should ask the language model what langs it supports. - self.langs = ["French", "German", "Italian", "Portuguese", "Spanish"] - # Initial values. - self.fromlang = "English" - self.tolang = "Spanish" - import LanguageModel - self.languagemodel = LanguageModel.LanguageModel() - - # We do not have collaboration features - # make the share option insensitive - self.max_participants = 1 - - # Main layout. - hbox = gtk.HBox(homogeneous=True, spacing=8) - vbox = gtk.VBox(spacing=16) - vbox.set_border_width(16) - - # Toolbar (compatibility with old-toolbars). - try: - from sugar.graphics.toolbarbox import ToolbarBox, ToolbarButton - from sugar.activity.widgets import ActivityButton, StopButton, \ - ShareButton, KeepButton, TitleEntry - - toolbar_box = ToolbarBox() - activity_button = ActivityButton(self) - toolbar_box.toolbar.insert(activity_button, 0) - activity_button.show() - - title_entry = TitleEntry(self) - toolbar_box.toolbar.insert(title_entry, -1) - title_entry.show() - - share_button = ShareButton(self) - toolbar_box.toolbar.insert(share_button, -1) - share_button.show() - - separator = gtk.SeparatorToolItem() - separator.props.draw = False - separator.set_expand(True) - toolbar_box.toolbar.insert(separator, -1) - separator.show() - - stop_button = StopButton(self) - toolbar_box.toolbar.insert(stop_button, -1) - stop_button.show() - - self.set_toolbox(toolbar_box) - toolbar_box.show() - except ImportError: - toolbox = ActivityToolbox(self) - self.set_toolbox(toolbox) - toolbox.show() - - # transbox: <label> - <text entry> - <speak button> - transbox = gtk.Table() - transbox.resize(2, 3) - transbox.set_row_spacings(8) - transbox.set_col_spacings(12) - - # Labels. - label1 = gtk.Label(_("Word") + ':') - label1.set_alignment(xalign=0.0, yalign=0.5) - label2 = gtk.Label(_("Translation") + ':') - label2.set_alignment(xalign=0.0, yalign=0.5) - - # Text entry box to enter word to be translated. - self.totranslate = gtk.Entry(max=50) - self.totranslate.connect("changed", self.totranslate_cb) - self.totranslate.modify_font(pango.FontDescription("Sans 14")) - - # Text entry box to receive word translated. - self.translated = gtk.Entry(max=50) - self.translated.set_property('editable', False) - self.translated.modify_font(pango.FontDescription("Sans 14")) - - # Speak buttons. - speak1 = gtk.ToolButton() - speak_icon1 = Icon(icon_name='microphone') - speak1.set_icon_widget(speak_icon1) - speak1.connect("clicked", self.speak1_cb) - speak2 = gtk.ToolButton() - speak_icon2 = Icon(icon_name='microphone') - speak2.set_icon_widget(speak_icon2) - speak2.connect("clicked", self.speak2_cb) - - transbox.attach(label1, 0, 1, 0, 1, xoptions=gtk.FILL) - transbox.attach(self.totranslate, 1, 2, 0, 1, xoptions=gtk.FILL|gtk.EXPAND) - transbox.attach(speak1, 2, 3, 0, 1, xoptions=gtk.FILL) - - transbox.attach(label2, 0, 1, 1, 2, xoptions=gtk.FILL) - transbox.attach(self.translated, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND) - transbox.attach(speak2, 2, 3, 1, 2, xoptions=gtk.FILL) - - vbox.pack_start(transbox, expand=False) - - # The language choice combo boxes. - self.lang1combo = gtk.combo_box_new_text() - self.lang1combo.append_text("English") - self.lang1combo.connect("changed", self.lang1combo_cb) - self.lang1combo.set_active(0) - - self.lang2combo = gtk.combo_box_new_text() - for x in self.langs: - self.lang2combo.append_text(x) - self.lang2combo.connect("changed", self.lang2combo_cb) - self.lang2combo.set_active(4) - - self.lang1combo.set_size_request(600,50) - self.lang2combo.set_size_request(600,50) - - # The "lang1" treeview box - self.lang1model = gtk.ListStore(str) - lang1view = gtk.TreeView(self.lang1model) - lang1view.set_headers_visible(False) - lang1cell = gtk.CellRendererText() - lang1treecol = gtk.TreeViewColumn("", lang1cell, text=0) - lang1view.get_selection().connect("changed", self.lang1sel_cb) - lang1view.append_column(lang1treecol) - lang1scroll = gtk.ScrolledWindow(hadjustment=None, vadjustment=None) - lang1scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - lang1scroll.add(lang1view) - - # The "lang2" box - self.lang2model = gtk.ListStore(str) - lang2view = gtk.TreeView(self.lang2model) - lang2view.set_headers_visible(False) - lang2cell = gtk.CellRendererText() - lang2treecol = gtk.TreeViewColumn("", lang2cell, text=0) - lang2view.get_selection().connect("changed", self.lang2sel_cb) - lang2view.append_column(lang2treecol) - lang2scroll = gtk.ScrolledWindow(hadjustment=None, vadjustment=None) - lang2scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - lang2scroll.add(lang2view) - - lang1_vbox = gtk.VBox(spacing=8) - lang1_vbox.pack_start(self.lang1combo, expand=False) - lang1_vbox.pack_start(lang1scroll) - - lang2_vbox = gtk.VBox(spacing=8) - lang2_vbox.pack_start(self.lang2combo, expand=False) - lang2_vbox.pack_start(lang2scroll) - - hbox.pack_start(lang1_vbox) - hbox.pack_start(lang2_vbox) - - vbox.pack_start(hbox) - self.set_canvas(vbox) - self.totranslate.grab_focus() - self.show_all() - - def say(self, text, lang): - # No Portuguese accent yet. - if lang == "portuguese": - lang = "spanish" - tmpfile = "/tmp/something.wav" - subprocess.call(["espeak", text, "-w", tmpfile, "-v", lang]) - subprocess.call(["aplay", tmpfile]) - os.unlink(tmpfile) - - def lang1combo_cb(self, combo): - pass - - def lang2combo_cb(self, combo): - self.languagemodel.SetLanguages("English", self.langs[combo.get_active()]) - - def lang1sel_cb(self, column): - # FIXME: Complete the text entry box - model, _iter = column.get_selected() - value = model.get_value(_iter,0) - translations = self.languagemodel.GetTranslations(0, value) - self.translated.set_text(",".join(translations)) - - def lang2sel_cb(self, column): - model, _iter = column.get_selected() - value = model.get_value(_iter,0) - translations = self.languagemodel.GetTranslations(1, value) - self.translated.set_text(",".join(translations)) - - def speak1_cb(self, button): - text = self.totranslate.get_text() - lang = self.fromlang.lower() - self.say(text, lang) - - def speak2_cb(self, button): - text = self.translated.get_text() - lang = self.tolang.lower() - self.say(text, lang) - - def totranslate_cb(self, totranslate): - entry = totranslate.get_text() - # Ask for completion suggestions - if not entry: - return - - (list1, list2) = self.languagemodel.GetSuggestions(entry) - self.lang1model.clear() - self.lang2model.clear() - for x in list1: - self.lang1model.append([x]) - for x in list2: - self.lang2model.append([x]) - - # If we think we know what the word will be, translate it. - if entry in list1 or len(list1) == 1 and len(list2) == 0: - langiter = self.lang2combo.get_active() - lang = self.langs[langiter].lower() - self.fromlang = "English" - self.tolang = lang - translations = self.languagemodel.GetTranslations(0, list1[0]) - self.translated.set_text(",".join(translations)) - - elif entry in list2 or len(list1) == 0 and len(list2) == 1: - langiter = self.lang2combo.get_active() - lang = self.langs[langiter].lower() - self.fromlang = lang - self.tolang = "English" - translations = self.languagemodel.GetTranslations(1, list2[0]) - self.translated.set_text(",".join(translations)) - -############# TEMPLATES AND INLINE FILES ############## -ACTIVITY_INFO_TEMPLATE = """ -[Activity] -name = %(title)s -bundle_id = %(bundle_id)s -service_name = %(bundle_id)s -class = %(class)s -icon = activity-icon -activity_version = %(version)d -mime_types = %(mime_types)s -show_launcher = yes -%(extra_info)s -""" - -PIPPY_ICON = \ -"""<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [ - <!ENTITY stroke_color "#010101"> - <!ENTITY fill_color "#FFFFFF"> -]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="activity-pippy"> - <path d="M28.497,48.507 c5.988,0,14.88-2.838,14.88-11.185c0-9.285-7.743-10.143-10.954-11.083c-3.549-0.799-5.913-1.914-6.055-3.455 c-0.243-2.642,1.158-3.671,3.946-3.671c0,0,6.632,3.664,12.266,0.74c1.588-0.823,4.432-4.668,4.432-7.32 c0-2.653-9.181-5.719-11.967-5.719c-2.788,0-5.159,3.847-5.159,3.847c-5.574,0-11.149,5.306-11.149,10.612 c0,5.305,5.333,9.455,11.707,10.612c2.963,0.469,5.441,2.22,4.878,5.438c-0.457,2.613-2.995,5.306-8.361,5.306 c-4.252,0-13.3-0.219-14.745-4.079c-0.929-2.486,0.168-5.205,1.562-5.205l-0.027-0.16c-1.42-0.158-5.548,0.16-5.548,5.465 C8.202,45.452,17.347,48.507,28.497,48.507z" fill="&fill_color;" stroke="&stroke_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5"/> - <path d="M42.579,19.854c-2.623-0.287-6.611-2-7.467-5.022" fill="none" stroke="&stroke_color;" stroke-linecap="round" stroke-width="3"/> - <circle cx="35.805" cy="10.96" fill="&stroke_color;" r="1.676"/> -</g></svg><!-- " --> -""" - -PIPPY_DEFAULT_ICON = \ -"""<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [ - <!ENTITY stroke_color "#010101"> - <!ENTITY fill_color "#FFFFFF"> -]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" - viewBox="0 0 55 55" width="55px" x="0px" y="0px" xml:space="preserve" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" -><g display="block" id="activity-icon"><path - d="M 28.497,48.507 C 34.485,48.507 43.377,45.669 43.377,37.322 C 43.377,32.6795 41.44125,30.14375 39.104125,28.651125 C 36.767,27.1585 38.482419,26.816027 39.758087,25.662766 C 39.42248,24.275242 37.206195,22.826987 36.262179,21.037968 C 34.005473,20.582994 27.526,19.113 30.314,19.113 C 30.314,19.113 36.946,22.777 42.58,19.853 C 44.168,19.03 47.012,15.185 47.012,12.533 C 47.012,9.88 37.831,6.814 35.045,6.814 C 32.257,6.814 29.886,10.661 29.886,10.661 C 24.312,10.661 12.043878,16.258005 12.043878,21.564005 C 12.043878,24.216505 16.585399,30.069973 19.144694,33.736352 C 22.438716,38.455279 27.257,31.3065 30.444,31.885 C 33.407,32.354 35.885,34.105 35.322,37.323 C 34.865,39.936 32.327,42.629 26.961,42.629 C 22.709,42.629 13.661,42.41 12.216,38.55 C 11.287,36.064 12.384,33.345 13.778,33.345 L 13.751,33.185 C 12.331,33.027 8.203,33.345 8.203,38.65 C 8.202,45.452 17.347,48.507 28.497,48.507 z " - fill="&fill_color;" stroke="&stroke_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5" /> - <path d="M42.579,19.854c-2.623-0.287-6.611-2-7.467-5.022" fill="none" stroke="&stroke_color;" stroke-linecap="round" stroke-width="3"/> - <circle cx="35.805" cy="10.96" fill="&stroke_color;" r="1.676"/> -</g></svg><!-- " --> -""" - -############# ACTIVITY META-INFORMATION ############### -# this is used by Words to generate a bundle for itself. - -def pippy_activity_version(): - """Returns the version number of the generated activity bundle.""" - return 1 -def pippy_activity_extra_files(): - """Returns a map of 'extra' files which should be included in the - generated activity bundle.""" - # Cheat here and generate the map from the fs contents. - extra = {} - bp = get_bundle_path() - for d in [ 'po', 'data' ]: # everybody gets library already - for root, dirs, files in os.walk(os.path.join(bp, d)): - for name in files: - fn = os.path.join(root, name).replace(bp+'/', '') - extra[fn] = open(os.path.join(root, name), 'r').read() - extra['activity/activity-default.svg'] = PIPPY_DEFAULT_ICON - return extra -def pippy_activity_news(): - """Return the NEWS file for this activity.""" - # Cheat again. - return open(os.path.join(get_bundle_path(), 'NEWS')).read() -def pippy_activity_icon(): - """Return an SVG document specifying the icon for this activity.""" - return PIPPY_ICON -def pippy_activity_class(): - """Return the class which should be started to run this activity.""" - return 'pippy_app.WordsActivity' -def pippy_activity_bundle_id(): - """Return the bundle_id for the generated activity.""" - return 'org.laptop.Words' -def pippy_activity_mime_types(): - """Return the mime types handled by the generated activity, as a list.""" - return 'text/x-python' diff --git a/wordsactivity.py b/wordsactivity.py new file mode 100644 index 0000000..afa7369 --- /dev/null +++ b/wordsactivity.py @@ -0,0 +1,267 @@ +# Copyright 2008 Chris Ball. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Words Activity: A multi-lingual dictionary with speech synthesis.""" +"""Actividad Palabras: Un diccionario multi-lengua con sintesis de habla""" + +import gtk +import logging +import pango +import os +import subprocess + +from gettext import gettext as _ + +from sugar.activity import activity +from sugar.activity.activity import ActivityToolbox, \ + get_bundle_path, get_bundle_name + +from sugar.graphics.icon import Icon +OLD_TOOLBARS = False +try: + from sugar.graphics.toolbarbox import ToolbarBox, ToolbarButton + from sugar.activity.widgets import ActivityButton, StopButton, \ + ShareButton, KeepButton, TitleEntry +except ImportError: + OLD_TOOLBARS = True + +# logging +logger = logging.getLogger('Words') + + +class WordsActivity(activity.Activity): + """Words Activity as specified in activity.info""" + + def __init__(self, handle): + """Set up the Words activity.""" + super(WordsActivity, self).__init__(handle) + self._logger = logging.getLogger('words-activity') + + # Instantiate a language model. + # FIXME: We should ask the language model what langs it supports. + self.langs = ["French", "German", "Italian", "Portuguese", "Spanish"] + # Initial values. + self.fromlang = "English" + self.tolang = "Spanish" + import LanguageModel + self.languagemodel = LanguageModel.LanguageModel() + + # We do not have collaboration features + # make the share option insensitive + self.max_participants = 1 + + # Main layout. + hbox = gtk.HBox(homogeneous=True, spacing=8) + vbox = gtk.VBox(spacing=16) + vbox.set_border_width(16) + + # Toolbar (compatibility with old-toolbars). + if not OLD_TOOLBARS: + toolbar_box = ToolbarBox() + activity_button = ActivityButton(self) + toolbar_box.toolbar.insert(activity_button, 0) + activity_button.show() + + title_entry = TitleEntry(self) + toolbar_box.toolbar.insert(title_entry, -1) + title_entry.show() + + share_button = ShareButton(self) + toolbar_box.toolbar.insert(share_button, -1) + share_button.show() + + separator = gtk.SeparatorToolItem() + separator.props.draw = False + separator.set_expand(True) + toolbar_box.toolbar.insert(separator, -1) + separator.show() + + stop_button = StopButton(self) + toolbar_box.toolbar.insert(stop_button, -1) + stop_button.show() + + self.set_toolbox(toolbar_box) + toolbar_box.show() + else: + toolbox = ActivityToolbox(self) + self.set_toolbox(toolbox) + toolbox.show() + + # transbox: <label> - <text entry> - <speak button> + transbox = gtk.Table() + transbox.resize(2, 3) + transbox.set_row_spacings(8) + transbox.set_col_spacings(12) + + # Labels. + label1 = gtk.Label(_("Word") + ':') + label1.set_alignment(xalign=0.0, yalign=0.5) + label2 = gtk.Label(_("Translation") + ':') + label2.set_alignment(xalign=0.0, yalign=0.5) + + # Text entry box to enter word to be translated. + self.totranslate = gtk.Entry(max=50) + self.totranslate.connect("changed", self.totranslate_cb) + self.totranslate.modify_font(pango.FontDescription("Sans 14")) + + # Text entry box to receive word translated. + self.translated = gtk.Entry(max=50) + self.translated.set_property('editable', False) + self.translated.modify_font(pango.FontDescription("Sans 14")) + + # Speak buttons. + speak1 = gtk.ToolButton() + speak_icon1 = Icon(icon_name='microphone') + speak1.set_icon_widget(speak_icon1) + speak1.connect("clicked", self.speak1_cb) + speak2 = gtk.ToolButton() + speak_icon2 = Icon(icon_name='microphone') + speak2.set_icon_widget(speak_icon2) + speak2.connect("clicked", self.speak2_cb) + + transbox.attach(label1, 0, 1, 0, 1, xoptions=gtk.FILL) + transbox.attach(self.totranslate, 1, 2, 0, 1, xoptions=gtk.FILL|gtk.EXPAND) + transbox.attach(speak1, 2, 3, 0, 1, xoptions=gtk.FILL) + + transbox.attach(label2, 0, 1, 1, 2, xoptions=gtk.FILL) + transbox.attach(self.translated, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND) + transbox.attach(speak2, 2, 3, 1, 2, xoptions=gtk.FILL) + + vbox.pack_start(transbox, expand=False) + + # The language choice combo boxes. + self.lang1combo = gtk.combo_box_new_text() + self.lang1combo.append_text("English") + self.lang1combo.connect("changed", self.lang1combo_cb) + self.lang1combo.set_active(0) + + self.lang2combo = gtk.combo_box_new_text() + for x in self.langs: + self.lang2combo.append_text(x) + self.lang2combo.connect("changed", self.lang2combo_cb) + self.lang2combo.set_active(4) + + self.lang1combo.set_size_request(600,50) + self.lang2combo.set_size_request(600,50) + + # The "lang1" treeview box + self.lang1model = gtk.ListStore(str) + lang1view = gtk.TreeView(self.lang1model) + lang1view.set_headers_visible(False) + lang1cell = gtk.CellRendererText() + lang1treecol = gtk.TreeViewColumn("", lang1cell, text=0) + lang1view.get_selection().connect("changed", self.lang1sel_cb) + lang1view.append_column(lang1treecol) + lang1scroll = gtk.ScrolledWindow(hadjustment=None, vadjustment=None) + lang1scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + lang1scroll.add(lang1view) + + # The "lang2" box + self.lang2model = gtk.ListStore(str) + lang2view = gtk.TreeView(self.lang2model) + lang2view.set_headers_visible(False) + lang2cell = gtk.CellRendererText() + lang2treecol = gtk.TreeViewColumn("", lang2cell, text=0) + lang2view.get_selection().connect("changed", self.lang2sel_cb) + lang2view.append_column(lang2treecol) + lang2scroll = gtk.ScrolledWindow(hadjustment=None, vadjustment=None) + lang2scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + lang2scroll.add(lang2view) + + lang1_vbox = gtk.VBox(spacing=8) + lang1_vbox.pack_start(self.lang1combo, expand=False) + lang1_vbox.pack_start(lang1scroll) + + lang2_vbox = gtk.VBox(spacing=8) + lang2_vbox.pack_start(self.lang2combo, expand=False) + lang2_vbox.pack_start(lang2scroll) + + hbox.pack_start(lang1_vbox) + hbox.pack_start(lang2_vbox) + + vbox.pack_start(hbox) + self.set_canvas(vbox) + self.totranslate.grab_focus() + self.show_all() + + def say(self, text, lang): + # No Portuguese accent yet. + if lang == "portuguese": + lang = "spanish" + tmpfile = "/tmp/something.wav" + subprocess.call(["espeak", text, "-w", tmpfile, "-v", lang]) + subprocess.call(["aplay", tmpfile]) + os.unlink(tmpfile) + + def lang1combo_cb(self, combo): + pass + + def lang2combo_cb(self, combo): + self.languagemodel.SetLanguages("English", self.langs[combo.get_active()]) + + def lang1sel_cb(self, column): + # FIXME: Complete the text entry box + model, _iter = column.get_selected() + value = model.get_value(_iter,0) + translations = self.languagemodel.GetTranslations(0, value) + self.translated.set_text(",".join(translations)) + + def lang2sel_cb(self, column): + model, _iter = column.get_selected() + value = model.get_value(_iter,0) + translations = self.languagemodel.GetTranslations(1, value) + self.translated.set_text(",".join(translations)) + + def speak1_cb(self, button): + text = self.totranslate.get_text() + lang = self.fromlang.lower() + self.say(text, lang) + + def speak2_cb(self, button): + text = self.translated.get_text() + lang = self.tolang.lower() + self.say(text, lang) + + def totranslate_cb(self, totranslate): + entry = totranslate.get_text() + # Ask for completion suggestions + if not entry: + return + + (list1, list2) = self.languagemodel.GetSuggestions(entry) + self.lang1model.clear() + self.lang2model.clear() + for x in list1: + self.lang1model.append([x]) + for x in list2: + self.lang2model.append([x]) + + # If we think we know what the word will be, translate it. + if entry in list1 or len(list1) == 1 and len(list2) == 0: + langiter = self.lang2combo.get_active() + lang = self.langs[langiter].lower() + self.fromlang = "English" + self.tolang = lang + translations = self.languagemodel.GetTranslations(0, list1[0]) + self.translated.set_text(",".join(translations)) + + elif entry in list2 or len(list1) == 0 and len(list2) == 1: + langiter = self.lang2combo.get_active() + lang = self.langs[langiter].lower() + self.fromlang = lang + self.tolang = "English" + translations = self.languagemodel.GetTranslations(1, list2[0]) + self.translated.set_text(",".join(translations)) |