#!/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.
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']
else:
catID = "0"
# 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, "<strong>","</strong>")
def insertTag_Italic(self, widget):
self.tagInsertionLogic(widget, "<em>", "</em>")
def insertTag_Uline(self, widget):
self.tagInsertionLogic(widget, "<span style=\"text-decoration: underline;\">", "</span>")
def insertTag_Strike(self, widget):
self.tagInsertionLogic(widget, "<span style=\"text-decoration: line-through;\">", "</span>")
def insertTag_Left(self, widget):
self.tagInsertionLogic(widget, "<div style=\"text-align: left;\">", "</div>")
def insertTag_Center(self, widget):
self.tagInsertionLogic(widget, "<div style=\"text-align: center;\">", "</div>")
def insertTag_Right(self, widget):
self.tagInsertionLogic(widget, "<div style=\"text-align: right;\">", "</div>")
def insertTag_Fill(self, widget):
self.tagInsertionLogic(widget, "<div style=\"text-align: justify;\">", "</div>")
# 0.6 - More tags to insert for more fun! Hooray!
def insertTag_Block(self,widget):
self.tagInsertionLogic(widget, "<blockquote>", "</blockquote>")
def insertTag_Para(self,widget):
self.tagInsertionLogic(widget, "<p>", "</p>")
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 = '<a href=\"' + self.linkURL + '\" target=\"' + self.linkTarget + '\">' + text + '</a>'
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('<a href=\"' + self.linkURL + '\" target=\"' + self.linkTarget + '\"></a>', -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("<img src=\"" + self.imageURL + "\" align=\"" + self.imageAlign + "\" width=\"" + self.imageWidth + "\" height=\"" + self.imageHeight + "\" alt=\"" + self.imageAlt + "\" / >", -1)
def imageHide(self, widget, foo):
self.imageDialog.hide()
return gtk.TRUE
# 0.6 - These function control inserting the table tags.
def showTableDialog(self, widget):
self.tableDialog = self.mainGlade.get_widget("tableDialog")
self.tableRowsEntry = self.mainGlade.get_widget("tableRowsEntry")
self.tableColsEntry = self.mainGlade.get_widget("tableColsEntry")
self.tableWidthEntry = self.mainGlade.get_widget("tableWidthEntry")
self.tableSpacingEntry = self.mainGlade.get_widget("tableSpacingEntry")
self.tablePaddingEntry = self.mainGlade.get_widget("tablePaddingEntry")
self.tableBorderEntry = self.mainGlade.get_widget("tableBorderEntry")
self.tableCancelButton = self.mainGlade.get_widget("tableCancelButton")
self.tableDialog.show()
self.tableDialog.connect_object("delete_event", self.tableHide, foo)
self.tableCancelButton.connect_object("clicked", self.tableHide, widget, foo)
def insertTableTag(self, widget):
self.mainStatus.push(1, "")
self.tableCols = self.tableColsEntry.get_text()
self.tableRows = self.tableRowsEntry.get_text()
self.tableWidth = self.tableWidthEntry.get_text()
self.tablePadding = self.tablePaddingEntry.get_text()
self.tableSpacing = self.tableSpacingEntry.get_text()
self.tableBorder = self.tableBorderEntry.get_text()
try:
int(self.tableRows)
# 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("<table width=\"" + self.tableWidth +"\" border=\"" + self.tableBorder + "\" cellspacing=\"" + self.tableSpacing + "\" cellpadding=\"" + self.tablePadding + "\">\n")
for i in range(0, int(self.tableRows)):
self.buffer.insert_at_cursor("<tr>")
for i in range(0, int(self.tableCols)):
self.buffer.insert_at_cursor("<td>Insert Text Here</td>")
self.buffer.insert_at_cursor("</tr>\n")
self.buffer.insert_at_cursor("</table>")
self.tableHide(widget, foo)
except:
self.mainStatus.push(1, "Please enter a numeric value for table columns and rows.")
def tableHide(self, widget, foo):
self.tableDialog.hide()
return gtk.TRUE
def callPreview(self, widget, foo, page):
# 0.7 - This just exports all the necessary arguments to our preview function library
if page == 1:
preview.previewEntry(self.mainGlade, self.view)
elif page == 2:
# 0.96 - D'OH! I spend hours debugging only to find that I forgot to
# add the right callback for the Advanced tab. I'm an idiot...
preview.previewEntry(self.mainGlade, self.view)
else:
pass
def callSpellCheck(self, widget):
SpellCheck = spellcheck.SpellCheck()
SpellCheck.displaySpellWindow(self.mainGlade)
# This function initializes the app on load, calling the main function.
# When the main function is called __init__ is done automagically.
if __name__ == "__main__":
blogtk = BloGTK()
blogtk.main()
|