logging system and more market indices
authorDaniel Martin Yerga <yerga@yerga-desktop.(none)>
Mon, 10 Aug 2009 15:38:40 +0000 (17:38 +0200)
committerDaniel Martin Yerga <yerga@yerga-desktop.(none)>
Mon, 10 Aug 2009 15:38:40 +0000 (17:38 +0200)
TODO
changelog
debian/control
marketdata.py
stockthis.py

diff --git a/TODO b/TODO
index 0f78f22..fa66f5f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -73,3 +73,21 @@ http://finance.yahoo.com/q/cp?s=^MXX
 
 S&P CNX NIFTY (^NSEI) 50 India
 http://es.finance.yahoo.com/q/cp?s=^NSEI
+
+TEL AVIV TA-100 IND (^TA100) 99 Israel
+http://es.finance.yahoo.com/q/cp?s=^TA100
+
+ALL ORDINARIES (^AORD) 492 Australia
+http://es.finance.yahoo.com/q/cp?s=^AORD
+
+NZX 50 INDEX GROSS (^NZ50) 50 New Zealand
+http://es.finance.yahoo.com/q/cp?s=^NZ50
+
+KOSPI Composite Index (^KS11) 478 South Korea
+http://es.finance.yahoo.com/q/cp?s=^KS11
+
+SSE Composite Index (1801677) 865 China
+http://es.finance.yahoo.com/q/cp?s=000001.SS
+
+OSLO EXCH ALL SHARE (^OSEAX) 192 Norway
+http://es.finance.yahoo.com/q/cp?s=^OSEAX
index a51635b..1c87504 100644 (file)
--- a/changelog
+++ b/changelog
@@ -1,3 +1,13 @@
+2009-08-10  Daniel Martín Yerga  <dyerga@gmail.com>
+
+    * stockthis.py: Added logging system.
+    * marketdata.py: Improve some names of the instruments.
+    Added more European and World market indices.
+
+2009-08-09  Daniel Martín Yerga  <dyerga@gmail.com>
+
+    * stockthis.py: Fixed bug with signals in standard button in About dialog.
+
 2009-08-06  Daniel Martín Yerga  <dyerga@gmail.com>
 
     * stockthis.py: Added proper About dialog.
index 8b90ed3..e690419 100644 (file)
@@ -8,7 +8,7 @@ Standards-Version: 3.6.2
 Package: stockthis
 XB-Maemo-Display-Name: StockThis
 Architecture: all
-Depends: python, python-hildon, python-gtk2, python-ystockquote
+Depends: python, python-hildon, python-gtk2, python-ystockquote, python-pycurl
 Description: A stocks application.
  StockThis is a simple application to show quotes from the most important world markets.
  Also, it shows  graphs with the changes in different amount of time.
index c515441..982eb6a 100644 (file)
@@ -71,10 +71,10 @@ idindexes = ["usindex", "eurindex", "othindex"]
 usmarkets = ["Dow Jones Industrial", "NASDAQ 100", "S&P 500"]
 idusmarkets = ["dow", "nasdaq", "sp500"]
 
-eumarkets = ["IBEX35", "SPANISH MERCADO CONTINUO", "IBEX NUEVO MERCADO", "FTSE 100", "FTSE 250", "EURO STOXX 50", "S&P / MIB INDX", "MIB 30", "MIDEX", "MIBTEL"]
+eumarkets = ["IBEX 35 (SPAIN)", "MERCADO CONTINUO (SPAIN)", "IBEX NM (SPAIN)", "FTSE 100 (UK)", "FTSE 250 (UK)", "EURO STOXX 50 (EUROPE)", "S&P / MIB INDX (ITALY)", "MIB 30 (ITALY)", "MIDEX (ITALY)", "MIBTEL (ITALY)"]
 ideumarkets = ["ibex35", "mc", "ibexnm", "ftse100", "ftse250", "eurostoxx50", "spmib", "mib30", "midex", "mibtel"]
 
-otmarkets = ["Bovespa", "S&P/TSX Composite index"]
+otmarkets = ["Bovespa (BRAZIL)", "S&P/TSX Composite index (CANADA)"]
 idotmarkets = ["bvsp", "tsx"]
 
 #### INDEXES ####
