Commits

Vladimir Kolev committed 15699c6

Added offline mode and Preferences dialog

Comments (0)

Files changed (4)

 Just run the script from your terminal:
 
 	python gtkpyglot.py
+
+To work in Offline mode with gtkPyglot you need a database file.
+The generation of such one file is still not automated, but you can
+use the one generated from http://l10n.gnome.org/languages/ with
+state of 04.03.2011. 
+Please be advised that this is a big file ~ 348.8MB
+
+Download the langs.db file from the following URL:
+https://www.wuala.com/vkolev/Scripts/langs.db?key=txIFzTBQrudn
 results will be always corrent, but it schould give you a hint how 
 you could translate a specific menu label, button, description etc.
 
+Since version 2.0 gtkPyglot can work in Offline mode. To work in that
+mode you need to have a database file with the translations. Currently
+The application can't generate one, but you can use the one, generated
+on 04.03.2011 from the gnome translations website. Be advised, that this
+database file is really large and containes 55 languages - the ones
+supported by pylyglot. The filesize of the database file is ~ 349MB and
+can be downloaded from the following URL:
+https://www.wuala.com/vkolev/Scripts/langs.db?key=txIFzTBQrudn
+
 Requirements
 ------------
 
-*  Internet connection - since the application still needs to access
-the services from pylyglot and google
+*  Internet connection (to access pylyglot and google)
 *  Python >= 2.6
 *  PyGTK  >= 2.16
 *  python-simplejson
+*  python-pysqlite2
+*  python-configobj
 
 Installation
 ------------
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy project-wide -->
   <object class="GtkWindow" id="window1">
-    <property name="width_request">600</property>
+    <property name="width_request">700</property>
     <property name="height_request">500</property>
-    <property name="title" translatable="yes">gtkPyglot 1.0</property>
+    <property name="title" translatable="yes">gtkPyglot 2.0</property>
     <property name="window_position">center</property>
-    <property name="default_width">600</property>
+    <property name="default_width">700</property>
     <property name="default_height">500</property>
     <property name="icon">pyglot.svg</property>
     <signal name="destroy" handler="on_window1_destroy"/>
               </packing>
             </child>
             <child>
+              <object class="GtkToolButton" id="toolbutton1">
+                <property name="visible">True</property>
+                <property name="tooltip_text" translatable="yes">Edit some application settings</property>
+                <property name="label" translatable="yes">Preferences</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-preferences</property>
+                <signal name="clicked" handler="preferences_button_clicked"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
               <object class="GtkToolButton" id="about_button">
                 <property name="visible">True</property>
                 <property name="tooltip_text" translatable="yes">About this application</property>
     <property name="skip_pager_hint">True</property>
     <property name="has_separator">False</property>
     <property name="program_name">gtkPyglot</property>
-    <property name="version">1.0</property>
+    <property name="version">2.0</property>
     <property name="copyright" translatable="yes">Lincense: GNU/GPL v3</property>
     <property name="comments" translatable="yes">GTK Frontend for the Pylyglot translations 
 website, using their xml-rpc service to retrieve 
       </object>
     </child>
   </object>
+  <object class="GtkDialog" id="prefsdialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Preferences</property>
+    <property name="icon">gtkpyglot.png</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkHBox" id="hbox3">
+                <property name="visible">True</property>
+                <property name="spacing">30</property>
+                <child>
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Database file:</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox6">
+                    <property name="visible">True</property>
+                    <property name="spacing">1</property>
+                    <child>
+                      <object class="GtkEntry" id="entry2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x2022;</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="openbtn">
+                        <property name="label">gtk-open</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">4</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox4">
+                <property name="visible">True</property>
+                <property name="spacing">19</property>
+                <child>
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Working mode:</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="onoffbtn">
+                    <property name="label" translatable="yes">Online</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">5</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox5">
+                <property name="visible">True</property>
+                <property name="spacing">4</property>
+                <child>
+                  <object class="GtkLabel" id="label6">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Default language:</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="combobox2">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="padding">5</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
 </interface>
 #-*- encoding: utf-8 -*-
 
 import sys
