#!/usr/bin/python

####
# File: gnome-blosxom
# Author: Chris Ladd
# Created: May 12, 2004
####

####
# Copyright (c) 2004 Chris Ladd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
####

import os
import time
import gtk
import pango
import gnome
import gnome.ui
import ftplib
import xml.dom.minidom

gtkspell_exists = 1
try :
    import gtkspell
except :
    gtkspell_exists = 0

VERSION = "1.0"
PIXMAPDIR = "/usr/share/pixmaps"

class Settings :
    
    def __init__(self):
        self.server = ""
        self.username = ""
        self.password = ""
        self.directory = ""
        self.extension = ""
    
    def Load(self) :
        try :
            file = open(os.path.expanduser("~/.gnome2_private/gnome-blosxom"), "r")
            document = xml.dom.minidom.parse(file)
            
            self.server = document.documentElement.getAttribute("server")
            self.username = document.documentElement.getAttribute("username")
            self.password = document.documentElement.getAttribute("password")
            self.directory = document.documentElement.getAttribute("directory")
            self.extension = document.documentElement.getAttribute("extension")
            
            file.close()
        except :
            self.server = ""
            self.username = ""
            self.password = ""
            self.directory = ""
            self.extension = "txt"
            
    def Save(self) :
        file = open(os.path.expanduser("~/.gnome2_private/gnome-blosxom"), "w")
        document = xml.dom.minidom.parseString("<gnome-blosxom></gnome-blosxom>")
        
        document.documentElement.setAttribute("server", str(self.server))
        document.documentElement.setAttribute("username", str(self.username))
        document.documentElement.setAttribute("password", str(self.password))
        document.documentElement.setAttribute("directory", str(self.directory))
        document.documentElement.setAttribute("extension", str(self.extension))
        document.writexml(file)
        
        file.close()