@@ -85,11 +85,11 @@ idindexes = ["usindex", "eurindex", "othindex"]
 usindex_symbols = ["^DJI", "^NDX", "^GSPC", "^RUT"]
 usindex_names = ["Dow Jones Industrial Average", "NASDAQ-100", "S&P 500 INDEX", "RUSSELL 2000 INDEX"]
 
-eurindex_symbols = ["^FTSE", "^GDAXI", "^FCHI", "^IBEX", "^MIB30", "^STOXX50E"]
-eurindex_names = ["UK FTSE 100", "GERMAN DAX", "FRANCE CAC 40", "SPANISH IBEX 35", "ITALIAN MIB 30", "DJ EURO STOXX 50"]
+eurindex_symbols = ["^STOXX50E", "^FTSE", "^FTMC", "^FTLC", "^FTAS", "^GDAXI", "^TECDAX", "^SDAXI", "^FCHI", "^SBF120", "^SBF250", "^IBEX", "^SMSI", "^MIB30", "FTSEMIB.MI", "^MIBTEL", "^MIDEX", "^BFX", "^AEX", "^AMX", "^SSMI", "^SSHI", "^ISEQ", "^OMXSPI", "^OSEAX", "OMXC20.CO", "^ATX", "^ATXPRIME", "^PSI20"]
+eurindex_names = ["DJ EURO STOXX 50 (EUROPE)", "FTSE 100 (UK)", "FTSE ACT 250 (UK)", "FTSE 350 (UK)", "FTSE ALL-SHARE (UK)", "DAX (GERMANY)", "TECDAX (GERMANY)", "SDAX PERF-IND (GERMANY)", "CAC 40 (FRANCE)", "PARIS IND SBF120 (FRANCE)", "PARIS IND SBF250 (FRANCE)", "IBEX 35 (SPAIN)", "IGB MADRID (SPAIN)", "MIB 30 (ITALY)", "FTSE MIB (ITALY)", "MIBTEL (ITALY)", "MIDEX (ITALY)", "EURONEXT BEL-20 (BELGIUM)", "AEX (NETHERLANDS)", "AMX INDEX (NETHERLANDS)", "SMI (SWITZERLAND)", "SPI (SWITZERLAND)", "ISEQ-OVERALL PRICE (IRELAND)", "OMXS ALL SHARE INDX (SWEDEN)", "OSLO EXCH ALL SHARE (NORWAY)", "OMX COPENHAGEN 20 (DENMARK)", "ATX (AUSTRIA)", "ATX PRIME (AUSTRIA)", "PSI 20 (PORTUGAL)"]
 
-othindex_symbols = ["^BVSP", "^N225", "^HSI", "^TWII", "^BSESN", "^STI", "^JKSE"]
-othindex_names = ["BRASIL IBOVESPA", "JAPAN NIKKEI 225", "HONG KONG HANG SENG INDEX", "TAIWAN TSEC WEIGHTED INDEX", "INDIA BSE SENSEX", "SINGAPORE STRAITS TIMES INDEX", "INDONESIA COMPOSITE INDEX"]
+othindex_symbols = ["^BVSP", "^MXX", "^MERV", "^N225", "^HSI", "^TWII", "^BSESN", "^STI", "^JKSE", "^KS11", "000001.SS", "EGX30.CA", "^AORD", "^NZ50", "^TA100"]
+othindex_names = ["IBOVESPA (BRAZIL)", "IPC (MEXICO)", "MERVAL BUENOS AIRES (ARGENTINA)", "NIKKEI 225 (JAPAN)", "HANG SENG INDEX (HONG KONG)", "TSEC WEIGHTED INDEX (TAIWAN)", "BSE SENSEX (INDIA)", "STRAITS TIMES INDEX (SINGAPORE)", "COMPOSITE INDEX (INDONESIA)", "KOSPI Composite Index (SOUTH KOREA)", "SSE Composite Index (CHINA)", "EGX 30 INDEX (EGYPT)", "ALL ORDINARIES (AUSTRALIA)", "NZX 50 INDEX GROSS (NEW ZEALAND)", "TEL AVIV TA-100 IND (ISRAEL)"]
 
 #### OTHER INSTRUMENTS ####
 
index 5f6892e..1df7d6c 100644 (file)
 # Version 0.1
 #
 
+_version = "StockThis 0.3 alpha1 rev1"
+
 import urllib2
 import gtk, gobject
 import os
 import hildon
-
-#import osso
-#osso_c = osso.Context("net.yerga.stockthis", "0.3", False)
-
 import marketdata
 import settings
+import logging
+import sys
 
+#import osso
+#osso_c = osso.Context("net.yerga.stockthis", "0.3", False)
 
 #detect if is ran locally or not
-import sys
 runningpath = sys.path[0]
 
 if '/usr/share' in runningpath:
@@ -47,12 +48,32 @@ settingsdb, imgdir, configdir, logfile = \
     settings.define_paths(runninglocally, HOME)
 
 
+logger = logging.getLogger('st')
+logging.basicConfig(filename=logfile,level=logging.ERROR, filemode='w')
+
+DEBUG = True
+
+if DEBUG:
+    #set the main logger to DEBUG
+    logger.setLevel(logging.DEBUG)
+
+    #Create a handler for console debug
+    console = logging.StreamHandler()
+    console.setLevel(logging.DEBUG)
+    # set a format which is simpler for console use
+    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
+    # tell the handler to use this format
+    console.setFormatter(formatter)
+    logging.getLogger('').addHandler(console)
+
 fhsize = gtk.HILDON_SIZE_FINGER_HEIGHT
 horbtn = hildon.BUTTON_ARRANGEMENT_HORIZONTAL
 ui_normal = gtk.HILDON_UI_MODE_NORMAL
 ui_edit = gtk.HILDON_UI_MODE_EDIT
 winprogind = hildon.hildon_gtk_window_set_progress_indicator
 
+logger.debug("test this log")
+
 gtk.gdk.threads_init()
 
 class StocksPy:
@@ -66,12 +87,7 @@ class StocksPy:
         self.program.add_window(self.window)
         self.window.connect("destroy", gtk.main_quit)
 
-        menu = hildon.AppMenu()
-        self.window.set_app_menu(menu)
-        button = gtk.Button("About")
-        button.connect("clicked", About)
-        menu.append(button)
-        menu.show_all()
+        self.create_menu(self.window)
 
         vbox = gtk.VBox()
         toolbar = self.main_toolbar(False, False, None, '', '')
@@ -93,6 +109,17 @@ class StocksPy:
         self.window.add(vbox)
         self.window.show_all()
 
+    def create_menu(self, window):
+        menu = hildon.AppMenu()
+        window.set_app_menu(menu)
+        button = gtk.Button("About")
+        button.connect("clicked", About)
+        menu.append(button)
+        button = gtk.Button("Log")
+        button.connect("clicked", Log, logfile)
+        menu.append(button)
+        menu.show_all()
+
     def show_instrument_view(self, widget, path, column, inmodel, names,
         ids, mindex):
         market = inmodel[path][0]
@@ -100,6 +127,7 @@ class StocksPy:
         ids = ids[mindex.index(market)]
 
         window = hildon.StackableWindow()
+        self.create_menu(window)
         window.set_title("StockThis - " + inmodel[path][1])
 
         vbox = gtk.VBox()
@@ -122,7 +150,7 @@ class StocksPy:
 
     def show_quotes_view(self, widget, path, column, model, portfolio):
         quote = model[path][0], model[path][1]
-        print "quote:", quote[0]
+        #print "quote:", quote[0]
         #('EURUSD=X', 'EUR/USD')
 
         #Currencies and ETFs should show the list now -> view = True
@@ -131,7 +159,7 @@ class StocksPy:
         for i in marketdata.localids[(len(marketdata.localids)-2):]:
             for j in i:
                 if quote[0] == j:
-                    print j
+                    #print j
                     view = True
 
         if not view:
@@ -162,6 +190,7 @@ class StocksPy:
 
 
         win = hildon.StackableWindow()
+        self.create_menu(win)
         win.set_title("StockThis - Quotes View - " + quote[1])
 
         vbox = gtk.VBox()
@@ -225,7 +254,6 @@ class StocksPy:
         selector = self.create_selector(data, True)
         button1.set_selector(selector)
         button1.set_title("Your shares")
-        #FIXME: Improve as it's shown you have a component in your portfolio
         shares = self.get_shares_from_symbol(quote[0])
         button1.set_value(shares)
         hbox.pack_start(button1, True, True, 0)
@@ -265,7 +293,8 @@ class StocksPy:
 
         parea.add_with_viewport(vbox1)
 
-        widgets = [win, ltitle, lprice, lchange,  lpercent, lvolume, l52whigh, l52wlow, lshares, holdingsvalue, dayvaluechange]
+        widgets = [win, ltitle, lprice, lchange,  lpercent, lvolume, l52whigh,
+                    l52wlow, lshares, holdingsvalue, dayvaluechange]
 
         toolbar = self.main_toolbar(True, portfolio, widgets, quote[0], quote[1])
 
@@ -281,31 +310,39 @@ class StocksPy:
         self.show_data(quote[0], widgets, shares)
 
     def get_shares_from_symbol(self, symbol):
-        portfolio_data = settings.load_portfolio(settingsdb)
         shares = "0"
-        for item in portfolio_data :
-            if symbol in item:
-                shares = item[2]
-        return shares
+        try:
+            portfolio_data = settings.load_portfolio(settingsdb)
+            for item in portfolio_data :
+                if symbol in item:
+                    shares = item[2]
+            return shares
+        except:
+            logger.exception("Getting shares from symbol")
+            return shares
 
     def add_to_portfolio(self, widget, button, symbol, name):
         shares = button.get_value()
 
-        portfolio = settings.load_portfolio(settingsdb)
-        index = "None"
-        for item in portfolio:
-            if symbol in item:
-                index = portfolio.index(item)
+        try:
+            portfolio = settings.load_portfolio(settingsdb)
+            index = "None"
+            for item in portfolio:
+                if symbol in item:
+                    index = portfolio.index(item)
 
-        item = [symbol, name, shares, '-']
+            item = [symbol, name, shares, '-']
 
-        if index is "None":
-            settings.insert_new_item_to_portfolio(settingsdb, item)
-        else:
-            settings.delete_item_from_portfolio(settingsdb, symbol)
-            settings.insert_new_item_to_portfolio(settingsdb, item)
+            if index is "None":
+                settings.insert_new_item_to_portfolio(settingsdb, item)
+            else:
+                settings.delete_item_from_portfolio(settingsdb, symbol)
+                settings.insert_new_item_to_portfolio(settingsdb, item)
 
-        self.show_info_banner(widget, "Added to portfolio")
+            self.show_info_banner(widget, "Added to portfolio")
+        except:
+            logger.exception("Adding to portfolio")
+            self.show_info_banner(widget, "Error adding to portfolio")
 
 
     def create_selector(self, data, entry):
@@ -330,7 +367,7 @@ class StocksPy:
         try:
             data = yt.get_all(symbol)
         except:
-            print 'Failed to get internet data'
+            logger.exception("Getting data from Yahoo")
             data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A',
                     '52_week_high': 'N/A', '52_week_low': 'N/A'}
             ltitle.set_markup('<b><big>Failed to get data</big></b>')
@@ -382,6 +419,7 @@ class StocksPy:
 
     def show_graph_view(self, widget, symbol, name):
         win = hildon.StackableWindow()
+        self.create_menu(win)
         win.set_title("StockThis - Graph View - " + name)
 
         vbox = gtk.VBox()
@@ -490,6 +528,7 @@ class StocksPy:
             self.graph.set_from_pixbuf(pbuf)
             winprogind(win, 0)
         except:
+            logger.exception("Getting graph data")
             winprogind(win, 0)
             self.graphs_title.set_label('Failed to get data')
             self.graph.destroy()
@@ -540,6 +579,7 @@ class StocksPy:
         data = settings.load_portfolio(settingsdb)
 
         win = hildon.StackableWindow()
+        self.create_menu(win)
         win.set_title("StockThis - Portfolio")
 
         vbox = gtk.VBox()
@@ -599,12 +639,16 @@ class StocksPy:
         conf = self.show_confirmation(win, "Delete items?")
 
         if conf:
-            selmodel, selected = selection.get_selected_rows()
-            iters = [selmodel.get_iter(path) for path in selected]
-            for i in iters:
-                symbol = selmodel.get_value(i, 0)
-                settings.delete_item_from_portfolio(settingsdb, symbol)
-                selmodel.remove(i)
+            try:
+                selmodel, selected = selection.get_selected_rows()
+                iters = [selmodel.get_iter(path) for path in selected]
+                for i in iters:
+                    symbol = selmodel.get_value(i, 0)
+                    settings.delete_item_from_portfolio(settingsdb, symbol)
+                    selmodel.remove(i)
+            except:
+                logger.exception("Deleting item from portfolio")
+                self.info_banner(widget, "Error deleting item")
 
     def _tv_remove_portfolio_columns(self, treeview):
         column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
@@ -639,9 +683,12 @@ class StocksPy:
 
     def get_price(self, symbol):
         from ystockquote import ystockquote as yt
-        price = yt.get_price(symbol)
-
-        return price
+        try:
+            price = yt.get_price(symbol)
+            return price
+        except:
+            logger.exception("Getting price from Yahoo")
+            return "N/A"
 
     def _create_portfolio_model(self, data):
         lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
@@ -698,6 +745,8 @@ class About:
         self.info_lb = gtk.Label()
         self.info_lb.set_line_wrap(True)
 
+        self.id = False
+
         hbox1 = gtk.HBox()
 
         button = hildon.Button(fhsize, horbtn)
@@ -784,7 +833,9 @@ stockthis.garage.maemo.org"""
             self.action_btn.show()
             self.image.hide()
             self.action_btn.set_title('I want donate')
-            self.action_btn.connect("clicked", self.do_action, "donate")
+            if self.id:
+                self.action_btn.disconnect(self.id)
+            self.id = self.action_btn.connect("clicked", self.do_action, "donate")
             info = """<small><b>StockThis</b> is a free (and gratis) software application.
 Developing good software takes time and hard work.
 
@@ -797,7 +848,9 @@ Donations are a great incentive and help to feel that the hard work is appreciat
             self.action_btn.show()
             self.image.hide()
             self.action_btn.set_title('Report bug')
-            self.action_btn.connect("clicked", self.do_action, "report")
+            if self.id:
+                self.action_btn.disconnect(self.id)
+            self.id = self.action_btn.connect("clicked", self.do_action, "report")
             info = """<small>StockThis is being improved thanks to bug reports. The author appreciates very much all these reports.
 If the application is raising an error when you're using it, you have two choices to report this error:
 1) Send the log from the application menu (if there's an error in the log).
@@ -808,13 +861,178 @@ If the application is raising an error when you're using it, you have two choice
             self.image.show()
             self.image.set_from_file(imgdir + "maemoorg.png")
             self.action_btn.set_title('Vote for StockThis')
-            self.action_btn.connect("clicked", self.do_action, "vote")
+            if self.id:
+                self.action_btn.disconnect(self.id)
+            self.id = self.action_btn.connect("clicked", self.do_action, "vote")
             info = """<small>The downloads section in maemo.org has a nice system where you can rate applications.
 If you consider StockThis a good application (or a bad one too), you could rate it in maemo.org site.</small>"""
 
         self.info_lb.set_markup(info)
 
 
+class Log:
+
+    def __init__(self, widget, logfile):
+        #Log dialog UI
+        dialog = gtk.Dialog(title='Log', parent=None)
+
+        dialog.set_size_request(600, 350)
+
+        parea = hildon.PannableArea()
+        parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
+
+        textview = hildon.TextView()
+        textview.set_property("editable", False)
+        textview.set_property("wrap-mode", gtk.WRAP_WORD)
+
+        log = open(logfile, 'r')
+        logtext = log.read()
+        log.close()
+
+        textview.get_buffer().set_text(logtext)
+        parea.add(textview)
+
+        dialog.vbox.pack_start(parea, True, True, 0)
+
+        hbox = gtk.HBox()
+
+        save_btn = hildon.Button(fhsize, horbtn)
+        save_btn.set_title("Save")
+        save_btn.connect('clicked', self.save, logfile, dialog)
+
+        clear_btn = hildon.Button(fhsize, horbtn)
+        clear_btn.set_title("Clear")
+        clear_btn.connect('clicked', self.clear, textview, logfile)
+
+        send_btn = hildon.Button(fhsize, horbtn)
+        send_btn.set_title('Send')
+        send_btn.connect('clicked', self.send, dialog, logfile)
+
+        hbox.pack_start(save_btn, True, True, 0)
+        hbox.pack_start(clear_btn, True, True, 0)
+        hbox.pack_start(send_btn, True, True, 0)
+
+        dialog.vbox.pack_start(hbox, False, False, 0)
+
+        dialog.show_all()
+        dialog.run()
+        dialog.destroy()
+
+    def show_filechooser(self, window, title, name, EXT):
+        action = gtk.FILE_CHOOSER_ACTION_SAVE
+
+        m = hildon.FileSystemModel()
+        file_dialog = hildon.FileChooserDialog(window, action, m)
+        file_dialog.set_title(title)
+
+        file_dialog.set_current_name(name)
+        HOME = os.path.expanduser("~")
+
+        if os.path.exists(HOME + '/MyDocs/.documents'):
+            file_dialog.set_current_folder(HOME + '/MyDocs/.documents')
+        else:
+            file_dialog.set_current_folder(HOME)
+
+        file_dialog.set_default_response(gtk.RESPONSE_CANCEL)
+
+        result = file_dialog.run()
+        if result == gtk.RESPONSE_OK:
+            namefile = file_dialog.get_filename()
+            namefile, extension = os.path.splitext(namefile)
+            namefile = namefile + "." + EXT
+        else:
+            namefile = None
+        file_dialog.destroy()
+
+        return namefile
+
+
+    def clear(self, widget, textview, logfile):
+        textview.get_buffer().set_text('')
+        f = open(logfile, 'w')
+        f.close()
+
+    def save(self, widget, logfile, dlg):
+        import shutil
+        filename = self.show_filechooser(dlg, "Save log file",
+                    "stockthis-log", "txt")
+
+        if not filename:
+            return
+
+        try:
+            shutil.copyfile(logfile, filename)
+            stockspy.show_info_banner(widget, 'Log file saved')
+        except:
+            logger.exception("Saving log file")
+            stockspy.show_info_banner(widget, 'Error saving the log file')
+
+    def send(self, widget, dlg, logfile):
+        import thread
+        hildon.hildon_gtk_window_set_progress_indicator(dlg, 1)
+        thread.start_new_thread(self._do_send, (dlg, logfile))
+
+    def _do_send(self, dlg, logfile):
+        import pycurl, shutil, random, commands
+        try:
+            rname = ''
+            for i in random.sample('abcdefghijkl123456789', 18):
+                rname += i
+
+            rnamepath = HOME + "/.stockthis/" + rname
+            shutil.copyfile(logfile, rnamepath)
+
+            gtkversion = "%s.%s.%s" % gtk.ver
+            if os.path.exists("/etc/maemo_version"):
+                mfile = open("/etc/maemo_version", 'r')
+                maemoversion = mfile.read()
+                mfile.close()
+            else:
+                maemoversion = ''
+
+            opsystem = ' '.join(os.uname())
+            pyversion = os.sys.version
+            pid = os.getpid()
+            comm = ("awk '/Private_Dirty/{sum+=$2}END{print sum \"kB\"}'"
+            " /proc/%s/smaps") % pid
+            status, dirtymem = commands.getstatusoutput(comm)
+
+            lfile = open(rnamepath, 'r')
+            log = lfile.read()
+            lfile.close()
+
+
+            log = ("%s\nPython version: %s\nGtk version: %s\n"
+            "Maemo version: %sOperating system: %s\n"
+            "Dirty Memory: %s\nLog:\n%s") % (_version, pyversion, gtkversion,
+            maemoversion, opsystem, dirtymem, log)
+
+            lfile = open(rnamepath, 'w')
+            lfile.write(log)
+            lfile.close()
+
+            url = "http://yerga.net/logs/uploader.php"
+            data = [('uploadedfile', (pycurl.FORM_FILE, rnamepath)),]
+            mycurl = pycurl.Curl()
+            mycurl.setopt(pycurl.URL, url)
+            mycurl.setopt(pycurl.HTTPPOST, data)
+
+            mycurl.perform()
+            mycurl.close()
+            os.remove(rnamepath)
+
+            gtk.gdk.threads_enter()
+            stockspy.show_info_banner(dlg, 'Log sent')
+            gtk.gdk.threads_leave()
+            hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
+        except:
+            logger.exception("Sending log file")
+            gtk.gdk.threads_enter()
+            stockspy.show_info_banner(dlg, 'Error sending the log file')
+            gtk.gdk.threads_leave()
+            hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
+
+
 if __name__ == "__main__":
     stockspy = StocksPy()
     gtk.gdk.threads_enter()