#!/usr/bin/env python
# -*- coding: utf-8 -*-

#----------------------------------------------------------------------
# Authors:
#   Bruno Dilly
#
# Copyright (C) 2007 Authors
#
# Released under GNU GPL, read the file 'COPYING' for more information
# ----------------------------------------------------------------------

import pygtk
pygtk.require('2.0')
import gtk

# pickle -- Python object serialization
# The pickle module implements a fundamental, but powerful algorithm for
# serializing and de-serializing a Python object structure. ``Pickling''
# is the process whereby a Python object hierarchy is converted into a 
# byte stream
import pickle
# os -- Miscellaneous operating system interfaces
# This module provides a more portable way of using operating system dependent
# functionality than importing a operating system dependent built-in module
# like posix or nt
import os
import sys

import imclib

import gettext
# finds the locale directory
dir = os.path.dirname(os.path.abspath(sys.argv[0]))
# install gettext
gettext.install('imcgui', os.path.join(dir, 'locale'), unicode=1)

class GUI:

    def error(self, message):
        """
        Display error message.
        """
        print message
    # error()

    def read_file(self, path):
        """
        Returns a read object from a file specified by the path, using the
        pickle module.
        """
        try:
            file = open(path, 'r')
            try:
                object = pickle.load(file)
            except Exception:
                object = None
            file.close()
        except IOError:
            return None
        return object
    # read_file()

    def write_file(self, path, object):
        """
        Writes a given object to a file specified by the path using the pickle
        module.
        """
        # Opens the file to be written
        if os.path.exists(path):
            file = open(path, 'w')
        else:
            file = open(path, 'w')
            os.chmod(path, 0600)
        # pickle is the standard way to make Python objects which can
        # be stored and reused by other programs or by a future 
        # invocation of the same program
        pickle.dump(object, file)
        file.close()
    # write_file()

    def write_configuration(self, item=None, state=None):
        """
        Writes the configuration dictionary to a file, or stores the provided
        item's state in the dictionary, if a item is provided.
        """
        if item == None:
            # Writes the configuration dictionary to the file
            self.write_file(self.configurationPath, self.configuration)
        else:
            # Stores the item's state in the dictionary
            self.configuration[item] = state
    # write_configuration()

    def read_configuration(self, item=None):
        """
        Return the state of an item in the configuration dictionary, or
        creates the configuration dictionary reading it from a file if the
        item is not provided. If the provided item doesn't exists, it returns
        False.
        """
        # Reads the file
        if item == None:
            self.configuration = self.read_file(self.configurationPath)
            if self.configuration == None:
                self.configuration = {}
        # Return the item's state, if it exists
        elif self.configuration.has_key(item):
            return self.configuration[item]
        # If the item doesnt exists, returns None
        else:
            return None
    # read_configuration()
           

    def save_imc_article(self, widget):
        """
        Displays a file chooser window to save the file. Creates an tuple
        with the arguments and optional dictionaries and dump it into a file.
        """
        # Creates a default file chooser dialog to save files
        dialog = gtk.FileChooserDialog(_("Save Indymedia Article File"),
                               None,
                               gtk.FILE_CHOOSER_ACTION_SAVE,
                               (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                gtk.STOCK_SAVE, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)
        # Adds file filters
        filter = gtk.FileFilter()
        filter.set_name(_("All files"))
        filter.add_pattern("*")
        dialog.add_filter(filter)
        filter = gtk.FileFilter()
        filter.set_name(_("Indymedia Articles (*.ima)"))
        filter.add_pattern("*.ima")
        dialog.add_filter(filter)
        dialog.set_filter(filter)
        dialog.show_all()
        # Opens the dialog and waits for the response
        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            # Saves the article to the file
            filename = dialog.get_filename()+".ima"
            fields = self.extract_information()
            self.write_file(filename, fields)
        dialog.destroy()
    # save_imc_article()

    def open_imc_article(self, widget):
        """
        Displays a file chooser window to open the file. Gets the dictionaries
        from the file and fill the fields.
        """
        # Creates a default file chooser dialog to open files
        dialog = gtk.FileChooserDialog(_("Open Indymedia Article File"),
                               None,
                               gtk.FILE_CHOOSER_ACTION_OPEN,
                               (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)
        # Adds file filters
        filter = gtk.FileFilter()
        filter.set_name(_("All files"))
        filter.add_pattern("*")
        dialog.add_filter(filter)
        filter = gtk.FileFilter()
        filter.set_name(_("Indymedia Articles (*.ima)"))
        filter.add_pattern("*.ima")
        dialog.add_filter(filter)
        dialog.set_filter(filter)
        dialog.show_all()
        # Opens the dialog and waits for the response
        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            filename = dialog.get_filename()
            if self.read_file(filename) == None:
                self.error(_("The file ") + filename + _(" isn't a valid Indymedia Article file."))
            else:
                (imcIndex, arguments, optional) = self.read_file(filename)
                self.fill_fields(imcIndex, arguments, optional)
        dialog.destroy()
    # open_imc_article()

    def fill_fields(self, imcIndex, arguments, optional):
        iter = self.listStoreProfile.get_iter_first()
        i = 0
        while(iter):
            if arguments["author"] == self.listStoreProfile.get_value(iter,0):
                self.comboProfile.set_active(i)
                break
            iter = self.listStoreProfile.iter_next(iter)
            i += 1
        # if the profile wasn't find it must be appended
        if i == self.comboProfileLen:
            self.listStoreProfile.append([arguments["author"],
                optional["email"], optional["homepage"], optional["address"],
                optional["phone"]])
            self.populate_combo_profile()
            self.comboProfile.set_active(i)
        self.comboIMC.set_active(imcIndex)
        i = 0
        for lang in self.imcList[imcIndex][3]:
            if lang[1] == arguments["language"]:
                self.comboLanguage.set_active(i)
                break
            i += 1
        self.entryTitle.set_text(arguments["title"])
        self.textSummary.get_buffer().set_text(arguments["summary"])
        self.textArticle.get_buffer().set_text(arguments["article"])
        if optional["html"]:
            self.radioButtonHtml.set_active(True)
        else:
            self.radioButtonPlain.set_active(True)
        self.listStoreMedia.clear()
        for i in range(len(optional["media_titles"])):
            title = optional["media_titles"][i]
            filename = optional["media_files"][i]
            comment = optional["media_comments"][i]
            self.listStoreMedia.append([title, filename, comment])
    # fill_fields

    def populate_combo_profile(self):
        if self.listStoreProfile == None:
            self.load_profiles()
        iter = self.listStoreProfile.get_iter_first()
        # Clears the combo
        for i in range(self.comboProfileLen):
            self.comboProfile.remove_text(0)
        self.comboProfile.set_sensitive(False)
        if iter != None:
            self.comboProfileLen = 0
            while iter:
                self.comboProfileLen = self.comboProfileLen + 1
                self.comboProfile.append_text(self.listStoreProfile.get_value(iter, 0))
                iter = self.listStoreProfile.iter_next(iter)
            self.comboProfile.set_sensitive(True)
        return
      # populate_combo_profile()

    def load_profiles(self):
        profiles = []
        if self.listStoreProfile == None:
            # Creates the list store
            self.listStoreProfile = gtk.ListStore(str, str, str, str, str)
        else:
            self.listStoreProfile.clear()
        # Loads profiles previously saved
        if os.path.exists(self.profilesPath):
            profiles = self.read_file(self.profilesPath)
            if profiles == None:
                profiles = []
            # Appends all the profiles
            for profile in profiles:
                self.listStoreProfile.append(profile)
        return profiles
     # load_profiles()

    def edit_profile(self, widget, mode):
        """
        Creates the Add or Edit Profile dialog.
        """
        # Creates the add/edit profile dialog
        dialogEditProfile = gtk.Dialog(_("Add Profile"), None,
            gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
            (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                      gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        dialogEditProfile.set_default_response(gtk.RESPONSE_OK)
        # add = True if the profile should be added, or False if the profile
        # should be edited
        add = True
        # Adds a horizontal box to entry author
        hBoxAuthor = gtk.HBox()
        dialogEditProfile.vbox.pack_start(hBoxAuthor)
        labelAuthor = gtk.Label(_("Author") + ":")
        entryAuthor = gtk.Entry()
        hBoxAuthor.pack_start(labelAuthor)
        hBoxAuthor.pack_start(entryAuthor)
        # Adds a horizontal box to entry email
        hBoxEmail = gtk.HBox()
        dialogEditProfile.vbox.pack_start(hBoxEmail)
        labelEmail = gtk.Label(_("e-mail") + ":")
        entryEmail = gtk.Entry()
        hBoxEmail.pack_start(labelEmail)
        hBoxEmail.pack_start(entryEmail)
        # Adds a horizontal box to entry homepage
        hBoxHomepage = gtk.HBox()
        dialogEditProfile.vbox.pack_start(hBoxHomepage)
        labelHomepage = gtk.Label(_("Homepage") + ":")
        entryHomepage = gtk.Entry()
        hBoxHomepage.pack_start(labelHomepage)
        hBoxHomepage.pack_start(entryHomepage)
        # Adds a horizontal box to entry address
        hBoxAddress = gtk.HBox()
        dialogEditProfile.vbox.pack_start(hBoxAddress)
        labelAddress = gtk.Label(_("Address") + ":")
        entryAddress = gtk.Entry()
        hBoxAddress.pack_start(labelAddress)
        hBoxAddress.pack_start(entryAddress)
        # Adds a horizontal box to entry phone
        hBoxPhone = gtk.HBox()
        dialogEditProfile.vbox.pack_start(hBoxPhone)
        labelPhone = gtk.Label(_("Phone") + ":")
        entryPhone = gtk.Entry()
        hBoxPhone.pack_start(labelPhone)
        hBoxPhone.pack_start(entryPhone)
        # If the profile is beeing re-edited, fill the fields and changes the
        # title
        if mode == "edit":
            selection = self.treeViewProfile.get_selection()
            model, iter = selection.get_selected()
            if iter != None:
                add = False
                author, email, homepage, address, phone = self.listStoreProfile.get(iter, 0, 1, 2, 3, 4)
                entryAuthor.set_text(author)
                entryEmail.set_text(email)
                entryHomepage.set_text(homepage)
                entryAddress.set_text(address)
                entryPhone.set_text(phone)
                dialogEditProfile.set_title(_("Edit Profile"))
        # Displays the dialog
        dialogEditProfile.show_all()
        response = dialogEditProfile.run()
        if response == gtk.RESPONSE_ACCEPT:
            if add: 
                self.listStoreProfile.append([entryAuthor.get_text(),
                    entryEmail.get_text(), entryHomepage.get_text(),
                    entryAddress.get_text(), entryPhone.get_text()])
            else:
                self.listStoreProfile.set(iter, 0, entryAuthor.get_text(),
                    1, entryEmail.get_text(), 2, entryHomepage.get_text(),
                    3, entryAddress.get_text(), 4, entryPhone.get_text())
        dialogEditProfile.destroy()   
    # edit_profile()

    def remove_profile(self, widget):
        """
        Removes the profile selected from the treeview.
        """
        selection = self.treeViewProfile.get_selection()
        model, iter = selection.get_selected()
        if iter:
            model.remove(iter)
        return
    # remove_profile()

    def manage_profiles(self, widget):
        """
        A function that displays the Manage Profiles dialog.
        """
        # Creates the manage profiles dialog
        dialogManage = gtk.Dialog(_("Manage Profiles"), None,
            gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
            (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                      gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        dialogManage.set_default_response(gtk.RESPONSE_OK)
        # Adds a horizontal box to manage profiles
        hBox = gtk.HBox()
        dialogManage.vbox.pack_start(hBox)
        # Adds a scrollew window to see the list of profiles
        scrolledWindow = gtk.ScrolledWindow()
        hBox.pack_start(scrolledWindow)
        # Creates the TreeView using liststore
        self.treeViewProfile = gtk.TreeView(self.listStoreProfile)
        scrolledWindow.add(self.treeViewProfile)
        scrolledWindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        # Creates a CellRenderer to render the data
        cellRender = gtk.CellRendererText()
        # Creates the TreeViewColumns to display the data
        columnAuthor = gtk.TreeViewColumn(_('Author'), cellRender, text=0)
        columnAuthor.set_resizable(True)
        columnEmail = gtk.TreeViewColumn(_('e-mail'), cellRender, text=1)
        columnEmail.set_resizable(True)
        columnHomepage = gtk.TreeViewColumn(_('Homepage'), cellRender, text=2)
        columnHomepage.set_resizable(True)
        columnAddress = gtk.TreeViewColumn(_('Address'), cellRender, text=3)
        columnAddress.set_resizable(True)
        columnPhone = gtk.TreeViewColumn(_('Phone'), cellRender, text=4)
        columnPhone.set_resizable(True)
        # Adds columns to treeview
        self.treeViewProfile.append_column(columnAuthor)
        self.treeViewProfile.append_column(columnEmail)
        self.treeViewProfile.append_column(columnHomepage)
        self.treeViewProfile.append_column(columnAddress)
        self.treeViewProfile.append_column(columnPhone)
        # Makes treeview searchable
        self.treeViewProfile.set_search_column(0)
        # Allows sorting on the column
        columnAuthor.set_sort_column_id(0)
        # Allows enable drag and drop of rows including row move
        self.treeViewProfile.set_reorderable(True)
        # Adds a vertical button box to add control buttons
        vButtonBox = gtk.VButtonBox()
        vButtonBox.set_layout(gtk.BUTTONBOX_START)
        hBox.pack_start(vButtonBox, False, False)
        # Adds the buttons "Add Profile", "Remove Profile" and "Edit Profile"
        self.buttonAddProfile = gtk.Button(None, gtk.STOCK_ADD)
        self.buttonAddProfile.connect("clicked", self.edit_profile, "add")
        vButtonBox.pack_start(self.buttonAddProfile)
        self.buttonEditProfile = gtk.Button(None, gtk.STOCK_EDIT)
        self.buttonEditProfile.connect("clicked", self.edit_profile, "edit")
        vButtonBox.pack_start(self.buttonEditProfile)
        self.buttonRemoveProfile = gtk.Button(None, gtk.STOCK_REMOVE)
        self.buttonRemoveProfile.connect("clicked", self.remove_profile)
        vButtonBox.pack_start(self.buttonRemoveProfile)
        # Adds the save profiles checkbutton
        checkButtonSaveProfiles = gtk.CheckButton(_("Save profiles"))
        if self.read_configuration("SAVE_PROFILES"):
            checkButtonSaveProfiles.set_active(True)
        dialogManage.vbox.pack_start(checkButtonSaveProfiles, False)
        # Displays the dialog
        dialogManage.show_all()
        response = dialogManage.run()
        # Saves the profiles
        if response == gtk.RESPONSE_ACCEPT:
            if checkButtonSaveProfiles.get_active():
                # Creates an array with the profiles
                profiles = []
                iter = self.listStoreProfile.get_iter_first()
                while iter:
                    profile = []
                    for col in range(5):
                        profile.append(self.listStoreProfile.get_value(iter, col))
                    profiles.append(profile)
                    iter = self.listStoreProfile.iter_next(iter)
                # Saves the profiles in a file
                self.write_file(self.profilesPath, profiles)
            self.populate_combo_profile()
            # Stores the user preference
            self.write_configuration("SAVE_PROFILES", checkButtonSaveProfiles.get_active())
        dialogManage.destroy()
    # manage_profiles()

    def get_profile(self, index):
        """
        Returns the profile referenced by the index.
        """
        if index != -1:
            profile = { 
                "author" : self.listStoreProfile[index][0],
                "email" : self.listStoreProfile[index][1], 
                "homepage" : self.listStoreProfile[index][2], 
                "address" : self.listStoreProfile[index][3],
                "phone" : self.listStoreProfile[index][4]
                }
        else:
             profile = {
                "author" : "",
                "email" : "",
                "homepage" : "",
                "address" : "",
                "phone" : ""
                }
        return profile
    # get_profile()

    def remove_media_selected(self, button):
        """
        Removes the media selected from the treeview.
        """
        selection = self.treeViewMedia.get_selection()
        model, iter = selection.get_selected()
        if iter:
            model.remove(iter)
        return
   # remove_media_selected()

    def changed_imc(self, widget):
        """
        A function that is called when the user select an IMC. It populates
        the language combo box.
        """
        # Finds the max value of languages for imc
        max = 0
        for i in self.imcList:
            if len(i[3]) > max:
                max = len(i[3])
        # Cleans the combobox
        for i in range(max):
            self.comboLanguage.remove_text(0)
        # Appends the language options
        for lang in self.imcList[widget.get_active()][3]:
            self.comboLanguage.append_text(lang[0])
        # Sets the combobox to be sensitive, so the user can interact with it
        if len(self.imcList[widget.get_active()][3]) > 0:
            self.comboLanguage.set_sensitive(True)
    # changed_imc()

    def extract_information(self):
        """
        A function that get the information from the interface
        fields and complete the arguments and optional dictionaries
        """
        imcIndex = self.comboIMC.get_active()
        langIndex = self.comboLanguage.get_active()
        if imcIndex == -1 or langIndex == -1:
            self.error(_("You must select an IMC and a language to publish."))
            return None, None, None
        arguments, optional = imclib.get_information()
        arguments["language"] = self.imcList[imcIndex][3][langIndex][1]
        arguments["title"] = self.entryTitle.get_text()
        buffer = self.textSummary.get_buffer()
        arguments["summary"] = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
        buffer = self.textArticle.get_buffer()
        arguments["article"] = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
        profile = self.get_profile(self.comboProfile.get_active())
        arguments["author"] = profile["author"]
        optional["address"] = profile["address"]
        optional["phone"] = profile["phone"]
        optional["email"] = profile["email"]
        optional["homepage"] = profile["homepage"]
        optional["html"] = self.radioButtonHtml.get_active()
        iter = self.listStoreMedia.get_iter_first()
        while iter:
            title, path, comment = self.listStoreMedia.get(iter, 0, 1, 2)
            optional["media_files"].append(path)
            optional["media_titles"].append(title)
            optional["media_comments"].append(comment)
            iter = self.listStoreMedia.iter_next(iter)
        return imcIndex, arguments, optional
    # extract_information()

    def publish(self, widget):
        """
        A function that gets the dictionaries returned from 
        extract_information() and publishes it with imclib.
        """
        imcIndex, arguments, optional = self.extract_information()
        if imcIndex == None:
            return
        if imclib.publish(imcIndex, arguments, optional):
            info = _("Your article has been successfully published!")
            message = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT,
                gtk.MESSAGE_INFO, gtk.BUTTONS_OK, info)
            message.run()
            message.destroy()
        else:
            info = _("Error: your article wasn't published!\nVerify if you filled all the mandatory fields.")
            message = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT,
                gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, info)
            message.run()
            message.destroy()
    # publish()

    def about(self, widget):
        """
        A callback function that displays the about dialog.
        """
        # Text to be displayed
        strAbout = """
    IMCPub is a Python library that publishes content on    
    Indymedia sites. It comes with a set of accompanying    
    frontends for activists to use in order to (hopefully)    
    make it easier for them to help the IMC project.    
            """
        # Creates a simple about dialog
        dialogAbout = gtk.Dialog(_("About IMC Publisher"), None,
            gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
            (gtk.STOCK_OK, gtk.RESPONSE_OK))
        dialogAbout.set_default_response(gtk.RESPONSE_OK)
        # Adds a label with the text
        label = gtk.Label(strAbout)
        dialogAbout.vbox.pack_start(label)
        dialogAbout.show_all()
        response = dialogAbout.run()
        dialogAbout.destroy()
    # about()

    def add_media(self, widget, data=None):
        """
        A callback function that displays a file chooser dialog to open the
        media files and set title and description.
        It appends paths, titles and comments to self.optional.
        """
        # Creates a default file chooser dialog to open files
        dialogMedia = gtk.FileChooserDialog(_("Select Media File"),
                               None,
                               gtk.FILE_CHOOSER_ACTION_OPEN,
                               (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialogMedia.set_default_response(gtk.RESPONSE_OK)
        dialogMedia.set_select_multiple(True)
        filter = gtk.FileFilter()
        filter.set_name(_("All Files"))
        filter.add_pattern("*")
        dialogMedia.add_filter(filter)
        filter = gtk.FileFilter()
        filter.set_name(_("Images (*.gif, *.jpg, *.png, *.tiff)"))
        filter.add_mime_type("image/png")
        filter.add_mime_type("image/jpeg")
        filter.add_mime_type("image/gif")
        filter.add_pattern("*.png")
        filter.add_pattern("*.jpg")
        filter.add_pattern("*.gif")
        filter.add_pattern("*.tif")
        dialogMedia.add_filter(filter)
        dialogMedia.set_filter(filter)
        # Adds title and comment fields
        table = gtk.Table(2,2)
        label = gtk.Label(_('Title')+ ":")
        label.set_alignment(0, 0.5)
        table.attach(label, 0, 1, 0, 1)
        mediaTitle = gtk.Entry()
        table.attach(mediaTitle, 1, 2, 0, 1)
        label = gtk.Label(_('Comment')+ ":")
        label.set_alignment(0, 0.5)
        table.attach(label, 0, 1, 1, 2)
        mediaComment = gtk.Entry()
        table.attach(mediaComment, 1, 2, 1, 2)
        dialogMedia.vbox.pack_start(table, False)
        dialogMedia.show_all()
        # Opens the dialog and waits for the response
        response = dialogMedia.run()
        if response == gtk.RESPONSE_OK:
            for filename in dialogMedia.get_filenames():
                self.listStoreMedia.append([mediaTitle.get_text(),
                    filename, mediaComment.get_text()])
        dialogMedia.destroy()
    # addMedia()

    def destroy(self, widget):
        """
        A callback function that saves the configuration preferences and
        destroys the graphical interface.
        """
        self.write_configuration()
        gtk.main_quit()
    # destroy()

    def __init__(self):
        """
        Creates a new window
        """
        # Creates the main window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_title(_("Indymedia Desktop"))

        # Makes the directory to save files related to imcpub
        dir = os.path.expanduser("~/.imcpub/")
        if dir == None:
            dir = "/tmp/.imcpub/"
            os.mkdir(dir, 0700)
        if not os.access(dir, os.F_OK):
            os.mkdir(dir, 0700)
        elif not os.access(dir, os.R_OK | os.W_OK):
            os.chmod(dir, 0700)
        # Defines the paths necessaries
        self.profilesPath = os.path.join(dir, "imcpub.profiles")
        self.configurationPath = os.path.join(dir, "imcpub.config")

        # It will store all the profiles
        self.listStoreProfile = None
        # Gets the list of enabled IMCs
        self.imcList = imclib.get_imc_list()
        # Looks for user's preferences
        self.read_configuration()

        # Connect the "destroy" event to a signal handler.
        # This event occurs when we call gtk_widget_destroy() on the window,
        # or if we return FALSE in the "delete_event" callback.
        self.window.connect("destroy", self.destroy)

        # Sets the border width of the window.
        self.window.set_border_width(10)

        # Creates a vertical box to add all the other widgets to
        # the window
        self.vBox = gtk.VBox()
        self.window.add(self.vBox)

        # Creates a menu bar
        self.menuBar = gtk.MenuBar()
        # Adds file menu
        self.menuFile = gtk.Menu()
        self.menuItemFile = gtk.MenuItem(_("File"))
        self.menuFileSave = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS)
        self.menuFileSave.connect("activate", self.save_imc_article)
        self.menuFileOpen = gtk.ImageMenuItem(gtk.STOCK_OPEN)
        self.menuFileOpen.connect("activate", self.open_imc_article)
        self.menuFileQuit = gtk.ImageMenuItem(gtk.STOCK_QUIT)
        self.menuFileQuit.connect_object("activate", gtk.Widget.destroy, 
                                        self.window)
        self.menuItemFile.set_submenu(self.menuFile)
        self.menuFile.append(self.menuFileSave)
        self.menuFile.append(self.menuFileOpen)
        self.menuFile.append(gtk.SeparatorMenuItem())
        self.menuFile.append(self.menuFileQuit)
        # Adds profile menu
        self.menuProfile = gtk.Menu()
        self.menuItemProfile = gtk.MenuItem(_("Profiles"))
        self.menuProfileManage = gtk.MenuItem(_("Manage Profiles"))
        self.menuProfileManage.connect("activate", self.manage_profiles)
        self.menuItemProfile.set_submenu(self.menuProfile)
        self.menuProfile.append(self.menuProfileManage)
        # Adds help menu
        self.menuHelp = gtk.Menu()
        self.menuItemHelp = gtk.MenuItem(_("Help"))
        self.menuHelpContents = gtk.ImageMenuItem(gtk.STOCK_HELP)
        self.menuHelpAbout = gtk.ImageMenuItem(gtk.STOCK_ABOUT)
        self.menuHelpAbout.connect("activate", self.about)
        self.menuItemHelp.set_submenu(self.menuHelp)
        self.menuHelp.append(self.menuHelpContents)
        self.menuHelp.append(self.menuHelpAbout)
        # Adds menu itens to menu bar
        self.menuBar.append(self.menuItemFile)
        self.menuBar.append(self.menuItemProfile)
        self.menuBar.append(self.menuItemHelp)

        # Creates a general information frame
        self.frameGeneral = gtk.Frame(_("General Information:"))
        self.tableGeneral = gtk.Table(2, 2)
        # Creates a general information table
        self.labelProfile = gtk.Label(_("Select a profile:"))
        self.labelProfile.set_alignment(0, 0.5)
        self.tableGeneral.attach(self.labelProfile, 0, 1, 0, 1)
        self.comboProfile = gtk.combo_box_new_text()
        self.comboProfile.set_sensitive(False)
        self.comboProfileLen = 0
        self.populate_combo_profile()
        self.tableGeneral.attach(self.comboProfile, 1, 2, 0, 1)
        self.labelIMC = gtk.Label(_("Choose an IMC:"))
        self.labelIMC.set_alignment(0, 0.5)
        self.tableGeneral.attach(self.labelIMC, 0, 1, 1, 2)
        self.comboIMC = gtk.combo_box_new_text()
        for imc in self.imcList:
            self.comboIMC.append_text(imc[0])
        self.comboIMC.connect('changed', self.changed_imc)
        self.tableGeneral.attach(self.comboIMC, 1, 2, 1, 2)
        self.labelLanguage = gtk.Label(_("Select a language:"))
        self.labelLanguage.set_alignment(0, 0.5)
        self.tableGeneral.attach(self.labelLanguage, 0, 1, 2, 3)
        self.comboLanguage = gtk.combo_box_new_text()
        # Sets it to unsensite until the user select the imc, because
        # it just will be populated this moment
        self.comboLanguage.set_sensitive(False)
        self.tableGeneral.attach(self.comboLanguage, 1, 2, 2, 3)
        self.frameGeneral.add(self.tableGeneral)

        # Creates a frame to entry article title
        self.frameTitle = gtk.Frame(_("Title:"))
        self.entryTitle = gtk.Entry()
        self.frameTitle.add(self.entryTitle)

        # Creates a summary frame
        self.frameSummary = gtk.Frame(_("Summary:"))
        self.swSummary = gtk.ScrolledWindow()
        self.swSummary.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.textSummary = gtk.TextView()
        self.textSummary.set_editable(True)
        self.textSummary.set_wrap_mode(gtk.WRAP_WORD)
        self.textSummary.set_accepts_tab(False)
        self.textSummary.set_size_request(-1, 50)
        self.swSummary.add(self.textSummary)
        self.frameSummary.add(self.swSummary)

        # Creates an article frame
        self.frameArticle = gtk.Frame(_("Article:"))
        self.vBoxArticle = gtk.VBox()
        self.swArticle = gtk.ScrolledWindow()
        self.swArticle.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.textArticle = gtk.TextView()
        self.textArticle.set_editable(True)
        self.textArticle.set_wrap_mode(gtk.WRAP_WORD)
        self.textArticle.set_accepts_tab(False)
        self.textArticle.set_size_request(-1, 120)
        self.swArticle.add(self.textArticle)
        self.radioButtonPlain = gtk.RadioButton(None, _("text/plain"))
        self.radioButtonPlain.set_active(True)
        self.radioButtonHtml = gtk.RadioButton(self.radioButtonPlain, _("text/html"))
        self.vBoxArticle.pack_start(self.swArticle)
        self.vBoxArticle.pack_start(self.radioButtonPlain, False)
        self.vBoxArticle.pack_start(self.radioButtonHtml, False)
        self.frameArticle.add(self.vBoxArticle)

        # Creates a media files frame
        self.frameMedia = gtk.Frame(_("Attach Media Files:"))
        self.vBoxMedia = gtk.VBox()
        # Adds vertical scrollbar
        self.swMedia = gtk.ScrolledWindow()
        # Creates a liststore with one string column to use as the model
        self.listStoreMedia = gtk.ListStore(str, str, str)
        # Creates the TreeView using liststore
        self.treeViewMedia = gtk.TreeView(self.listStoreMedia)
        self.treeViewMedia.set_size_request(-1, 110)
        self.swMedia.add(self.treeViewMedia)
        self.swMedia.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        # Creates a CellRenderer to render the data
        self.cellRenderMedia = gtk.CellRendererText()
        # Creates the TreeViewColumns to display the data
        self.columnMediaTitle = gtk.TreeViewColumn(_('Title'), self.cellRenderMedia, text=0)
        self.columnMediaTitle.set_resizable(True)
        self.columnMediaPath = gtk.TreeViewColumn(_('Path'), self.cellRenderMedia, text=1)
        self.columnMediaPath.set_resizable(True)
        self.columnMediaComment = gtk.TreeViewColumn(_('Comment'), self.cellRenderMedia, text=2)
        self.columnMediaComment.set_resizable(True)
        # Adds columns to treeview
        self.treeViewMedia.append_column(self.columnMediaTitle)
        self.treeViewMedia.append_column(self.columnMediaPath)
        self.treeViewMedia.append_column(self.columnMediaComment)
        # Makes treeview searchable
        self.treeViewMedia.set_search_column(0)
        # Allows sorting on the column
        self.columnMediaTitle.set_sort_column_id(0)
        # Allows enable drag and drop of rows including row move
        self.treeViewMedia.set_reorderable(True)
        # Creates buttons horizontal box
        self.hButtonBoxMedia = gtk.HButtonBox()
        self.buttonAddMedia = gtk.Button(None, gtk.STOCK_ADD)
        # Connects the button, the click event and the function addMedia
        self.buttonAddMedia.connect("clicked", self.add_media)
        self.buttonRemoveMedia = gtk.Button(None, gtk.STOCK_REMOVE)
        self.buttonRemoveMedia.connect('clicked', self.remove_media_selected)
        self.buttonRemoveAllMedia = gtk.Button(None, gtk.STOCK_CLEAR)
        self.buttonRemoveAllMedia.connect_object('clicked', gtk.ListStore.clear, self.listStoreMedia)
        # Add widgets
        self.hButtonBoxMedia.pack_start(self.buttonAddMedia)
        self.hButtonBoxMedia.pack_start(self.buttonRemoveMedia)
        self.hButtonBoxMedia.pack_start(self.buttonRemoveAllMedia)
        self.vBoxMedia.pack_start(self.swMedia)
        self.vBoxMedia.pack_start(self.hButtonBoxMedia, False)
        self.frameMedia.add(self.vBoxMedia)

        # Creates a horizontal button box with the buttons 
        # with the labels "Publish" and "Quit".
        self.hButtonBoxPublish = gtk.HButtonBox()
        self.hButtonBoxPublish.set_layout(gtk.BUTTONBOX_END)
        self.buttonPublish = gtk.Button(_("Publish"))
        self.buttonQuit = gtk.Button(None, gtk.STOCK_QUIT)
        # This will cause the window to be destroyed by calling
        # gtk_widget_destroy(window) when "clicked".
        self.buttonQuit.connect_object("clicked", gtk.Widget.destroy, self.window)
        self.buttonPublish.connect("clicked", self.publish)
        self.hButtonBoxPublish.pack_start(self.buttonPublish)
        self.hButtonBoxPublish.pack_start(self.buttonQuit)

        # Packs menu bar, boxes, buttonboxes and frames into the main vbox.
        self.vBox.pack_start(self.menuBar, False)
        self.vBox.pack_start(self.frameGeneral, False)
        self.vBox.pack_start(self.frameTitle, False)
        self.vBox.pack_start(self.frameSummary)
        self.vBox.pack_start(self.frameArticle)
        self.vBox.pack_start(self.frameMedia)
        self.vBox.pack_start(gtk.HSeparator(), False, True, 5)
        self.vBox.pack_start(self.hButtonBoxPublish, False)

        # Display the window and all the widgets
        self.window.show_all()

    # __init()__

    def main(self):
        """ 
        All PyGTK applications must have a gtk.main(). Control ends here
        and waits for an event to occur (like a key press or mouse event).
        """
        gtk.main()
    # main()
# GUI

# If the program is run directly or passed as an argument to the python
# interpreter then create a interface instance and show it
if __name__ == "__main__":
    interface = GUI()
    interface.main()