class Application(gnome.ui.App) :

    def Clear(self) :
        self.title_entry.set_text("")
        self.textview.get_buffer().set_text("")
        self.category_entry.set_text("")
        
    def DeleteCallback(self, widget, event, data = None) :
        return gtk.FALSE

    def DestroyCallback(self, widget, data = None) :
        gtk.main_quit()
    
    def PostCallback(self, widget, data = None) :
        # Create the temp file
        os.chdir("/tmp")
        filename = "%i.%s" % (int(time.time()), self.settings.extension)
        
        file = open(filename, "w")
        file.write(self.title_entry.get_text())
        file.write("\n")
        file.write(self.textview.get_buffer().get_text(self.textview.get_buffer().get_start_iter(), self.textview.get_buffer().get_end_iter()))
        file.close()
        
        # Connect to the ftp server
        try :
            ftp = ftplib.FTP(self.settings.server)
        except :
            dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Unable to connect to %s." % self.settings.server)
            dialog.run()
            dialog.hide()
            return gtk.TRUE
            
        try :
            ftp.login(self.settings.username, self.settings.password)
        except:
            dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Unable to login to %s." % self.settings.server)
            dialog.run()
            dialog.hide()
            return gtk.TRUE
            
        try :
            ftp.cwd(self.settings.directory)
        except :
            dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Unable to change to directory %s." % self.settings.directory)
            dialog.run()
            dialog.hide()
            ftp.quit()
            return gtk.TRUE
        
        # Change into the correct catagory folder, creating them as you go if needed
        categories = self.category_entry.get_text().split("/")
        for category in categories :
            try :
                ftp.cwd(category)
            except :
                try :
                    ftp.mkd(category)
                except :
                    dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Unable to make directory %s." % category)
                    dialog.run()
                    dialog.hide()
                    ftp.quit()
                    return gtk.TRUE
                    
                try :
                    ftp.cwd(category)
                except :
                    dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Unable to change to directory %s." % category)
                    dialog.run()
                    dialog.hide()
                    ftp.quit()
                    return gtk.TRUE
        
        # Upload the blog entry
        file = open(filename, "rb")
        
        try :
            ftp.storbinary("STOR %s" % filename, file)
        except :
            dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Unable to upload file to %s." % self.settings.server)
            dialog.run()
            dialog.hide()
            ftp.quit()
            file.close()
            return gtk.TRUE
            
        ftp.quit()
        file.close()
        
        # Clean up
        os.remove(filename)
        
        # Store the settings
        self.settings.Save()
        
        # Clear everything
        self.Clear()
        
        # Reload the Settings
        self.settings.Load()
        
        return gtk.TRUE
        
    def SettingsCallback(self, widget, data = None) :
        dialog = gtk.Dialog("Settings", self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
        
        table = gtk.Table(5, 2, gtk.FALSE)
        table.set_col_spacings(6)
        dialog.vbox.pack_start(table, gtk.TRUE, gtk.TRUE, 6)
        
        server_label = gtk.Label("Server:")
        server_label.set_alignment(0.0, 0.5)
        table.attach(server_label, 0, 1, 0, 1, gtk.FILL, xpadding=6)
        server_entry = gtk.Entry()
        server_entry.set_text(self.settings.server)
        table.attach(server_entry, 1, 2, 0, 1, xpadding=6)
        
        username_label = gtk.Label("Username:")
        username_label.set_alignment(0.0, 0.5)
        table.attach(username_label, 0, 1, 1, 2, gtk.FILL, xpadding=6)
        username_entry = gtk.Entry()
        username_entry.set_text(self.settings.username)
        table.attach(username_entry, 1, 2, 1, 2, xpadding=6)
        
        password_label = gtk.Label("Password:")
        password_label.set_alignment(0.0, 0.5)
        table.attach(password_label, 0, 1, 2, 3, gtk.FILL, xpadding=6)
        password_entry = gtk.Entry()
        password_entry.set_text(self.settings.password)
        table.attach(password_entry, 1, 2, 2, 3, xpadding=6)
        
        directory_label = gtk.Label("Directory:")
        directory_label.set_alignment(0.0, 0.5)
        table.attach(directory_label, 0, 1, 3, 4, gtk.FILL, xpadding=6)
        directory_entry = gtk.Entry()
        directory_entry.set_text(self.settings.directory)
        table.attach(directory_entry, 1, 2, 3, 4, xpadding=6)
        
        extension_label = gtk.Label("File Extension:")
        extension_label.set_alignment(0.0, 0.5)
        table.attach(extension_label, 0, 1, 4, 5, gtk.FILL, xpadding=6)
        extension_entry = gtk.Entry()
        extension_entry.set_text(self.settings.extension)
        table.attach(extension_entry, 1, 2, 4, 5, xpadding=6)
        
        dialog.set_default_size(400, 200)
        dialog.show_all()
        dialog.run()
        dialog.hide()
    
        self.settings.server = server_entry.get_text()
        self.settings.username = username_entry.get_text()
        self.settings.password = password_entry.get_text()
        self.settings.directory = directory_entry.get_text()
        self.settings.extension = extension_entry.get_text()
        
        self.settings.Save()
    
        return gtk.TRUE
        
    def KeyPressCallback(self, widget, event, data=None) :
        if event.keyval == 65289 :
            # A Hack until PyGTK 2.4...
            self.category_entry.grab_focus()
            return gtk.TRUE
        
        return gtk.FALSE
        
    def AboutCallback(self, widget, data = None) :
        gnome.ui.About("Gnome Blosxom", VERSION, "Copyright 2004 Chris Ladd", "Blosxom Blog Posting Tool", ["Chris Ladd <caladd@particlestorm.net>"], None, None, self.image.get_pixbuf()).show()
    
        return gtk.TRUE
        
    def BoldCallback(self, widget, data = None) :
        buffer = self.textview.get_buffer()
        
        if buffer.get_selection_bound() !=  buffer.get_insert() :
            if buffer.get_iter_at_mark(buffer.get_selection_bound()).compare(buffer.get_iter_at_mark(buffer.get_insert())) == -1 :
                buffer.insert(buffer.get_iter_at_mark(buffer.get_selection_bound()), "<b>")
                buffer.insert(buffer.get_iter_at_mark(buffer.get_insert()), "</b>")
            else :
                buffer.insert(buffer.get_iter_at_mark(buffer.get_selection_bound()), "</b>")
                buffer.insert(buffer.get_iter_at_mark(buffer.get_insert()), "<b>")
            
            buffer.move_mark(buffer.get_selection_bound(), buffer.get_iter_at_mark(buffer.get_insert()))
            
        return gtk.TRUE
    
    def ItalicCallback(self, widget, data = None) :
        buffer = self.textview.get_buffer()
        
        if buffer.get_selection_bound() !=  buffer.get_insert() :
            if buffer.get_iter_at_mark(buffer.get_selection_bound()).compare(buffer.get_iter_at_mark(buffer.get_insert())) == -1 :
                buffer.insert(buffer.get_iter_at_mark(buffer.get_selection_bound()), "<i>")
                buffer.insert(buffer.get_iter_at_mark(buffer.get_insert()), "</i>")
            else :
                buffer.insert(buffer.get_iter_at_mark(buffer.get_selection_bound()), "</i>")
                buffer.insert(buffer.get_iter_at_mark(buffer.get_insert()), "<i>")
                
            buffer.move_mark(buffer.get_selection_bound(), buffer.get_iter_at_mark(buffer.get_insert()))
        
        return gtk.TRUE
    
    def LinkCallback(self, widget, data = None) :
        buffer = self.textview.get_buffer()
        selection_iter = buffer.get_iter_at_mark(buffer.get_selection_bound())
        insert_mark = buffer.get_insert()
        
        if buffer.get_selection_bound() != insert_mark :
            dialog = gtk.Dialog("Insert Link Tags", self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
        
            hbox = gtk.HBox(gtk.FALSE, 0)
            hbox.pack_start(gtk.Label("Address: "), gtk.FALSE, gtk.FALSE, 6)
            entry = gtk.Entry()
            entry.set_size_request(300, -1)
            hbox.pack_start(entry, gtk.TRUE, gtk.TRUE, 5)
            hbox.show_all()
            dialog.vbox.pack_start(hbox, gtk.TRUE, gtk.TRUE, 5)
            
            response = dialog.run()
            dialog.hide()
        
            if response == gtk.RESPONSE_ACCEPT :
                if selection_iter.compare(buffer.get_iter_at_mark(insert_mark)) == -1 :
                    buffer.insert(selection_iter, '<a href="%s">' % entry.get_text())
                    buffer.insert(buffer.get_iter_at_mark(insert_mark), "</a>")
                else :
                    buffer.insert(selection_iter, "</a>")
                    buffer.insert(buffer.get_iter_at_mark(insert_mark), '<a href="%s">' % entry.get_text())
                buffer.move_mark(buffer.get_selection_bound(), buffer.get_iter_at_mark(buffer.get_insert()))
        
        return gtk.TRUE
    
    def __init__(self) :
        self.settings = Settings()
        self.settings.Load()
        
        # Setup the application
        gnome.ui.App.__init__(self, "Gnome Blosxom", "Gnome Blosxom")
        
        # Setup the main window
        self.image = gtk.Image();
        self.image.set_from_file(PIXMAPDIR + "/gnome-blosxom.png");

        self.set_icon(self.image.get_pixbuf());
        
        self.connect("delete_event", self.DeleteCallback)
        self.connect("destroy", self.DestroyCallback)
        
        vbox = gtk.VBox(gtk.FALSE, 0)
        
        # Setup the main menubar
        self.menu_items = (
            ("/_File", None, None, 0, "<Branch>"),
            ("/File/_Post", "<control>P", self.PostCallback, 0, "<StockItem>", gtk.STOCK_SAVE),
            ("/File/_Settings...", "<control>S", self.SettingsCallback, 0, "<StockItem>", gtk.STOCK_PREFERENCES),
            ("/File/Separator", None, None, 0, "<Separator>"),
            ("/File/_Quit", "<control>Q", self.DestroyCallback, 0, "<StockItem>", gtk.STOCK_QUIT),
            ("/For_mat", None, None, 0, "<Branch>"),
            ("/Format/_Bold", "<control>B", self.BoldCallback, 0, "<StockItem>", gtk.STOCK_BOLD),
            ("/Format/_Italic", "<control>I", self.ItalicCallback, 0, "<StockItem>", gtk.STOCK_ITALIC),
            ("/Format/_Link...", "<control>L", self.LinkCallback, 0, "<StockItem>", gtk.STOCK_JUMP_TO),
            ("/_Help", None, None, 0, "<Branch>"),
            ("/_Help/_About...", None, self.AboutCallback, 0, "<StockItem>", "gnome-stock-about")
        )
    
        self.accel_group = gtk.AccelGroup()
        self.item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>", self.accel_group)
        self.item_factory.create_items(self.menu_items)
        self.add_accel_group(self.accel_group)
    
        self.menubar = self.item_factory.get_widget("<main>")
        self.set_menus(self.menubar)
    
        # Setup the toolbar
        self.toolbar = gtk.Toolbar();
        self.toolbar.append_item("Post", "Post the entry", "", gtk.image_new_from_stock(gtk.STOCK_SAVE, gtk.ICON_SIZE_SMALL_TOOLBAR), self.PostCallback)
        self.toolbar.append_item("Settings", "Set the program settings", "", gtk.image_new_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_SMALL_TOOLBAR), self.SettingsCallback)
        self.toolbar.append_space()
        self.toolbar.append_item("Bold", "Insert bold tags", "", gtk.image_new_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR), self.BoldCallback)
        self.toolbar.append_item("Italic", "Insert italic tags", "", gtk.image_new_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR), self.ItalicCallback)
        self.toolbar.append_item("Link", "Insert link tags", "", gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, gtk.ICON_SIZE_SMALL_TOOLBAR), self.LinkCallback)
        self.set_toolbar(self.toolbar)
        
        # Setup the layout controls
        hbox_top = gtk.HBox(gtk.FALSE, 0)
        hbox_middle = gtk.HBox(gtk.FALSE, 0)
        hbox_bottom = gtk.HBox(gtk.FALSE, 0)
        
        vbox.pack_start(hbox_top, gtk.FALSE, gtk.FALSE, 6)
        vbox.pack_start(hbox_middle, gtk.TRUE, gtk.TRUE, 0)
        vbox.pack_start(hbox_bottom, gtk.FALSE, gtk.FALSE, 6)
        
        # Setup the title label
        self.title_label = gtk.Label("Title:")
        hbox_top.pack_start(self.title_label, gtk.FALSE, gtk.FALSE, 6)
        
        # Setup the title entry
        self.title_entry = gtk.Entry()
        hbox_top.pack_start(self.title_entry, gtk.TRUE, gtk.TRUE, 6)
        
        # Setup the content textview
        self.scrolledwindow = gtk.ScrolledWindow()
        self.scrolledwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
        self.scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
        self.textview = gtk.TextView()
        self.textview.set_wrap_mode(gtk.WRAP_WORD);
        self.textview.connect("key-press-event", self.KeyPressCallback)
        if (gtkspell_exists) :
            self.testview_spell = gtkspell.Spell(self.textview)
        self.scrolledwindow.add(self.textview)
        hbox_middle.pack_start(self.scrolledwindow, gtk.TRUE, gtk.TRUE, 6)

        # Setup the category label
        self.category_label = gtk.Label("Category:")
        hbox_bottom.pack_start(self.category_label, gtk.FALSE, gtk.FALSE, 6)
        
        # Setup category entry
        self.category_entry = gtk.Entry();
        hbox_bottom.pack_start(self.category_entry, gtk.TRUE, gtk.TRUE, 6)
        
        # Setup the post button
        post_hbox = gtk.HBox(gtk.FALSE, 6)
        post_hbox.pack_start(gtk.Label(""), gtk.TRUE, gtk.TRUE, 0) 
        post_hbox.pack_start(gtk.image_new_from_stock(gtk.STOCK_SAVE, gtk.ICON_SIZE_BUTTON), gtk.FALSE, gtk.FALSE, 0)
        post_hbox.pack_start(gtk.Label("Post"), gtk.FALSE, gtk.FALSE, 0)
        post_hbox.pack_start(gtk.Label(""), gtk.TRUE, gtk.TRUE, 0) 
        self.button = gtk.Button()
        self.button.add(post_hbox)
        self.button.set_size_request(84, 30)
        self.button.connect("clicked", self.PostCallback)
        hbox_bottom.pack_start(self.button, gtk.FALSE, gtk.FALSE, 6)
        
        # Show everything
        self.set_contents(vbox)
        self.set_default_size(500, 450)
        self.set_focus(self.button)
        self.show_all()
    
def Main() :
    program = gnome.init("gnome-blosxom", VERSION)
	
    # Check to make sure the right version of PyGTK is installed
    if gtk.pygtk_version[0] is 1 :
        message = "You appear to be running PyGTK version %i.%i.%i but this program requires version 2.0 or greater.\n\nPlease upgrade to a newer version." % gtk.pygtk_version
        dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, message)
        dialog.run()
    else :
        application = Application()
    
        gtk.main()

# Start the program
if __name__ == "__main__" :
    Main()