+import os
 import pygtk
 pygtk.require("2.0")
 import gtk
 import urllib
 import webbrowser
 import simplejson
-
+from configobj import ConfigObj
+from pysqlite2 import dbapi2 as sqlite3
 
 SERVER_URL = "http://pylyglot.org/rpc_service/"
 GOOGLE_URL = "http://ajax.googleapis.com/ajax/services/language/translate"
 
+# Preconfigurations
+
+# Server information
 server = xmlrpclib.Server(SERVER_URL)
 langs_raw = server.get_languages()
 langs = []
 for lang in langs_raw:
         langs.append(lang['short_name'])
 
+stats = server.get_status()
+
+# Current application path
 cur_path = sys.path[0]
 if cur_path != "":
         cur_path = "%s/" % cur_path        
 
-stats = server.get_status()
-
+# Parameters for the google search
 params = {}
 params['langpair'] = ""
 params['v'] = "1.0"
 params['q'] = ""
 
+# Configuration file parsing
+config = ConfigObj("%sdata/gtkpyglot.conf" % cur_path)
+
 class GtkPylyglot(object):
         
         def __init__(self):
                         "paste_button_clicked" : self.paste_click,
                         "clear_button_clicked" : self.clear_click,
                         "about_button_clicked" : self.show_about,
+                        "preferences_button_clicked" : self.show_prefs,
                         "quit_button_clicked" : gtk.main_quit,
                         "search_button_clicked" : self.search,
                         'translate_button_clicked' : self.translate,
                 langs.sort()
                 for lang in langs:
                         self.langstore.append(['%s' % lang])
-                self.combobox.set_active(0)
+                self.combobox.set_active(int(config['deflang']))
 
                 # Show the statistics in the statusbar
                 self.label_langs = builder.get_object("label1")
                 self.label_trans.set_markup("<b>Translations: </b> %s" % stats['total_translations'])
 
                 # Prepare the table for the results
-                self.store = gtk.ListStore(str, str, str)
+                self.store = gtk.ListStore(str, str, str, str)
                 self.tree_view = builder.get_object('treeview1')
                 self.tree_view.set_model(self.store)
                 self.create_columns(self.tree_view)
         def create_columns(self, treeView):
                 rendererText = gtk.CellRendererText()
                 column = gtk.TreeViewColumn("Translation", rendererText, text=0)
-                column.set_fixed_width(365)
+                column.set_fixed_width(310)
                 column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
                 column.set_resizable(True)
                 column.set_sort_column_id(0)
                 treeView.append_column(column)
 
                 rendererText = gtk.CellRendererText()
-                column = gtk.TreeViewColumn("Last update", rendererText, text=1)
+                column = gtk.TreeViewColumn("Original", rendererText, text=1)
+                column.set_fixed_width(200)
+                column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+                column.set_resizable(True)
+                column.set_sort_column_id(0)
+                treeView.append_column(column)
+
+                rendererText = gtk.CellRendererText()
+                column = gtk.TreeViewColumn("Last update", rendererText, text=2)
                 column.set_sort_column_id(1)
                 treeView.append_column(column)
 
                 rendererText = gtk.CellRendererText()
-                column = gtk.TreeViewColumn("Standard", rendererText, text=2)
+                column = gtk.TreeViewColumn("Standard", rendererText, text=3)
                 column.set_sort_column_id(2)
                 treeView.append_column(column)
 
                         dialog.run()
                         dialog.destroy()
                 else:
+                    if int(config['mode']) == 1:
                         translations = server.get_translation(searchlang, searchterm)
                         if not translations:
                                 resdialog = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT,
                                 self.store.clear()
                                 for trans in translations:
                                         self.store.append(['%s' % trans['translation'],
+                                                           'None',
                                                           '%s' % trans['updatedate'],
                                                           '%s' % trans['standardized']])
