Tentative Patch to Let Gnome-Blog Check Your Spelling



Hi, 

this is a (tentative) patch to let Gnome-Blog
(http://www.gnome.org/seth/gnome-blog/index.html) check your spelling.
One can choose the language in the preference section. It uses aspell
and is partly "stolen" from BloGtk (http://blogtk.sf.net). 

A screenshot can be find under:
http://www.ronny-klein.de/linux/archives/gnome-blog-can-spell-checking.html. 
And the patch is also available from: 
http://www.ronny-klein.de/linux/archives/gnome-blog-diff-2004-02-15-19-04-37

I'm utterly new to programming, so don't blame me for anything. However,
as a non-native English speaker I'd just needed this feature, and it
seems that Seth is waiting until spell checking is integrated into PyGtk
which is, of course, the preferred way to do so. 

I've submitted the patch to Seth, but, I've gotten no answer yet. So,
I've decided to post this here because I think this is an eagerly
expected feature. Any suggestion is welcome :o)

How to apply:

     1. Download Gnome-Blog 0.7 from the site mentioned above. 
     2. mv ~/YourDownloadDirectory/gnome-blog-diff-2004-02-15-19-04-37
        /PythonLibDirectory/site-packages/gnome-blog/
     3. cd /PythonLibDirectory/site-packages/gnome-blog
     4. patch < gnome-blog-diff-2004-02-15-19-04-37
     5. rm gnome-blog-diff-2004-02-15-19-04-37

Start Gnome-Blog new. Happy Blogging!

Index: blog.py
===================================================================
RCS file: /home/rklein/Home/Downloads/Quellen/cvsroot/gnome-blog/blog.py,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 blog.py
--- blog.py	15 Feb 2004 13:22:43 -0000	1.1.1.1
+++ blog.py	15 Feb 2004 18:04:17 -0000
@@ -2,7 +2,7 @@
 
 def getBlogList (gconf_prefix):
     client = gconf.client_get_default()
-    (username, password, protocol, url) = _getSettings(client, gconf_prefix)
+    (username, password, protocol, url, lang) = _getSettings(client, gconf_prefix)
     blog_backend = _getBlogBackend(protocol)
 
     return blog_backend.getBlogList(username, password, url, client, gconf_prefix)
@@ -10,7 +10,7 @@
     
 def postEntry (title, entry, gconf_prefix):
     client = gconf.client_get_default()
-    (username, password, protocol, url) = _getSettings(client, gconf_prefix)
+    (username, password, protocol, url, lang) = _getSettings(client, gconf_prefix)
     blog_backend = _getBlogBackend(protocol)
           
     return blog_backend.postEntry(username, password,
@@ -24,8 +24,9 @@
     password = client.get_string(gconf_prefix + "/blog_password")
     protocol = client.get_string(gconf_prefix + "/blog_protocol")
     url      = client.get_string(gconf_prefix + "/xmlrpc_url")
+    lang     = client.get_string(gconf_prefix + "/blog_lang")
 
-    return (username, password, protocol, url)
+    return (username, password, protocol, url, lang)
 
 def _getBlogBackend(protocol):
     modulename = "gnomeblog.%s" % (protocol)
Index: blog_poster.py
===================================================================
RCS file: /home/rklein/Home/Downloads/Quellen/cvsroot/gnome-blog/blog_poster.py,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 blog_poster.py
--- blog_poster.py	15 Feb 2004 13:22:43 -0000	1.1.1.1
+++ blog_poster.py	15 Feb 2004 17:02:49 -0000
@@ -8,6 +8,7 @@
 from gnomeblog import hig_alert
 from gnomeblog import rich_entry
 from gnomeblog import blog
+from gnomeblog import spellcheck
 
 gconf_prefix = None
 
@@ -45,7 +46,8 @@
         buttonBox.pack_end(self.postButtonAlignment)
 
         boldToggle   = self.blogEntry.createStyleToggle([("weight", pango.WEIGHT_BOLD)], gtk.STOCK_BOLD, "strong")
-        italicToggle = self.blogEntry.createStyleToggle([("style", pango.STYLE_ITALIC)], gtk.STOCK_ITALIC, "em")        
+        italicToggle = self.blogEntry.createStyleToggle([("style", pango.STYLE_ITALIC)], gtk.STOCK_ITALIC, "em")
+        spellButton  = spellcheck.InsertSpellCheckButton(self.blogEntry, gtk.STOCK_SPELL_CHECK, prefs_key)
         linkButton   = rich_entry.InsertHyperlinkButton(self.blogEntry)
         
         #link_tag = self.blogBuffer.create_tag("a")
@@ -54,7 +56,8 @@
         #linkButton = InsertButton
 
         buttonBox.pack_start(boldToggle, expand=gtk.FALSE)
-        buttonBox.pack_start(italicToggle, expand=gtk.FALSE)        
+        buttonBox.pack_start(italicToggle, expand=gtk.FALSE)
+        buttonBox.pack_start(spellButton, expand=gtk.FALSE)
         buttonBox.pack_start(linkButton, expand=gtk.FALSE)
         if (extra_button != None):
             buttonBox.pack_start(extra_button, expand=gtk.FALSE)
Index: blogger_prefs.py
===================================================================
RCS file: /home/rklein/Home/Downloads/Quellen/cvsroot/gnome-blog/blogger_prefs.py,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 blogger_prefs.py
--- blogger_prefs.py	15 Feb 2004 13:22:43 -0000	1.1.1.1
+++ blogger_prefs.py	15 Feb 2004 17:04:05 -0000
@@ -1,5 +1,7 @@
 import gtk
 import gconf
+import commands
+import re
 
 import gettext
 _ = gettext.gettext
@@ -51,32 +53,42 @@
                                                    ("MetaWeblog", "MetaWeblog")])
         self.blogProtocolLabel = LeftLabel("Blog Protocol:")
         
+        self.langMenu = gconf_widgets.OptionMenu(gconf_prefix + "/blog_lang")
+        self.langDict = re.compile('([\w-]+)').findall(commands.getoutput('aspell dump dicts'))
+        self.langUser=[]
+        for self.langDictItem in self.langDict:
+            self.langUser.append((self.langDictItem, self.langDictItem))
+        self.langMenu.setStringValuePairs(self.langUser)
+        self.langMenuLabel = LeftLabel(_("Language:"))
+        
         self.urlEntry = gconf_widgets.Entry(gconf_prefix + "/xmlrpc_url")
         self.urlEntry.set_width_chars(45)
         self.urlLabel = LeftLabel(_("Blog Base URL:"))
 
-	self.blogLabel = LeftLabel(_("Blog Name:"))
+        self.blogLabel = LeftLabel(_("Blog Name:"))
         self.blogMenu = gconf_widgets.OptionMenu(gconf_prefix + "/blog_id")
         self.lookupButton = gtk.Button(_("Lookup Blogs"))
         self.lookupButton.connect("clicked", self._onLookupBlogsButton)
 
 
-        table = gtk.Table(rows=4, columns=3)
+        table = gtk.Table(rows=5, columns=3)
         table.set_row_spacings(12)
         table.set_col_spacings(6)
 
         table.attach(self.blogProtocolLabel, 0, 1, 0, 1, xoptions=gtk.FILL)
         table.attach(self.urlLabel, 0, 1, 1, 2, xoptions=gtk.FILL)
-        table.attach(LeftLabel("Username:"), 0, 1, 2, 3, xoptions=gtk.FILL)
-        table.attach(LeftLabel("Password:"), 0, 1, 3, 4, xoptions=gtk.FILL)
-        table.attach(self.blogLabel, 0, 1, 4, 5, xoptions=gtk.FILL)
+        table.attach(self.langMenuLabel, 0 , 1, 2, 3, xoptions=gtk.FILL)
+        table.attach(LeftLabel("Username:"), 0, 1, 3, 4, xoptions=gtk.FILL)
+        table.attach(LeftLabel("Password:"), 0, 1, 4, 5, xoptions=gtk.FILL)
+        table.attach(self.blogLabel, 0, 1, 5, 6, xoptions=gtk.FILL)
 
         table.attach(self.blogProtocolMenu, 1, 3, 0, 1)
         table.attach(self.urlEntry, 1, 3, 1, 2)
-        table.attach(gconf_widgets.Entry(gconf_prefix + "/blog_username"), 1, 3, 2, 3)
-        table.attach(gconf_widgets.Entry(gconf_prefix + "/blog_password", gtk.TRUE), 1, 3, 3, 4)
-        table.attach(self.blogMenu, 1, 2, 4, 5)
-        table.attach(self.lookupButton, 2, 3, 4, 5, xoptions=gtk.FILL)
+        table.attach(self.langMenu, 1, 3, 2, 3)
+        table.attach(gconf_widgets.Entry(gconf_prefix + "/blog_username"), 1, 3, 3, 4)
+        table.attach(gconf_widgets.Entry(gconf_prefix + "/blog_password", gtk.TRUE), 1, 3, 4, 5)
+        table.attach(self.blogMenu, 1, 2, 5, 6)
+        table.attach(self.lookupButton, 2, 3, 5, 6, xoptions=gtk.FILL)
 
         vbox = gtk.VBox()
         vbox.pack_start(blogTypeBox)
Index: spellcheck.py
===================================================================
RCS file: spellcheck.py
diff -N spellcheck.py
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ spellcheck.py	15 Feb 2004 17:04:53 -0000
@@ -0,0 +1,263 @@
+import gtk
+import commands
+import os
+import re
+import cPickle
+import gconf
+
+from gnomeblog import blog
+
+foo = 0
+
+class InsertSpellCheckButton(gtk.Button):
+    def __init__(self, rich_entry, stock_icon_id, prefs_key):
+        gtk.Button.__init__(self) 
+        self.rich_entry = rich_entry
+        self.prefs_key = prefs_key
+        self.buffer = self.rich_entry.get_buffer()        
+        self.connect("clicked", self._onClicked)
+        image = gtk.Image()
+        image.set_from_stock(stock_icon_id, gtk.ICON_SIZE_SMALL_TOOLBAR)
+        self.add(image)
+        image.show()        
+
+    def _onClicked(self, button):
+        self.SpellCheck = SpellCheck(self.rich_entry, self.prefs_key)
+        self.SpellCheck.displaySpellWindow()
+        
+class SpellCheck:
+   def __init__(self, buffer, prefs_key):
+      self.gconf_prefix = prefs_key
+      self.buffer = buffer
+      
+   def displaySpellWindow(self):
+
+      self.spellWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
+      self.spellWindow.set_title("Check Spelling")
+      self.spellWindow.set_border_width(6)
+      self.spellWindow.set_size_request(400, 250)
+      self.spellWindow.set_modal(gtk.TRUE)
+      
+      self.hbox = gtk.HBox()
+      self.hbox.set_spacing(12)
+        
+      self.vboxLeft = gtk.VBox()
+      self.vboxLeft.set_spacing(6)      
+      self.vboxRight = gtk.VBox()
+      self.vboxRight.set_spacing(6)  
+      
+      self.mistakeLabel = gtk.Label("Not in Dictionary:")
+      self.mistakeLabel.set_alignment(0.0, 0.5)
+        
+      self.changeLabel = gtk.Label("Change To:")
+      self.changeLabel.set_alignment(0.0, 0.5)
+        
+      self.replacementsLabel = gtk.Label("Suggested Replacements:")
+      self.replacementsLabel.set_alignment(0.0, 0.5)
+       
+      self.mistakeEntry = gtk.Entry()
+      self.mistakeEntry.set_editable(gtk.FALSE)
+              
+      self.changeEntry  = gtk.Entry()
+      self.replacementsCombo = gtk.Combo()
+       
+      self.vboxLeft.pack_start(self.mistakeLabel, expand=gtk.FALSE)
+      self.vboxLeft.pack_start(self.mistakeEntry, expand=gtk.FALSE)
+      self.vboxLeft.pack_start(self.changeLabel, expand=gtk.FALSE)
+      self.vboxLeft.pack_start(self.changeEntry, expand=gtk.FALSE)
+      self.vboxLeft.pack_start(self.replacementsLabel, expand=gtk.FALSE)
+      self.vboxLeft.pack_start(self.replacementsCombo, expand=gtk.FALSE)
+       
+      self.separator = gtk.VSeparator()
+       
+      self.changeButton = gtk.Button("C_hange Word")
+      self.ignoreButton = gtk.Button("_Ignore Word")
+      self.addDictButton = gtk.Button("_Add To Dictionary")
+      self.cancelButton = gtk.Button("_Cancel", gtk.STOCK_CANCEL)
+      self.cancelButton.grab_focus()
+      
+      self.vboxRight.pack_start(self.changeButton, expand=gtk.FALSE)
+      self.vboxRight.pack_start(self.ignoreButton, expand=gtk.FALSE)
+      self.vboxRight.pack_start(self.addDictButton, expand=gtk.FALSE)
+      self.vboxRight.pack_end(self.cancelButton, expand=gtk.FALSE)
+        
+      self.hbox.pack_start(self.vboxLeft)
+      self.hbox.pack_start(self.separator)
+      self.hbox.pack_start(self.vboxRight)
+
+      self.spellWindow.add(self.hbox)
+      self.spellWindow.show_all()
+
+      self.spellWindow.connect_object("delete_event", self.windowHider, self.spellWindow)
+      self.cancelButton.connect_object("clicked", self.windowHider, self.spellWindow, foo)
+
+      self.replacementsCombo.entry.connect_object("changed", self.fillReplacement, foo)
+      self.ignoreButton.connect("clicked", self.advanceIter)
+      self.changeButton.connect("clicked", self.replaceWord)
+      self.addDictButton.connect("clicked", self.addtoCustomDict)
+
+      # Here's were we check for the existence of our custom dictionary. If it doesn't
+      # exist, we create it. If it does, we unpickle the data.
+      
+      self.customDictDir = os.path.expanduser('~') + "/.gnome-blog"
+      if os.path.exists(self.customDictDir) == 0:
+         os.mkdir(self.customDictDir)
+         
+      self.customDictLocation = self.customDictDir + "/custom.dict"
+      
+      if os.path.isfile(self.customDictLocation) == 0:
+         print "Creating a new custom dictionary"
+         self.customDict = open(self.customDictLocation, "w")
+         self.jargon = ["blog", "Blogger", "trackback", "pingback"]
+         cPickle.dump(self.jargon, self.customDict)
+         self.customDict.close()
+      else:
+         self.customDict = open(self.customDictLocation, "rw")
+         self.jargon = cPickle.load(self.customDict)
+         self.customDict.close()
+
+      self.spellWindow.show()
+
+      self.writeFile()
+
+   def writeFile(self):
+      self.bodyView = self.buffer
+      self.buffer = self.bodyView.get_buffer()
+      self.startiter = self.buffer.get_start_iter()
+      self.enditer = self.buffer.get_end_iter()
+      self.body = self.buffer.get_text(self.startiter, self.enditer, include_hidden_chars=1)
+
+      self.fileLocation = "/tmp/" + str(os.getuid()) + ".gnomeblog.tmp"
+      self.file = open(self.fileLocation, "w")
+      self.file.write(self.body)
+      self.file.close()
+
+      # We need to set our iter for parsing the entry at the beginning of the TextBuffer.
+
+      self.entryIter = self.startiter
+
+      self.spellcheck()
+
+   def spellcheck(self):
+
+      # Here's where we make our call to aspell to process our temporary file
+      client = gconf.client_get_default()
+      self.blog_lang = blog._getSettings(client, self.gconf_prefix)[4]
+      self.spelling = commands.getoutput('aspell -H --encoding=utf-8 -a < ' + self.fileLocation + ' --master=' + self.blog_lang)
+      self.wordlist = []
+      self.corrections = []
+
+      # This code uses regular expressions to strip out the HTML from our results.
+      # It has been shamelessly cribbed from http://www.intertwingly.net/code/mombo/spellcheck.py.
+      self.spelling = re.compile('^& (\w+) \d+ \d+: (.*)',re.M).findall(self.spelling)
+ 
+      # Now we create two lists - one list has our spelling mistakes, the other has our list
+      # of suggested replacements.
+      for found,suggest in self.spelling:
+         if found in self.jargon: continue
+         self.wordlist.append(found)
+         self.corrections.append(suggest.split(", "))
+
+      if self.wordlist == []:
+        self.windowHider(self.spellWindow, foo)
+        errDialog = gtk.Dialog(title="Spell Check", parent=self.spellWindow, flags=0)
+        errDialog.set_border_width(6)
+        errDialog.set_modal(gtk.TRUE)
+        button2 = gtk.Button(stock=gtk.STOCK_OK)
+        button2.connect_object("clicked", gtk.Widget.destroy, errDialog)
+        errDialog.action_area.pack_start(button2, gtk.TRUE, gtk.TRUE, 0)
+        button2.show()
+
+        errLabel = gtk.Label("No misspelled words found.")
+        errDialog.vbox.pack_start(errLabel, gtk.TRUE, gtk.TRUE, 2)
+
+        errLabel.show()
+        errDialog.show()
+      else:
+         self.iterator = 0
+         self.populateSpellWindow()
+
+   def populateSpellWindow(self):
+
+      try:
+         self.mistakeEntry.set_text(self.wordlist[self.iterator])
+
+         self.suggestions = self.corrections[self.iterator]
+
+         self.replacementsCombo.set_popdown_strings(self.suggestions)
+         
+         self.setMark(self.wordlist[self.iterator])
+
+      except:
+         pass
+
+   def replaceWord(self, widget):
+
+       self.setMark(self.wordlist[self.iterator])
+       self.buffer.delete_selection(0,0)
+
+       self.buffer.insert_at_cursor(self.changeEntry.get_text())
+
+       self.entryIter = self.buffer.get_iter_at_mark(self.insMark)
+          
+       self.advanceIter(foo)
+
+   def fillReplacement(self, widget):
+
+      self.replacementSuggestion = self.replacementsCombo.entry.get_text()
+
+      self.changeEntry.set_text(self.replacementSuggestion)
+
+   def advanceIter(self, widget):
+
+      self.iterator = self.iterator + 1
+
+      self.entryIter = self.buffer.get_iter_at_mark(self.selMark)
+
+      if self.iterator == len(self.wordlist):
+
+         self.windowHider(self.spellWindow, foo)
+
+         errDialog = gtk.Dialog(title="Spell Check", parent=None, flags=0)
+         errDialog.set_border_width(6)
+         errDialog.set_modal(gtk.TRUE)
+         button2 = gtk.Button(stock=gtk.STOCK_OK)
+         button2.connect_object("clicked", gtk.Widget.destroy, errDialog)
+         errDialog.action_area.pack_start(button2, gtk.TRUE, gtk.TRUE, 0)
+         button2.show()
+
+         errLabel = gtk.Label("Spell Check Complete.")
+         errDialog.vbox.pack_start(errLabel, gtk.TRUE, gtk.TRUE, 2)
+         errLabel.show()
+         errDialog.show()
+
+      else:
+         self.populateSpellWindow()
+
+   def addtoCustomDict(self, widget):
+
+      self.word = self.mistakeEntry.get_text()
+
+
+
+      self.jargon.append(self.mistakeEntry.get_text())
+
+      cPickle.dump(self.jargon, open(self.customDictLocation, "w"))
+      self.customDict.close()
+
+      self.advanceIter(widget)
+
+   def windowHider(self, widget, foo):
+      # Strike me down, and I'll become invisible like Obi-Wan did...
+      widget.hide()
+      return gtk.FALSE
+
+   def setMark(self, wordToMark):
+      self.selMark = self.buffer.get_selection_bound()
+      self.insMark = self.buffer.get_insert()
+         
+      self.match_start, self.match_end = self.entryIter.forward_search(self.wordlist[self.iterator], gtk.TEXT_SEARCH_TEXT_ONLY)
+      self.buffer.move_mark(self.selMark, self.match_end)
+      self.buffer.move_mark(self.insMark, self.match_start)
+      
+      self.bodyView.scroll_mark_onscreen(self.insMark)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]