#!/usr/bin/env python # BloGTK Version 1.1 # (C)2004 Jay Reding # Code released under the terms of the BSD License. (See file LICENSE) # This program allows users to post to various weblog systems without starting a # web browser. import pygtk pygtk.require("2.0") # This fixes a problem that sometimes causes an earlier # library to be loaded import gtk import gtk.glade import gtkhtml2 import pango import gobject import os import ConfigParser import cPickle import sys import string import xmlrpclib # Import modules from the BloGTK app tree. import config import post import customtags import preview import spellcheck import proxy # 0.5-1 - Python 2.3 doesn't like values named None as arguments. Hence, I will # be a smart-ass and replace 'None' with 'foo' foo = 0 # 1.1 - I should also make a global variable for the version number so that I don't # have to constantly be changing strings. version = "1.1" class BloGTK: def delete_event(self, widget, event, data=None): return gtk.FALSE def destroy(self, widget, data=None): gtk.main_quit() def displayPrefs(self, widget): # 0.7 - Here's where we do the new preferences code... prefsInstance = config.blogtkPrefs() prefsInstance.drawPrefs(self.mainGlade, foo) # 0.3 - When we load the prefs we want to ensure that the user must # reconnect with the new prefs before posting. self.postButton.set_sensitive(gtk.FALSE) # 0.9 - We also ensure that the title entry must be explictly reactivated # for MetaWeblog or MT users. self.titleEntry.set_sensitive(gtk.FALSE) # 0.9 - We should also make it clear that when you pop up the preferences # window you disconnect from the server. self.mainStatus.push(1, "Disconnected from server. Use File/Connect to re-connect") # 0.95 - And you can't retrieve a post list while disconnected... DUH! self.recallMenuOption.set_sensitive(gtk.FALSE) # 0.95 - We also need to disable our other entry systems. self.titleEntry.set_sensitive(gtk.FALSE) self.extendedView.set_sensitive(gtk.FALSE) self.excerptView.set_sensitive(gtk.FALSE) self.commentsCheck.set_sensitive(gtk.FALSE) self.pingsCheck.set_sensitive(gtk.FALSE) self.breaksCheck.set_sensitive(gtk.FALSE) self.keywordEntry.set_sensitive(gtk.FALSE) self.trackbackEntry.set_sensitive(gtk.FALSE) def __init__(self): # Open the glade file doors, Hal! self.mainGlade = gtk.glade.XML('/usr/share/blogtk/blogtk.glade') self.mainWindow = self.mainGlade.get_widget('mainWindow') # Let's grab some widgets for later editing/manipulating/inappropriate fondling self.blogCombo = self.mainGlade.get_widget('blogCombo') self.titleEntry = self.mainGlade.get_widget('titleEntry') self.bodyView = self.mainGlade.get_widget('bodyView') self.publishCheck = self.mainGlade.get_widget('publishCheck') self.catCombo = self.mainGlade.get_widget('catCombo') self.mainStatus = self.mainGlade.get_widget('mainStatus') self.postButton = self.mainGlade.get_widget('postButton') self.postsWindow = self.mainGlade.get_widget('recallDialog') self.editPostsItem = self.mainGlade.get_widget('recall1') self.mainStatus = self.mainGlade.get_widget('mainStatus') self.recallMenuOption = self.mainGlade.get_widget('recall1') self.extendedView = self.mainGlade.get_widget('extendedView') self.excerptView = self.mainGlade.get_widget('excerptView') self.keywordEntry = self.mainGlade.get_widget('keywordEntry') self.trackbackEntry = self.mainGlade.get_widget('trackbackEntry') self.breaksCheck = self.mainGlade.get_widget('breaksCheck') self.pingsCheck = self.mainGlade.get_widget('pingsCheck') self.commentsCheck = self.mainGlade.get_widget('commentsCheck') # Here's where we get our callbacks. This time, we don't even have to sleep # with the director. self.mainWindow.connect("delete_event", self.delete_event) self.mainWindow.connect("destroy", self.destroy) self.blogCombo.entry.connect("changed", self.blogCheck, foo) # We can autoconnect the signals from the menu items as they don't require # multiple args. self.mainGlade.signal_autoconnect({'on_preferences1_activate': self.displayPrefs}) self.mainGlade.signal_autoconnect({'on_quit1_activate': self.destroy}) self.mainGlade.signal_autoconnect({'on_connect1_activate': self.getBlogs}) self.mainGlade.signal_autoconnect({'on_new1_activate': self.confirmClear}) self.mainGlade.signal_autoconnect({'on_open1_activate': self.fileOpen}) self.mainGlade.signal_autoconnect({'on_save1_activate': self.fileSave}) self.mainGlade.signal_autoconnect({'on_save_as1_activate': self.fileSaveAs}) self.mainGlade.signal_autoconnect({'on_about1_activate': self.displayAbout}) self.mainGlade.signal_autoconnect({'on_recall1_activate': self.showPostsWin}) self.mainGlade.signal_autoconnect({'on_postButton_clicked': self.prepPost}) # Check for the existence of our new preferences directory self.homeDir = os.path.expanduser('~') self.configDir = self.homeDir + "/.BloGTK" if os.path.exists(self.configDir) == 0: print "Creating new BloGTK prefs directory" os.mkdir(self.configDir) # Now that we have a config dir, let's check for that config file if os.path.isfile(self.configDir + "/BloGTK.conf") == 0: # Oh crap, there's no config file! What to do? Create one! print "Config file not found - Will Open Prefs!" self.displayPrefs(self) else: self.grabConfig() # 0.6 - We also want to create our custom tags file if it doesn't already exist. if os.path.isfile(self.configDir + "/tags.conf") == 0: # Well, now we should create one. print "Creating file for custom tag entry" conf = open(self.configDir + "/tags.conf", "w") conf.write("; tags.conf\n") conf.write("; Custom tag data file for BloGTK.\n\n") conf.close() else: pass # 0.3 - We now have our own unique appkey! Hooray! self.appkey = "542ACD141588E5FEA3970055CF5796008A9063" # 0.4 - We don't want the ability to edit posts unless we've already connected # to a server. self.editPostsItem.set_sensitive(gtk.FALSE) # 0.4 - We want to set the hidden postIDLabel widget to a value of 'New' for all # new posts. self.postIDLabel = self.mainGlade.get_widget('postIDLabel') self.postIDLabel.set_text('New') # 0.4 - Here's where we attach our toolbar callbacks. self.mainGlade.signal_autoconnect({'on_newToolButton_clicked': self.confirmClear}) self.mainGlade.signal_autoconnect({'on_openToolButton_clicked': self.fileOpen}) self.mainGlade.signal_autoconnect({'on_saveToolButton_clicked': self.fileSave}) self.mainGlade.signal_autoconnect({'on_boldToolButton_clicked': self.insertTag_Bold}) self.mainGlade.signal_autoconnect({'on_italicToolButton_clicked': self.insertTag_Italic}) self.mainGlade.signal_autoconnect({'on_ulineToolButton_clicked': self.insertTag_Uline}) self.mainGlade.signal_autoconnect({'on_strikeToolButton_clicked': self.insertTag_Strike}) self.mainGlade.signal_autoconnect({'on_leftToolButton_clicked': self.insertTag_Left}) self.mainGlade.signal_autoconnect({'on_centerToolButton_clicked': self.insertTag_Center}) self.mainGlade.signal_autoconnect({'on_rightToolButton_clicked': self.insertTag_Right}) self.mainGlade.signal_autoconnect({'on_fillToolButton_clicked': self.insertTag_Fill}) self.mainGlade.signal_autoconnect({'on_cutToolButton_clicked': self.cut}) self.mainGlade.signal_autoconnect({'on_copyToolButton_clicked': self.copy}) self.mainGlade.signal_autoconnect({'on_pasteToolButton_clicked': self.paste}) self.mainGlade.signal_autoconnect({'on_cut1_activate': self.cut}) self.mainGlade.signal_autoconnect({'on_copy1_activate': self.copy}) self.mainGlade.signal_autoconnect({'on_paste1_activate': self.paste}) self.mainGlade.signal_autoconnect({'on_edit_tags1_activate': self.custTags}) self.mainGlade.signal_autoconnect({'on_applyTagButton_clicked': self.applyCustTag}) self.mainGlade.signal_autoconnect({'on_paraToolButton_clicked': self.insertTag_Para}) self.mainGlade.signal_autoconnect({'on_blockToolButton_clicked': self.insertTag_Block}) self.mainGlade.signal_autoconnect({'on_linkToolButton_clicked': self.showLinkDialog}) self.mainGlade.signal_autoconnect({'on_imageToolButton_clicked': self.showImageDialog}) self.mainGlade.signal_autoconnect({'on_tableToolButton_clicked': self.showTableDialog}) self.mainGlade.signal_autoconnect({'on_notebook2_switch_page': self.callPreview}) self.mainGlade.signal_autoconnect({'on_spellToolButton_clicked': self.callSpellCheck}) #self.notebook2 = self.mainGlade.get_widget('notebook2') #self.notebook2.connect("switch_page", self.callPreview) # 0.6 - These signal connections fix a problem where entries would be made once for # each button press. Using signal_autoconnect is a hack, but it works, so I'm happy... self.mainGlade.signal_autoconnect({'on_linkOK_clicked': self.makeLink}) self.mainGlade.signal_autoconnect({'on_imageOKButton_clicked': self.insertImageTag}) self.mainGlade.signal_autoconnect({'on_tableOKButton_clicked': self.insertTableTag}) # 0.9 - We need to activate our toolbar tooltips. Hopefully this will work - if not there is # a patch in Bugzilla to fix tooltips in toolbars and PyGTK. self.toolbar1 = self.mainGlade.get_widget('toolbar1') self.toolbar2 = self.mainGlade.get_widget('toolbar2') self.toolbar1.set_tooltips(gtk.TRUE) self.toolbar2.set_tooltips(gtk.TRUE) # 0.5 - We need to initialize our file pointer. self.file = "" # 0.6 - We need to pull our custom tag list from the config file as well. self.mainTagCombo = self.mainGlade.get_widget("mainTagCombo") confDir = os.path.expanduser('~') + "/.BloGTK" conf_file = confDir + "/tags.conf" config = ConfigParser.ConfigParser() config.readfp(open(conf_file)) tags = config.sections() self.mainTagCombo.set_popdown_strings(tags) # 0.9-3 - First we need to get our TreeView... self.treeView = self.mainGlade.get_widget('blogTreeView') # 0.9-3 - Now we need to initiate our List Store... self.model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) self.treeView.set_model(self.model) self.treeView.set_headers_visible(gtk.TRUE) renderer=gtk.CellRendererText() column=gtk.TreeViewColumn("Post Title",renderer, text=0) column.set_resizable(gtk.TRUE) self.treeView.append_column(column) self.treeView.show() # 0.7 - We need to initialize our preview system on init. self.view = gtkhtml2.View() scrollwindow = gtk.ScrolledWindow() scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrollwindow.set_shadow_type(gtk.SHADOW_IN) scrollwindow.add(self.view) vbox = self.mainGlade.get_widget('preview_vbox') vbox.pack_start(scrollwindow) scrollwindow.show() self.view.show() scrollwindow.connect('focus', self.callPreview, foo) # 0.95 - Let's try and pull our tooltips back into our toolbars, since # libglade doesn't yet seem to do so. (Although the patch is on bugzilla.) # First, we'll pull all our toolbuttons, then we'll assign their tooltips. self.tooltips = gtk.Tooltips() self.newToolButton = self.mainGlade.get_widget('newToolButton') self.openToolButton = self.mainGlade.get_widget('openToolButton') self.saveToolButton = self.mainGlade.get_widget('saveToolButton') self.cutToolButton = self.mainGlade.get_widget('cutToolButton') self.copyToolButton = self.mainGlade.get_widget('copyToolButton') self.pasteToolButton = self.mainGlade.get_widget('pasteToolButton') self.boldToolButton = self.mainGlade.get_widget('boldToolButton') self.italicToolButton = self.mainGlade.get_widget('italicToolButton') self.ulineToolButton = self.mainGlade.get_widget('ulineToolButton') self.strikeToolButton = self.mainGlade.get_widget('strikeToolButton') self.leftToolButton = self.mainGlade.get_widget('leftToolButton') self.centerToolButton = self.mainGlade.get_widget('centerToolButton') self.rightToolButton = self.mainGlade.get_widget('rightToolButton') self.fillToolButton = self.mainGlade.get_widget('fillToolButton') self.paraToolButton = self.mainGlade.get_widget('paraToolButton') self.blockToolButton = self.mainGlade.get_widget('blockToolButton') self.linkToolButton = self.mainGlade.get_widget('linkToolButton') self.imageToolButton = self.mainGlade.get_widget('imageToolButton') self.tableToolButton = self.mainGlade.get_widget('tableToolButton') self.applyTagButton = self.mainGlade.get_widget('applyTagButton') self.spellToolButton = self.mainGlade.get_widget('spellToolButton') self.tooltips.set_tip(self.newToolButton, "Create a new entry") self.tooltips.set_tip(self.openToolButton, "Open a saved entry") self.tooltips.set_tip(self.saveToolButton, "Save current entry") self.tooltips.set_tip(self.cutToolButton, "Cut selected text to clipboard") self.tooltips.set_tip(self.copyToolButton, "Copy selected text to clipboard") self.tooltips.set_tip(self.pasteToolButton, "Paste text in clipboard") self.tooltips.set_tip(self.cutToolButton, "Open a saved entry") self.tooltips.set_tip(self.boldToolButton, "Make text bold") self.tooltips.set_tip(self.italicToolButton, "Make text italicized") self.tooltips.set_tip(self.ulineToolButton, "Underline text") self.tooltips.set_tip(self.strikeToolButton, "Strikethrough text") self.tooltips.set_tip(self.leftToolButton, "Align text left") self.tooltips.set_tip(self.centerToolButton, "Align text center") self.tooltips.set_tip(self.rightToolButton, "Align text right") self.tooltips.set_tip(self.fillToolButton, "Justify text") self.tooltips.set_tip(self.paraToolButton, "Add paragraph") self.tooltips.set_tip(self.blockToolButton, "Add blockquote") self.tooltips.set_tip(self.linkToolButton, "Insert new link") self.tooltips.set_tip(self.imageToolButton, "Insert an image") self.tooltips.set_tip(self.tableToolButton, "Insert a table") self.tooltips.set_tip(self.applyTagButton, "Apply custom tag") self.tooltips.set_tip(self.spellToolButton, "Spellcheck post") def main(self): gtk.main() def grabConfig(self): # 0.7 - We also need to set the account selection widget to the default account name of # 'Default' (creative, ain't I?). # Accounts can be changed from the Account and Settings window. # Also, we need to see if someone is using an older config that the old default of # 'server' gets changed over to default. self.blogNameLabel = self.mainGlade.get_widget('blogNameLabel') if self.blogNameLabel.get_text() == "": self.blogNameLabel.set_text("Default") else: pass self.sectionName = self.blogNameLabel.get_text() # 0.5 Pull up our values from the config file using Python's builtin ConfigParser module self.conf = ConfigParser.ConfigParser() self.conf.readfp(open(self.configDir + "/BloGTK.conf")) # 0.7 - Here's where we change the default 'server' entry to the new default of 'Default' self.sections = self.conf.sections() for item in self.sections: if item == "server": self.conf.add_section("Default") self.url = self.conf.get("server", "server") self.user = self.conf.get("server", "user") self.passwd = self.conf.get("server", "pass") self.system = self.conf.get("server", "system") try: self.font = self.conf.get("server", "font") except ConfigParser.NoOptionError, error: self.font = "Sans 12" self.conf.set("Default", "server", self.url) self.conf.set("Default", "user", self.user) self.conf.set("Default", "pass", self.passwd) self.conf.set("Default", "system", self.system) self.conf.set("Default", "font", self.font) self.conf.remove_option("server", "server") self.conf.remove_option("server", "user") self.conf.remove_option("server", "pass") self.conf.remove_option("server", "system") try: self.conf.remove_option("server", "font") except: pass self.conf.remove_section("server") file = open(self.configDir + "/BloGTK.conf", "w") self.conf.write(file) file.close() self.url = self.conf.get(self.sectionName, 'server') self.user = self.conf.get(self.sectionName, 'user') self.passwd = self.conf.get(self.sectionName, 'pass') self.system = self.conf.get(self.sectionName, 'system') # 0.5 - If there's an error with importing the font selection, # set the font value. try: self.font = self.conf.get(self.sectionName, 'font') # 0.3 - Pull our font selection from the config and apply it to the editor windows. font_desc = pango.FontDescription(self.font) self.bodyView.modify_font(font_desc) self.titleEntry.modify_font(font_desc) self.extendedView.modify_font(font_desc) self.excerptView.modify_font(font_desc) except ConfigParser.NoOptionError, error: print "Adding default font section" self.conf.set('server', 'font', 'Sans 12') conf_file = open(self.configDir + "/BloGTK.conf", 'w+') self.conf.write(conf_file) conf_file.close() self.font = "Sans 12" # 0.9 - If we're upgrading from a previous version, our general options won't have been # set yet. Therefore we'll now have to set them to their default values. try: self.useUTF = self.conf.get("Default", "useUTF") self.defaultPublish = self.conf.get("Default", "defaultPublish") self.retrievalNumber = self.conf.get("Default", "retrievalNumber") if self.defaultPublish == "1": self.publishCheck.set_active(gtk.TRUE) else: pass except: print "Creating general settings configuration..." self.conf.set("Default", "useUTF", "0") self.conf.set("Default", "defaultPublish", "0") self.conf.set("Default", "retrievalNumber", "10") conf_file = open(self.configDir + "/BloGTK.conf", 'w+') self.conf.write(conf_file) conf_file.close() self.useUTF = "0" self.defaultPublish = "0" self.retrievalNumber = "10" self.rpcServer = proxy.get_xmlrpc_server(self.url) def displayAbout(self, widget): self.aboutDialog = self.mainGlade.get_widget('aboutDialog') self.closeButton = self.mainGlade.get_widget('closebutton1') self.aboutDialog.show() self.aboutDialog.connect("delete_event", self.hideAbout) self.closeButton.connect("clicked", self.hideAbout, foo) def hideAbout(self, widget, foo): self.aboutDialog.hide() return gtk.TRUE def confirmClear(self, widget): self.clearDialog = self.mainGlade.get_widget('confirmClear') self.okButton = self.mainGlade.get_widget('okbutton1') self.cancelButton = self.mainGlade.get_widget('cancelbutton1') self.clearDialog.connect("delete_event", self.hideWindow) self.okButton.connect("clicked", self.clearForm, foo) self.cancelButton.connect("clicked", self.hideWindow, foo) self.clearDialog.show() def clearForm (self, widget, foo): self.titleEntry.set_text("") self.clearDialog.hide() buffer = self.bodyView.get_buffer() startiter = buffer.get_start_iter() enditer = buffer.get_end_iter() buffer.delete(startiter, enditer) buffer2 = self.extendedView.get_buffer() startiter = buffer2.get_start_iter() enditer = buffer2.get_end_iter() buffer2.delete(startiter, enditer) buffer3 = self.excerptView.get_buffer() startiter = buffer3.get_start_iter() enditer = buffer3.get_end_iter() buffer3.delete(startiter, enditer) self.keywordEntry.set_text("") self.trackbackEntry.set_text("") # 0.4 - We want to set the hidden postIDLabel widget to a value of 'New' # for all new posts. self.postIDLabel.set_text('New') # 0.5-1 We also want to make sure that we clear the filename when we # create a new file. self.file = "" # 0.96 - We should also let the user know we've done all this... self.mainStatus.push(1, "Post cleared.") def hideWindow(self, widget, foo): # Strike me down, and I'll become invisible like Obi-Wan did... self.clearDialog.hide() return gtk.TRUE def getBlogs(self, widget): self.grabConfig() # Retrieve list of blogs for user. try: blogs = self.rpcServer.blogger.getUsersBlogs(self.appkey, self.user, self.passwd) blogName = [] blogID = [] for item in blogs: blogName.append(item['blogName']) blogID.append(item['blogid']) self.blogCombo.set_popdown_strings(blogName) # 0.4 - We want to enable those hidden options now... self.postButton.set_sensitive(gtk.TRUE) self.editPostsItem.set_sensitive(gtk.TRUE) self.mainStatus.push(1, "Connected to server at " + self.url) except xmlrpclib.Fault, error: errString = str(error) self.mainStatus.push(1, "An error occurred while connecting to the server: " + errString) except: self.mainStatus.push(1, "An error occurred while connecting. Check your settings.") # 0.9 - If the blogging system is either MetaWeblog or Blogger we can activate our Title Entry field... # 0.95 - We can also activate our other options if self.system == "mt": self.titleEntry.set_sensitive(gtk.TRUE) self.extendedView.set_sensitive(gtk.TRUE) self.excerptView.set_sensitive(gtk.TRUE) self.commentsCheck.set_sensitive(gtk.TRUE) self.pingsCheck.set_sensitive(gtk.TRUE) self.breaksCheck.set_sensitive(gtk.TRUE) self.keywordEntry.set_sensitive(gtk.TRUE) self.trackbackEntry.set_sensitive(gtk.TRUE) elif self.system == "metaweblog": self.titleEntry.set_sensitive(gtk.TRUE) self.extendedView.set_sensitive(gtk.TRUE) self.excerptView.set_sensitive(gtk.TRUE) else: pass # 0.95 - We can now also activate our option to edit/delete posts... self.recallMenuOption.set_sensitive(gtk.TRUE) def blogCheck(self, widget, foo): if self.system == "mt": self.getCategories(self, widget) else: return 0 text = self.blogCombo.entry.get_text() # 1.1 - Make sure we pull our version string rather than having to manually update each release. self.mainWindow.set_title("BloGTK " + version + " - " + text) def getCategories(self, widget, foo): blogName = self.blogCombo.entry.get_text() blogs = self.rpcServer.blogger.getUsersBlogs(self.appkey, self.user, self.passwd) # self.blogID = "" for item in blogs: for k,v in item.items(): if item['blogName'] == blogName: # 0.3 - By casting this variable as self, it fixes an assignment error self.blogID = item['blogid'] # Retrieve category list from the server categories = self.rpcServer.mt.getCategoryList(self.blogID, self.user, self.passwd) categoryName = [] categoryID = [] for item in categories: categoryName.append(item['categoryName']) categoryID.append(item['categoryId']) if categoryName != []: categoryName.sort(lambda x, y: cmp(string.lower(x), string.lower(y))) self.catCombo.set_popdown_strings(categoryName) else: print "No Categories To File" categoryName = [""] self.catCombo.set_popdown_strings(categoryName) def prepPost(self, widget): # We also need to retrieve the blogID and catID informtion... checkPublish = self.publishCheck.get_active() # Grab the title. title = self.titleEntry.get_text() # Grab that body, and hopefully we won't get sued for sexual harrassment. buffer = self.bodyView.get_buffer() startiter = buffer.get_start_iter() enditer = buffer.get_end_iter() body = buffer.get_text(startiter, enditer, include_hidden_chars=1).encode("utf-8") # Now to pull our blogid. blogName = self.blogCombo.entry.get_text() blogs = self.rpcServer.blogger.getUsersBlogs(self.appkey, self.user, self.passwd) for item in blogs: for k,v in item.items(): if item['blogName'] == blogName: blogID = item['blogid'] # Are we using MT? If so, we need to pull the category ID as well. catID = "0" if self.system == "mt": catName = self.catCombo.entry.get_text() cats = self.rpcServer.mt.getCategoryList(blogID, self.user, self.passwd) for item in cats: for k,v in item.items(): if item['categoryName'] == catName: catID = item['categoryId'] # 0.95 - We also need to pull our extended entry as well as our other # fields buffer = self.extendedView.get_buffer() startiter = buffer.get_start_iter() enditer = buffer.get_end_iter() extended = buffer.get_text(startiter, enditer, include_hidden_chars=1).encode("utf-8") buffer = self.excerptView.get_buffer() startiter = buffer.get_start_iter() enditer = buffer.get_end_iter() excerpt = buffer.get_text(startiter, enditer, include_hidden_chars=1).encode("utf-8") keywords = self.keywordEntry.get_text() trackbackURLS = self.trackbackEntry.get_text() if self.breaksCheck.get_active() == gtk.TRUE: breaks = "1" else: breaks = "0" if self.commentsCheck.get_active() == gtk.TRUE: commentsAllow = "1" else: commentsAllow = "0" if self.pingsCheck.get_active() == gtk.TRUE: pingsAllow = "1" else: pingsAllow = "0" # 0.4 - We need to determine if this is a new post, or one that's being edited. self.postStatus = self.postIDLabel.get_text() if self.postStatus == 'New': post.getPostInfo(self.url, self.user, self.passwd, self.system, blogID, catID, title, body, checkPublish, self.mainGlade, self.useUTF, extended, excerpt, keywords, trackbackURLS, breaks, commentsAllow, pingsAllow) else: post.repost(self.url, self.user, self.passwd, self.system, blogID, catID, title, body, checkPublish, self.postStatus, self.mainGlade, self.useUTF, extended, excerpt, keywords, trackbackURLS, breaks, commentsAllow, pingsAllow) def showPostsWin(self, foo): # 0.4 - This pops open our window that lets us retrieve our old posts. # TODO - 0.95 - TODONE self.postsWin_cancel = self.mainGlade.get_widget('recallCancelButton') # 0.95 - These functions allow us to use a ListView to view our posts in a more sensible # manner. self.postsWindow.show() self.postsWindow.connect("delete_event", self.hidePostsWin) self.postsWin_cancel.connect("clicked", self.hidePostsWin, foo) # 0.4 - Let's grab that BlogID from the main combo entry. # We don't need to do error checking here, since we've done this operation before. blogName = self.blogCombo.entry.get_text() blogs = self.rpcServer.blogger.getUsersBlogs(self.appkey, self.user, self.passwd) for item in blogs: for k,v in item.items(): if item['blogName'] == blogName: blogID = item['blogid'] if self.system == "mt": post.mt_grabPostList(self.mainGlade, self.url, self.user, self.passwd, self.system, blogID, self.model, self.treeView, self.retrievalNumber) elif self.system == "blogger": post.blogger_grabPostList(self.mainGlade, self.url, self.user, self.passwd, self.system, blogID, self.model, self.treeView, self.retrievalNumber) elif self.system == "metaweblog": post.mw_grabPostList(self.mainGlade, self.url, self.user, self.passwd, self.system, blogID, self.model, self.treeView, self.retrievalNumber) def hidePostsWin(self, widget, foo): self.model.clear() self.postsWindow.hide() return gtk.TRUE ### BEGIN TOOLBAR TAG INSERTION CODE ### def insertTag_Bold(self, widget): self.tagInsertionLogic(widget, "","") def insertTag_Italic(self, widget): self.tagInsertionLogic(widget, "", "") def insertTag_Uline(self, widget): self.tagInsertionLogic(widget, "", "") def insertTag_Strike(self, widget): self.tagInsertionLogic(widget, "", "") def insertTag_Left(self, widget): self.tagInsertionLogic(widget, "
", "") def insertTag_Para(self,widget): self.tagInsertionLogic(widget, "
", "
") def tagInsertionLogic(self, widget, tagStart, tagEnd): # 0.5 - This code is an amazing kludge, yet it works. In essence, what we do is determine # if there is a selection or not. If not, the code is relatively simple. If there is, we # first grab the selected text, then we add the tags, delete the original, then we insert # the text+tags. After that we actually search for the original text and set the selection # to our search results. As I stated, it's an amazingly convoluted piece of code, but it # works, so I'm willing to live with it. This code is repeated for each button. # 0.95 - Here comes another kludge... we're going to test and see how we can find which # field is actually being used then cast it as our selectedWindow. if self.bodyView.is_focus() == 1: self.selectedWindow = self.bodyView elif self.extendedView.is_focus() == 1: self.selectedWindow = self.extendedView elif self.excerptView.is_focus() == 1: self.selectedWindow = self.excerptView self.buffer = self.selectedWindow.get_buffer() selMark = self.buffer.get_selection_bound() insMark = self.buffer.get_insert() try: start, end = self.buffer.get_selection_bounds() text = self.buffer.get_text(start, end) new_text = tagStart + text + tagEnd self.buffer.delete(start, end) self.buffer.insert(start, new_text, -1) cur_pos = self.buffer.get_iter_at_mark(self.buffer.get_insert()) match_start, match_end = cur_pos.backward_search(text, gtk.TEXT_SEARCH_TEXT_ONLY) self.buffer.move_mark(selMark, match_end) self.buffer.move_mark(insMark, match_start) except: self.buffer.insert_at_cursor(tagStart + tagEnd, -1) end = self.buffer.get_iter_at_mark(selMark) end.backward_chars(len(tagEnd)) self.buffer.place_cursor(end) # 0.4 - This adds our cut/copy/paste logic from the toolbar/menubar def cut(self, widget): if self.bodyView.is_focus() == 1: self.bodyView.emit("cut-clipboard") elif self.titleEntry.is_focus() == 1: self.titleEntry.emit("cut-clipboard") elif self.extendedView.is_focus() == 1: self.extendedView.emit("cut-clipboard") elif self.excerptView.is_focus() == 1: self.excerptView.emit("cut-clipboard") elif self.keywordEntry.is_focus() == 1: self.keywordEntry.emit("cut-clipboard") elif self.trackbackEntry.is_focus() == 1: self.trackbackEntry.emit("cut-clipboard") else: pass def copy(self, widget): if self.bodyView.is_focus() == 1: self.bodyView.emit("copy-clipboard") elif self.titleEntry.is_focus() == 1: self.titleEntry.emit("copy-clipboard") elif self.extendedView.is_focus() == 1: self.extendedView.emit("copy-clipboard") elif self.excerptView.is_focus() == 1: self.excerptView.emit("copy-clipboard") elif self.keywordEntry.is_focus() == 1: self.keywordEntry.emit("copy-clipboard") elif self.trackbackEntry.is_focus() == 1: self.trackbackEntry.emit("copy-clipboard") else: pass def paste(self, widget): if self.bodyView.is_focus() == 1: self.bodyView.emit("paste-clipboard") elif self.titleEntry.is_focus() == 1: self.titleEntry.emit("paste-clipboard") elif self.extendedView.is_focus() == 1: self.extendedView.emit("paste-clipboard") elif self.excerptView.is_focus() == 1: self.excerptView.emit("paste-clipboard") elif self.keywordEntry.is_focus() == 1: self.keywordEntry.emit("paste-clipboard") elif self.trackbackEntry.is_focus() == 1: self.trackbackEntry.emit("paste-clipboard") else: pass # 0.5 - Here is our code for opening arbitrarily saved files. def fileOpen(self, widget): self.openDialog = self.mainGlade.get_widget("openFileDialog") self.openDialog_cancel = self.mainGlade.get_widget("cancel_button3") self.openDialog_ok = self.mainGlade.get_widget("ok_button3") self.openDialog.show() self.openDialog.connect("delete_event", self.openHide) self.openDialog_cancel.connect("clicked", self.openHide, foo) self.openDialog_ok.connect("clicked", self.openFile) def openFile(self, widget): self.file = self.openDialog.get_filename() try: openFile = open(self.file, "r") title = cPickle.load(openFile) body = cPickle.load(openFile) extended = cPickle.load(openFile) excerpt = cPickle.load(openFile) keywords = cPickle.load(openFile) trackbackURLS = cPickle.load(openFile) self.titleEntry.set_text(title) buffer = self.bodyView.get_buffer() buffer.set_text(body) buffer2 = self.extendedView.get_buffer() buffer2.set_text(extended) buffer3 = self.excerptView.get_buffer() buffer3.set_text(excerpt) self.keywordEntry.set_text(keywords) self.trackbackEntry.set_text(trackbackURLS) self.mainStatus.push(1, "Opened File " + self.file) except: self.mainStatus.push(1, "An error occurred in opening the file.") self.file = "" self.openHide(widget, foo) def openHide(self, widget, foo): self.openDialog.hide() return gtk.TRUE # 0.5 - This is where we save our posts to an arbitrary file. def fileSave(self, widget): if self.file == "": self.saveDialog = self.mainGlade.get_widget("saveFileDialog") self.saveDialog_cancel = self.mainGlade.get_widget("cancel_button4") self.saveDialog_ok = self.mainGlade.get_widget("ok_button4") self.saveDialog.show() self.saveDialog.connect("delete_event", self.saveHide) self.saveDialog_cancel.connect("clicked", self.saveHide, foo) self.saveDialog_ok.connect("clicked", self.saveFile) else: self.writeFile(widget, foo) def fileSaveAs(self, widget): self.file = "" self.fileSave(widget) def saveFile(self, widget): self.file = self.saveDialog.get_filename() if os.path.isfile(self.file) == 1: # 1.0 - Rather than creating a new widget in code, we now pull our # confirmation dialog from the Glade file. self.overwriteDialog = self.mainGlade.get_widget('overwriteDialog') self.overwrite_ButtonOK = self.mainGlade.get_widget('overwrite_buttonOK') self.overwrite_ButtonCancel = self.mainGlade.get_widget('overwrite_buttonCancel') self.overwrite_ButtonOK.connect("clicked", self.preWrite, foo) self.overwrite_ButtonCancel.connect("clicked", self.closeSaveDialog) self.overwriteDialog.connect("delete_event", self.closeSaveDialog) self.overwriteDialog.connect("destroy", self.closeSaveDialog) self.overwriteDialog.show() else: self.writeFile(widget, foo) def preWrite(self, widget, foo): self.writeFile(widget, foo) self.closeSaveDialog(widget) def closeSaveDialog(self, widget): self.overwriteDialog.hide() self.saveDialog.hide() return gtk.TRUE def writeFile(self, widget, foo): title = self.titleEntry.get_text() buffer = self.bodyView.get_buffer() startiter = buffer.get_start_iter() enditer = buffer.get_end_iter() body = buffer.get_text(startiter, enditer, include_hidden_chars=1) buffer2 = self.extendedView.get_buffer() startiter = buffer2.get_start_iter() enditer = buffer2.get_end_iter() extended = buffer2.get_text(startiter, enditer, include_hidden_chars=1) buffer3 = self.excerptView.get_buffer() startiter = buffer3.get_start_iter() enditer = buffer3.get_end_iter() excerpt = buffer3.get_text(startiter, enditer, include_hidden_chars=1) keywords = self.keywordEntry.get_text() trackbackURLS = self.trackbackEntry.get_text() saveFile = open(self.file, "w") cPickle.dump(title, saveFile) cPickle.dump(body, saveFile) cPickle.dump(extended, saveFile) cPickle.dump(excerpt, saveFile) cPickle.dump(keywords, saveFile) cPickle.dump(trackbackURLS, saveFile) try: self.saveHide(widget, foo) except: pass saveFile.close() self.mainStatus.push(1, "Wrote post to file: " + self.file) def saveHide(self, widget, foo): self.saveDialog.hide() return gtk.TRUE # 0.6 - This is where we call our new custom tag handing functions. def custTags(self, widget): customtags.displayTagsWindow(self.mainGlade) def applyCustTag(self, widget): mainTagEntry = self.mainGlade.get_widget("mainTagEntry") tag_name = mainTagEntry.get_text() confDir = os.path.expanduser('~') + "/.BloGTK" conf_file = confDir + "/tags.conf" config = ConfigParser.ConfigParser() config.readfp(open(conf_file)) # 0.6 - For some reason, Python throws a NoSectionError with this code, despite the fact that # there's no error. For convenience's sake, we'll escape this error for now. try: start_tag = config.get(tag_name, "start_tag") except ConfigParser.NoSectionError: pass try: script_tag = config.get(tag_name, "script_tag") except ConfigParser.NoSectionError: pass try: end_tag = config.get(tag_name, "end_tag") except ConfigParser.NoSectionError: pass # 0.95 - Here comes another kludge... we're going to test and see how we can find which # field is actually being used then cast it as our selectedWindow. if self.bodyView.is_focus() == 1: self.selectedWindow = self.bodyView elif self.extendedView.is_focus() == 1: self.selectedWindow = self.extendedView elif self.excerptView.is_focus() == 1: self.selectedWindow = self.excerptView self.buffer = self.selectedWindow.get_buffer() selMark = self.buffer.get_selection_bound() insMark = self.buffer.get_insert() child = os.popen(script_tag) script_output = child.read() try: start, end = self.buffer.get_selection_bounds() text = self.buffer.get_text(start, end) new_text = start_tag + script_output + text + end_tag self.buffer.delete(start, end) self.buffer.insert(start, new_text, -1) cur_pos = self.buffer.get_iter_at_mark(self.buffer.get_insert()) match_start, match_end = cur_pos.backward_search(text, gtk.TEXT_SEARCH_TEXT_ONLY) self.buffer.move_mark(selMark, match_end) self.buffer.move_mark(insMark, match_start) except: self.buffer.insert_at_cursor(start_tag + script_output + end_tag, -1) end = self.buffer.get_iter_at_mark(selMark) cur_point = len(end_tag) end.backward_chars(cur_point) self.buffer.place_cursor(end) # 0.6 - Here's where we handle the insertion of links from the link dialog. def showLinkDialog(self, widget): self.linkDialog = self.mainGlade.get_widget("linkDialog") self.linkOKButton = self.mainGlade.get_widget("linkOK") self.linkCancelButton = self.mainGlade.get_widget("linkCancel") self.linkDialog.show() self.linkDialog.connect_object("delete_event", self.linksHide, foo) self.linkCancelButton.connect_object("clicked", self.linksHide, widget, foo) self.linkURLEntry = self.mainGlade.get_widget("linkURLEntry") self.linkTargetEntry = self.mainGlade.get_widget("linkTargetEntry") self.linkTextEntry = self.mainGlade.get_widget("linkTextEntry") def makeLink(self, widget): self.linkURL = self.linkURLEntry.get_text() self.linkTarget = self.linkTargetEntry.get_text() self.linkDialog.hide() # 0.95 - Here comes another kludge... we're going to test and see how we can find which # field is actually being used then cast it as our selectedWindow. if self.bodyView.is_focus() == 1: self.selectedWindow = self.bodyView elif self.extendedView.is_focus() == 1: self.selectedWindow = self.extendedView elif self.excerptView.is_focus() == 1: self.selectedWindow = self.excerptView self.buffer = self.selectedWindow.get_buffer() selMark = self.buffer.get_selection_bound() insMark = self.buffer.get_insert() try: start, end = self.buffer.get_selection_bounds() text = self.buffer.get_text(start, end) new_text = '' + text + '' self.buffer.delete(start, end) self.buffer.insert(start, new_text, -1) cur_pos = self.buffer.get_iter_at_mark(self.buffer.get_insert()) match_start, match_end = cur_pos.backward_search(text, gtk.TEXT_SEARCH_TEXT_ONLY) self.buffer.move_mark(selMark, match_end) self.buffer.move_mark(insMark, match_start) except: self.buffer.insert_at_cursor('', -1) end = self.buffer.get_iter_at_mark(selMark) end.backward_chars(4) self.buffer.place_cursor(end) def linksHide(self, widget, foo): self.linkDialog.hide() return gtk.TRUE #0.6 - These functions are for the image insertion dialog. def showImageDialog(self, widget): self.imageDialog = self.mainGlade.get_widget("imageDialog") self.imageOKButton = self.mainGlade.get_widget("imageOKButton") self.imageCancelButton = self.mainGlade.get_widget("imageCancelButton") self.imageAlignEntry = self.mainGlade.get_widget("imageAlignEntry") self.imageAlignCombo = self.mainGlade.get_widget("imageAlignCombo") self.imageURLEntry = self.mainGlade.get_widget("imageURLEntry") self.imageAltEntry = self.mainGlade.get_widget("imageAltEntry") self.imageHeightEntry = self.mainGlade.get_widget("imageHeightEntry") self.imageWidthEntry = self.mainGlade.get_widget("imageWidthEntry") self.imageDialog.show() self.imageDialog.connect_object("delete_event", self.imageHide, foo) self.imageCancelButton.connect_object("clicked", self.imageHide, widget, foo) self.alignments = ["Left", "Right", "Middle", "AbsMiddle", "Top", "Bottom", "Center"] self.imageAlignCombo.set_popdown_strings(self.alignments) def insertImageTag(self, widget): self.imageURL = self.imageURLEntry.get_text() self.imageAlt = self.imageAltEntry.get_text() self.imageHeight = str(self.imageHeightEntry.get_value_as_int()) self.imageWidth = str(self.imageWidthEntry.get_value_as_int()) self.imageAlign = self.imageAlignEntry.get_text() self.imageDialog.hide() # 0.95 - Here comes another kludge... we're going to test and see how we can find which # field is actually being used then cast it as our selectedWindow. if self.bodyView.is_focus() == 1: self.selectedWindow = self.bodyView elif self.extendedView.is_focus() == 1: self.selectedWindow = self.extendedView elif self.excerptView.is_focus() == 1: self.selectedWindow = self.excerptView self.buffer = self.selectedWindow.get_buffer() self.buffer.insert_at_cursor("| Insert Text Here | ") self.buffer.insert_at_cursor("