+                    else:
+                        if os.path.isfile(config['database']):
+                            con = sqlite3.connect(config['database'])
+                            cur = con.cursor()
+                            langid = self.get_lang_id(searchlang)
+                            searchterm = "%"+searchterm+"%"
+                            cur.execute("select * from core_translation where msgid like :what and language_id=:lang",
+                                        {"what": searchterm, "lang": langid})
+                            result = cur.fetchall()
+                            con.close()
+                            if not result:
+                                dialog = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT,
+                                                          gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE,
+                                                          "Sorry! No results found...")
+                                dialog.run()
+                                dialog.destroy()
+                            else:
+                                self.store.clear()
+                                for res in result:
+                                    self.store.append(['%s' % res[1],
+                                                      '%s' % res[2],
+                                                      '%s' % res[6],
+                                                      '%s'% res[8]])
+                        else:
+                            dialog = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT,
+                                                      gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
+                                                      "Database file is missing!\nPlease provide correct filepath or switch to Online mode")
+                            dialog.run()
+                            dialog.destroy()
+
+        def get_lang_id(self, langname):
+            con = sqlite3.connect(config['database'])
+            cur = con.cursor()
+            cur.execute("select id from core_language where short_name=:lang", {"lang": langname})
+            result = cur.fetchone()
+            return result[0]
 
         def show_about(self, sender):
                 builder = gtk.Builder()
                 self.about.run()
                 self.about.destroy()
 
+        def show_prefs(self, sender):
+                builder = gtk.Builder()
+                builder.add_from_file("%sdata/main-gui.ui" % cur_path)
+                self.prefs = builder.get_object("prefsdialog")
+                self.entry2 = builder.get_object("entry2")
+                self.entry2.set_text(config['database'])
+                self.openbtn = builder.get_object("openbtn")
+                self.openbtn.connect("clicked", self.select_database)
+                self.onoffbtn = builder.get_object("onoffbtn")
+                self.onoffbtn.set_active(bool(config['mode']))
+                self.langselect = builder.get_object("combobox2")
+                 # Show the languages in the combobox
+                self.langstore = gtk.ListStore(str)
+                self.langcell = gtk.CellRendererText()
+                self.langselect.pack_start(self.langcell)
+                self.langselect.add_attribute(self.langcell, 'text', 0)
+                self.langselect.set_model(self.langstore)
+                self.langselect.set_wrap_width(5)
+                langs.sort()
+                for lang in langs:
+                        self.langstore.append(['%s' % lang])
+                self.langselect.set_active(int(config['deflang']))
+                self.prefs.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
+                self.prefs.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_OK)
+                response = self.prefs.run()
+                if response == gtk.RESPONSE_CLOSE:
+                    self.prefs.destroy()
+                else:
+                    config['database'] = self.entry2.get_text()
+                    config['mode'] = int(self.onoffbtn.get_state())
+                    config['deflang'] = int(self.langselect.get_active())
+                    config.write()
+                    self.prefs.destroy()
+
+        def select_database(self, sender):
+            filedialog = gtk.FileChooserDialog("Select Database file:",
+                                              None,
+                                              gtk.FILE_CHOOSER_ACTION_OPEN,
+                                              (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+                                              gtk.STOCK_OPEN, gtk.RESPONSE_OK))
+            filedialog.set_default_response(gtk.RESPONSE_OK)
+            filter = gtk.FileFilter()
+            filter.set_name("DB Files")
+            filter.add_mime_type("application/x-sqlite3")
+            filter.add_pattern("*.db")
+            filedialog.add_filter(filter)
+            response = filedialog.run()
+            if response == gtk.RESPONSE_OK:
+                self.entry2.set_text(filedialog.get_filename())
+            else:
+                filedialog.destroy()
+            filedialog.destroy()
+
+
+
+
         def translate(self, sender):
                 if self.searchbox.get_text() == "":
                         dialog = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT,