more markets, search function, and a bunch of minor things
[stockthis] / stockthis.py
index 3e86a93..86fb395 100644 (file)
 # Version 0.1
 #
 
+_version = "StockThis 0.3 beta1 rev1"
+
 import urllib2
 import gtk, gobject
-
+import os
 import hildon
+import marketdata
+import settings
+import logging
+import sys
 
-#import osso
-#osso_c = osso.Context("net.yerga.stockthis", "0.2", False)
-
-from marketdata import markets, idmarket, localmarkets, localids
+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:
-    running_locally = False
+    runninglocally = False
 else:
-    running_locally = True
+    runninglocally = True
 
-if running_locally:
-    imgdir = 'pixmaps/'
-else:
-    imgdir = '/usr/share/stockthis/pixmaps/'
+HOME = os.path.expanduser("~")
+
+settingsdb, imgdir, configdir, logfile = \
+    settings.define_paths(runninglocally, HOME)
 
-loading_img = imgdir + 'loading.gif'
+
+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
 
+allnames = []
+allsymbols = []
+
 gtk.gdk.threads_init()
 
 class StocksPy:
@@ -64,20 +88,17 @@ 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", self.on_about)
-        menu.append(button)
-        menu.show_all()
+        self.create_menu(self.window)
 
         vbox = gtk.VBox()
-        toolbar = self.main_toolbar(False)
+        toolbar = self.main_toolbar(False, False, None, '', '', True)
 
         parea = hildon.PannableArea()
         tv = hildon.GtkTreeView(ui_normal)
-        inmodel = self.__create_model(markets, idmarket)
-        tv.connect("row-activated", self.show_instrument_view, inmodel)
+        inmodel = self.__create_model(marketdata.main, marketdata.idmain)
+        tv.connect("row-activated", self.show_instrument_view, inmodel,
+                    marketdata.localmarkets, marketdata.localids,
+                    marketdata.idmain)
         tv.set_model(inmodel)
         self._tv_columns(tv)
         parea.add(tv)
@@ -89,21 +110,35 @@ class StocksPy:
         self.window.add(vbox)
         self.window.show_all()
 
-    def show_instrument_view(self, widget, path, column, inmodel):
-        market = inmodel[path][0]
+    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()
 
-        names = localmarkets[idmarket.index(market)]
-        ids = localids[idmarket.index(market)]
+    def show_instrument_view(self, widget, path, column, inmodel, names,
+        ids, mindex):
+        market = inmodel[path][0]
+        names = names[mindex.index(market)]
+        ids = ids[mindex.index(market)]
 
         window = hildon.StackableWindow()
+        self.create_menu(window)
+        window.set_title("StockThis - " + inmodel[path][1])
 
         vbox = gtk.VBox()
-        toolbar = self.main_toolbar(False)
+        toolbar = self.main_toolbar(False, False, None, '', '', False)
 
         parea = hildon.PannableArea()
+        parea.connect("horizontal-movement", self.horizontal_mov)
         tv = hildon.GtkTreeView(ui_normal)
         model = self.__create_model(names, ids)
-        tv.connect("row-activated", self.show_quotes_view, model)
+        tv.connect("row-activated", self.show_quotes_view, model, False)
         tv.set_model(model)
         self._tv_columns(tv)
         parea.add(tv)
@@ -115,25 +150,75 @@ class StocksPy:
         window.add(vbox)
         window.show_all()
 
+    def horizontal_mov(self, parea, direction, initial_x, initial_y):
+        #direction = 2 right-to-left
+        #direction = 3 lefto-to-right
+
+        vadj = parea.get_vadjustment()
+        val = vadj.get_value()
 
-    def show_quotes_view(self, widget, path, column, model):
+        if direction == 2:
+            if int(val)-2500 < 0:
+                 parea.scroll_to(-1, 0)
+            else:
+                parea.scroll_to(-1, int(val)-2500)
+        elif direction == 3:
+            parea.scroll_to(-1, int(val)+3500)
+
+        #print val
+
+    def show_quotes_view(self, widget, path, column, model, portfolio):
         quote = model[path][0], model[path][1]
+        #print "quote:", quote[0]
+        #('EURUSD=X', 'EUR/USD')
+
+        #Currencies and ETFs should show the list now -> view = True
+        #Other items show a new list with options
+        view = False
+        for i in marketdata.localids[(len(marketdata.localids)-2):]:
+            for j in i:
+                if quote[0] == j:
+                    #print j
+                    view = True
+
+        if not view:
+            if quote[0] in marketdata.idindexes:
+                self.show_instrument_view(widget, path, column, model,
+                                        marketdata.wnamesindexes,
+                                        marketdata.widsindexes,
+                                        marketdata.idindexes)
+                return
+            if quote[0] in marketdata.idotmarkets:
+                self.show_instrument_view(widget, path, column, model,
+                                        marketdata.omnames,
+                                        marketdata.omsymbols,
+                                        marketdata.idotmarkets)
+                return
+            if quote[0] in marketdata.ideumarkets:
+                self.show_instrument_view(widget, path, column, model,
+                                        marketdata.eunames,
+                                        marketdata.eusymbols,
+                                        marketdata.ideumarkets)
+                return
+            if quote[0] in marketdata.idusmarkets:
+                self.show_instrument_view(widget, path, column, model,
+                                        marketdata.usnames,
+                                        marketdata.ussymbols,
+                                        marketdata.idusmarkets)
+                return
 
-        self.stocks_id = quote[0]
-        self.stocks_name = quote[1]
-        print quote
 
-        self.quotes_win = hildon.StackableWindow()
+        win = hildon.StackableWindow()
+        self.create_menu(win)
+        win.set_title("StockThis - Quotes View - " + quote[1])
 
         vbox = gtk.VBox()
-        toolbar = self.main_toolbar(True)
 
-
-        self.titlelbl = gtk.Label('')
-        self.titlelbl.set_markup('<b><big>' + quote[1].replace('&', '') +
+        ltitle = gtk.Label('')
+        ltitle.set_markup('<b><big>' + quote[1].replace('&', '') +
                                  '</big></b>')
         color = gtk.gdk.color_parse("#03A5FF")
-        self.titlelbl.modify_fg(gtk.STATE_NORMAL, color)
+        ltitle.modify_fg(gtk.STATE_NORMAL, color)
 
         parea = hildon.PannableArea()
 
@@ -142,97 +227,169 @@ class StocksPy:
         hbox = gtk.HBox()
         label = gtk.Label('')
         label.set_markup('<b><big>Price:</big></b>')
-        self.lprice = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.lprice, False, False, 185)
+        lprice = gtk.Label('')
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(lprice, False, False, 245)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
         label = gtk.Label('')
         label.set_markup('<b><big>Change:</big></b>')
-        self.lchange = gtk.Label('')
-        self.lpercent = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.lchange, False, False, 145)
-        hbox.pack_start(self.lpercent, False, False, 0)
+        lchange = gtk.Label('')
+        lpercent = gtk.Label('')
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(lchange, False, False, 205)
+        hbox.pack_start(lpercent, False, False, 0)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
         label = gtk.Label('')
         label.set_markup('<b><big>Volume:</big></b>')
-        self.lvolume = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.lvolume, False, False, 145)
+        lvolume = gtk.Label('')
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(lvolume, False, False, 207)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
         label = gtk.Label('')
         label.set_markup('<b><big>52 week high:</big></b>')
-        self.l52whigh = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.l52whigh, False, False, 55)
+        l52whigh = gtk.Label('')
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(l52whigh, False, False, 125)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
         label = gtk.Label('')
         label.set_markup('<b><big>52 week low:</big></b>')
-        self.l52wlow = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.l52wlow, False, False, 70)
+        l52wlow = gtk.Label('')
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(l52wlow, False, False, 140)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
-
-        button = hildon.PickerButton(fhsize, horbtn)
-        #FIXME: touchentry selector
+        button1 = hildon.PickerButton(fhsize, horbtn)
         data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
                 "900", "1000"]
-        selector = self.create_selector(data)
-        button.set_selector(selector)
-        button.set_title("Shares")
-        #FIXME: check portfolio and see if there's quotes
-        button.set_value(data[0])
-        hbox.pack_start(button, True, True, 0)
+        selector = self.create_selector(data, True)
+        button1.set_selector(selector)
+        button1.set_title("Your shares")
+        shares = self.get_shares_from_symbol(quote[0])
+        button1.set_value(shares)
+        hbox.pack_start(button1, True, True, 0)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_title("Add to Portfolio")
-        #button.connect("clicked", self.publish_opt_screen)
+        button.connect("clicked", self.add_to_portfolio, button1, quote[0], quote[1])
         hbox.pack_start(button, True, True, 0)
-        vbox1.pack_start(hbox, False, False, 0)
+
+        hbox1 = gtk.HBox()
+        label = gtk.Label('')
+        label.set_markup('<b><big>Shares:</big></b>')
+        lshares = gtk.Label(shares)
+        hbox1.pack_start(label, False, False, 20)
+        hbox1.pack_start(lshares, False, False, 220)
+
+        hbox2 = gtk.HBox()
+        label = gtk.Label('')
+        label.set_markup('<b><big>Holdings Value:</big></b>')
+        holdingsvalue = gtk.Label("")
+        hbox2.pack_start(label, False, False, 20)
+        hbox2.pack_start(holdingsvalue, False, False, 105)
+
+        hbox3 = gtk.HBox()
+        label = gtk.Label('')
+        label.set_markup("<b><big>Day's Value Change:</big></b>")
+        dayvaluechange = gtk.Label("")
+        hbox3.pack_start(label, False, False, 20)
+        hbox3.pack_start(dayvaluechange, False, False, 45)
+
+        if not portfolio:
+            vbox1.pack_start(hbox, False, False, 0)
+        else:
+            vbox1.pack_start(hbox1, True, True, 0)
+            vbox1.pack_start(hbox2, True, True, 0)
+            vbox1.pack_start(hbox3, True, True, 0)
 
         parea.add_with_viewport(vbox1)
 
-        vbox.pack_start(self.titlelbl, False, False, 0)
+        widgets = [win, ltitle, lprice, lchange,  lpercent, lvolume, l52whigh,
+                    l52wlow, lshares, holdingsvalue, dayvaluechange]
+
+        toolbar = self.main_toolbar(True, portfolio, widgets, quote[0], quote[1], False)
+
+        vbox.pack_start(ltitle, False, False, 0)
         vbox.pack_start(gtk.HSeparator(), False, False, 0)
         vbox.pack_start(parea, True, True, 0)
         vbox.pack_start(gtk.HSeparator(), False, False, 5)
         vbox.pack_start(toolbar, False, False, 0)
 
-        self.quotes_win.add(vbox)
-        self.quotes_win.show_all()
-        self.show_data(quote[0], self.quotes_win)
 
-    def create_selector(self, data):
-        selector = hildon.hildon_touch_selector_new_text()
+        win.add(vbox)
+        win.show_all()
+        self.show_data(quote[0], widgets, shares)
+
+    def get_shares_from_symbol(self, symbol):
+        shares = "0"
+        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()
+
+        try:
+            portfolio = settings.load_portfolio(settingsdb)
+            index = "None"
+            for item in portfolio:
+                if symbol in item:
+                    index = portfolio.index(item)
+
+            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)
+
+            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):
+        if entry:
+            selector = hildon.TouchSelectorEntry(text=True)
+        else:
+            selector = hildon.TouchSelector(text=True)
         for i in range(len(data)):
             selector.append_text(data[i])
 
         return selector
 
-    def show_data(self, quote, win):
+    def show_data(self, symbol, widgets, shares):
         import thread
-        winprogind(win, 1)
-        thread.start_new_thread(self.get_data, (quote, win))
+        winprogind(widgets[0], 1)
+        thread.start_new_thread(self.get_data, (symbol, widgets, shares))
 
-    def get_data(self, quote, win):
+    def get_data(self, symbol, widgets, shares):
         from ystockquote import ystockquote as yt
+        win, ltitle, lprice, lchange,  lpercent, lvolume, l52whigh, l52wlow, lshares, holdingsvalue, dayvaluechange = widgets
+
         try:
-            data = yt.get_all(quote)
+            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'}
-            self.titlelbl.set_markup('<b><big>Failed to get data</big></b>')
+            ltitle.set_markup('<b><big>Failed to get data</big></b>')
 
         try:
             ch_percent = \
@@ -241,35 +398,53 @@ class StocksPy:
         except ValueError:
             ch_percent = 0.0
 
-        self.lprice.set_label(data['price'])
-        self.lchange.set_label(data['change'])
-        self.lpercent.set_label('%6.2f %%' % ch_percent)
+        lprice.set_label(data['price'])
+        lchange.set_label(data['change'])
+        lpercent.set_label('%6.2f %%' % ch_percent)
 
         if '-' in data['change']:
             color = gtk.gdk.color_parse("#FF0000")
         else:
             color = gtk.gdk.color_parse("#16EB78")
 
-        self.lpercent.modify_fg(gtk.STATE_NORMAL, color)
-        self.lchange.modify_fg(gtk.STATE_NORMAL, color)
+        lpercent.modify_fg(gtk.STATE_NORMAL, color)
+        lchange.modify_fg(gtk.STATE_NORMAL, color)
+
+        lvolume.set_label(data['volume'])
+        l52whigh.set_label(data['52_week_high'])
+        l52wlow.set_label(data['52_week_low'])
+
+        try:
+            daychange = float(shares)*float(data['change'])
+        except ValueError:
+            daychange = 'N/A'
+        try:
+            holdvalue = float(shares)*float(data['price'])
+        except ValueError:
+            holdvalue = 'N/A'
 
-        self.lvolume.set_label(data['volume'])
-        self.l52whigh.set_label(data['52_week_high'])
-        self.l52wlow.set_label(data['52_week_low'])
+        dayvaluechange.set_label(str(daychange))
+        holdingsvalue.set_label(str(holdvalue))
 
         winprogind(win, 0)
 
-    def refresh_stock_data(self, widget):
-        self.show_data(self.stocks_id, self.quotes_win)
+    def refresh_stock_data(self, widget, portfolio, widgets, symbol):
+        if portfolio:
+            shares = self.get_shares_from_symbol(symbol)
+        else:
+            shares = "0"
 
+        self.show_data(symbol, widgets, shares)
 
-    def show_graph_view(self, widget):
+    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()
-        toolbar = self.main_toolbar(False)
+        toolbar = self.main_toolbar(False, True, None, '', '', False)
 
-        self.graphs_title = gtk.Label(self.stocks_name)
+        self.graphs_title = gtk.Label(name)
         color = gtk.gdk.color_parse("#03A5FF")
         self.graphs_title.modify_fg(gtk.STATE_NORMAL, color)
 
@@ -280,42 +455,42 @@ class StocksPy:
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('1d')
-        button.connect("clicked", self.show_graph, '1d', win)
+        button.connect("clicked", self.show_graph, '1d', win, symbol)
         hbox.pack_start(button)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('5d')
-        button.connect("clicked", self.show_graph, '5d', win)
+        button.connect("clicked", self.show_graph, '5d', win, symbol)
         hbox.pack_start(button)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('3m')
-        button.connect("clicked", self.show_graph, '3m', win)
+        button.connect("clicked", self.show_graph, '3m', win, symbol)
         hbox.pack_start(button)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('6m')
-        button.connect("clicked", self.show_graph, '6m', win)
+        button.connect("clicked", self.show_graph, '6m', win, symbol)
         hbox.pack_start(button)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('1y')
-        button.connect("clicked", self.show_graph, '1y', win)
+        button.connect("clicked", self.show_graph, '1y', win, symbol)
         hbox.pack_start(button)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('2y')
-        button.connect("clicked", self.show_graph, '2y', win)
+        button.connect("clicked", self.show_graph, '2y', win, symbol)
         hbox.pack_start(button)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('5y')
-        button.connect("clicked", self.show_graph, '5y', win)
+        button.connect("clicked", self.show_graph, '5y', win, symbol)
         hbox.pack_start(button)
 
         button = hildon.Button(fhsize, horbtn)
         button.set_label('Max')
-        button.connect("clicked", self.show_graph, 'max', win)
+        button.connect("clicked", self.show_graph, 'max', win, symbol)
         hbox.pack_start(button)
 
         vbox1 = gtk.VBox()
@@ -335,31 +510,30 @@ class StocksPy:
         win.add(vbox)
         win.show_all()
 
-        self.show_graph(None, '1d', win)
+        self.show_graph(None, '1d', win, symbol)
 
-    def show_graph(self, widget, option, win):
+    def show_graph(self, widget, option, win, symbol):
         import thread
         winprogind(win, 1)
-        thread.start_new_thread(self.get_graph_data, (option, win))
+        thread.start_new_thread(self.get_graph_data, (option, win, symbol))
 
-    def get_graph_data(self, option, win):
-        kind = self.stocks_id
+    def get_graph_data(self, option, win, symbol):
         if option == '1d':
-            url = 'http://uk.ichart.yahoo.com/b?s=%s' % kind
+            url = 'http://uk.ichart.yahoo.com/b?s=%s' % symbol
         elif option == '5d':
-            url = 'http://uk.ichart.yahoo.com/w?s=%s' % kind
+            url = 'http://uk.ichart.yahoo.com/w?s=%s' % symbol
         elif option == '3m':
-            url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % kind.lower()
+            url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % symbol.lower()
         elif option == '6m':
-            url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % kind.lower()
+            url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % symbol.lower()
         elif option == '1y':
-            url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % kind.lower()
+            url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % symbol.lower()
         elif option == '2y':
-            url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % kind.lower()
+            url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % symbol.lower()
         elif option == '5y':
-            url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % kind.lower()
+            url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % symbol.lower()
         elif option == 'max':
-            url = 'http://chart.finance.yahoo.com/c/my/s/%s' % kind.lower()
+            url = 'http://chart.finance.yahoo.com/c/my/s/%s' % symbol.lower()
 
         try:
             myimg = urllib2.urlopen(url)
@@ -373,12 +547,11 @@ 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()
 
-
-
     def _tv_columns(self, treeview):
         column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
         column.set_visible(False)
@@ -394,9 +567,9 @@ class StocksPy:
             lstore.set(iter, 0, ids[item], 1, names[item])
         return lstore
 
-    def main_toolbar(self, quotesview):
+    def main_toolbar(self, quotesview, portfolio, widgets, symbol, name, initial):
         toolbar = gtk.HBox()
-        toolbar.set_homogeneous(True)
+        #toolbar.set_homogeneous(True)
 
         portfolio_btn = hildon.Button(fhsize, horbtn)
         portfolio_btn.set_title("Portfolio")
@@ -404,66 +577,314 @@ class StocksPy:
 
         graph_btn = hildon.Button(fhsize, horbtn)
         graph_btn.set_title("Graph")
-        graph_btn.connect("clicked", self.show_graph_view)
+        graph_btn.connect("clicked", self.show_graph_view, symbol, name)
 
         refresh_btn = hildon.Button(fhsize, horbtn)
         refresh_btn.set_title("Refresh")
-        refresh_btn.connect("clicked", self.refresh_stock_data)
-
-        toolbar.pack_start(portfolio_btn)
+        refresh_btn.connect("clicked", self.refresh_stock_data, portfolio,
+                            widgets, symbol)
+
+
+        stockiconspath = "/usr/share/icons/hicolor/48x48/hildon/"
+        info_btn = hildon.Button(fhsize, horbtn)
+        img = gtk.Image()
+        img.set_from_file(stockiconspath + "general_information.png")
+        info_btn.set_image(img)
+        info_btn.connect("clicked", self.show_app_information)
+
+        search_btn = hildon.Button(fhsize, horbtn)
+        img = gtk.Image()
+        img.set_from_file(stockiconspath + "general_search.png")
+        search_btn.set_image(img)
+        search_btn.connect("clicked", self.show_search_dialog)
+
+        if not portfolio:
+            toolbar.pack_start(portfolio_btn)
+            if not quotesview:
+                toolbar.pack_start(info_btn, False, False, 0)
         if quotesview:
             toolbar.pack_start(graph_btn)
             toolbar.pack_start(refresh_btn)
 
+        if initial:
+            toolbar.pack_start(search_btn, False, False, 0)
+
         toolbar.show_all()
 
         return toolbar
 
+    def show_search_dialog(self, widget):
+        dlg = gtk.Dialog(title='Search company', parent=None, flags=0)
+        dlg.set_has_separator(False)
+
+        entry = hildon.Entry(fhsize)
+        dlg.vbox.pack_start(entry, False, False, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_label("Search")
+        button.connect("clicked", self.do_search, entry, dlg)
+        dlg.vbox.pack_start(button, False, False, 0)
+
+        dlg.show_all()
+        dlg.run()
+        dlg.destroy()
+
+
+    def do_search(self, widget, entry, dlg):
+        import thread
+        text = entry.get_text()
+        dlg.destroy()
+
+        winprogind(self.window, 1)
+        thread.start_new_thread(self._really_do_search, (text,))
+
+    def _really_do_search(self, text):
+
+        if allnames == []:
+            for market in marketdata.eunames:
+                for company in market:
+                    if not company in allnames:
+                        allnames.append(company)
+
+            for market in marketdata.omnames:
+                for company in market:
+                    if not company in allnames:
+                        allnames.append(company)
+
+            for market in marketdata.usnames:
+                for company in market:
+                    if not company in allnames:
+                        allnames.append(company)
+
+        if allsymbols == []:
+            for market in marketdata.eusymbols:
+                for company in market:
+                    if not company in allsymbols:
+                        allsymbols.append(company)
+
+            for market in marketdata.omsymbols:
+                for company in market:
+                    if not company in allsymbols:
+                        allsymbols.append(company)
+
+            for market in marketdata.ussymbols:
+                for company in market:
+                    if not company in allsymbols:
+                        allsymbols.append(company)
+
+        new_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
+        for i in range(len(allnames)):
+            if text.lower() in allnames[i].lower():
+                niter = new_model.append()
+                new_model.set(niter, 0, allsymbols[i], 1, allnames[i])
+
+        if len(new_model) == 0:
+            winprogind(self.window, 0)
+            gtk.gdk.threads_enter()
+            self.show_info_banner(self.window, "No items found for this search")
+            gtk.gdk.threads_leave()
+            return
+
+        gtk.gdk.threads_enter()
+        self.show_search_screen(new_model, text)
+        gtk.gdk.threads_leave()
+        winprogind(self.window, 0)
+
+
+    def show_search_screen(self, model, text):
+        window = hildon.StackableWindow()
+        self.create_menu(window)
+        window.set_title("StockThis - Search for " + text)
+
+        vbox = gtk.VBox()
+        toolbar = self.main_toolbar(False, False, None, '', '', False)
+
+        parea = hildon.PannableArea()
+        parea.connect("horizontal-movement", self.horizontal_mov)
+        tv = hildon.GtkTreeView(ui_normal)
+        tv.connect("row-activated", self.show_quotes_view, model, False)
+        tv.set_model(model)
+        self._tv_columns(tv)
+        parea.add(tv)
+
+        vbox.pack_start(parea, True, True, 0)
+        vbox.pack_start(gtk.HSeparator(), False, False, 5)
+        vbox.pack_start(toolbar, False, False, 0)
+
+        window.add(vbox)
+        window.show_all()
+
+
+    def show_app_information(self, widget):
+        self.show_information_note(self.window, (
+        "The data is got from Yahoo! Finance.\n"
+        "It could be delayed or even wrong.\n"
+        "The author doesn't validate in any way this data and therefore he is not responsible for any damage that may occur.\n\n"
+        "You can scroll large list with gestures:\n"
+        "Left-to-right gesture: scroll down.\n"
+        "Right-to-left gesture: scroll up."))
+
     def show_portfolio_view(self, widget):
-        #FIXME: get data from sqlite settings
-        data = [["SAN.MC", "BANCO SANTANDER R", "200", "-"],
-                ["BBVA.MC", "BBVA R", "300", "-"]]
+        data = settings.load_portfolio(settingsdb)
+
         win = hildon.StackableWindow()
+        self.create_menu(win)
+        win.set_title("StockThis - Portfolio")
 
         vbox = gtk.VBox()
 
         parea = hildon.PannableArea()
         tv = hildon.GtkTreeView(ui_normal)
         tv.set_headers_visible(True)
-        inmodel = self._create_portfolio_model(data)
-        #tv.connect("row-activated", self.show_instrument_view, inmodel)
-        tv.set_model(inmodel)
+        self.portfolio_model = self._create_portfolio_model(data)
+        tv.connect("row-activated", self.show_quotes_view, self.portfolio_model, True)
+        tv.set_model(self.portfolio_model)
         self._tv_portfolio_columns(tv)
         parea.add(tv)
 
+        hbox = gtk.HBox()
         button = hildon.Button(fhsize, horbtn)
         button.set_title("Refresh All")
-        button.connect("clicked", self.refresh_portfolio, tv, win, data)
+        button.connect("clicked", self.refresh_portfolio, tv, win)
+        hbox.pack_start(button, True, True, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title("Add manually")
+        button.connect("clicked", self.add_item_dlg)
+        hbox.pack_start(button, True, True, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title("Remove")
+        button.connect("clicked", self.remove_item)
+        hbox.pack_start(button, True, True, 0)
+
+        vbox.pack_start(parea, True, True, 0)
+        vbox.pack_start(hbox, False, False, 0)
+        win.add(vbox)
+        win.show_all()
+
+    def add_item_dlg(self, widget):
+        dlg = gtk.Dialog(title='Add to portfolio', parent=None, flags=0)
+        dlg.set_has_separator(False)
+
+        button1 = hildon.PickerButton(fhsize, horbtn)
+        data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
+                "900", "1000"]
+        selector = self.create_selector(data, True)
+        button1.set_selector(selector)
+        button1.set_title("Your shares")
+        button1.set_value("0")
+        dlg.vbox.pack_start(button1, False, False, 0)
+
+        entry1 = hildon.Entry(fhsize)
+        entry1.set_placeholder("Name")
+        dlg.vbox.pack_start(entry1, False, False, 0)
+
+        entry2 = hildon.Entry(fhsize)
+        entry2.set_placeholder("Yahoo Finance symbol")
+        dlg.vbox.pack_start(entry2, False, False, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_label("Add")
+        button.connect("clicked", self.add_item, dlg, button1, entry1, entry2)
+        dlg.vbox.pack_start(button, False, False, 0)
+
+        dlg.show_all()
+        dlg.run()
+        dlg.destroy()
+
+
+    def add_item(self, widget, dlg, button, entry1, entry2):
+        symbol = entry2.get_text()
+        name = entry1.get_text()
+        shares = button.get_value()
+
+        self.add_to_portfolio(widget, button, symbol, name)
+        dlg.destroy()
+
+        niter = self.portfolio_model.append()
+        self.portfolio_model.set(niter, 0, symbol, 1, name, 2, shares, 3, "-")
+
+    def remove_item(self, widget):
+        win = hildon.StackableWindow()
+        win.fullscreen()
+        toolbar = hildon.EditToolbar("Choose items to delete", "Delete")
+        win.set_edit_toolbar(toolbar)
+
+        vbox = gtk.VBox()
+        parea = hildon.PannableArea()
+        tv = hildon.GtkTreeView(ui_edit)
+        selection = tv.get_selection()
+        selection.set_mode(gtk.SELECTION_MULTIPLE)
+        tv.set_model(self.portfolio_model)
+        self._tv_remove_portfolio_columns(tv)
+        parea.add(tv)
+
+        toolbar.connect("button-clicked", self.delete_from_portfolio, win, tv,
+                        selection)
+        toolbar.connect_object("arrow-clicked", gtk.Window.destroy, win)
 
         vbox.pack_start(parea, True, True, 0)
-        vbox.pack_start(button, False, False, 0)
         win.add(vbox)
         win.show_all()
 
-    def refresh_portfolio(self, widget, tv, win, data):
+    def delete_from_portfolio(self, widget, win, tv, selection):
+        if not self.is_treeview_selected(tv):
+            return
+
+        conf = self.show_confirmation(win, "Delete items?")
+
+        if conf:
+            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)
+        column.set_visible(False)
+        treeview.append_column(column)
+
+        column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
+        column.set_property("expand", True)
+        treeview.append_column(column)
+
+        column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
+        column.set_visible(False)
+        treeview.append_column(column)
+
+        column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
+        column.set_visible(False)
+        treeview.append_column(column)
+
+    def refresh_portfolio(self, widget, tv, win):
+        data = settings.load_portfolio(settingsdb)
         import thread
         winprogind(win, 1)
         thread.start_new_thread(self._do_refresh_portfolio, (data, tv, win))
 
-
     def _do_refresh_portfolio(self, data, tv, win):
         for item in data:
             item[3] = self.get_price(item[0])
 
-        model = self._create_portfolio_model(data)
-        tv.set_model(model)
+        self.portfolio_model = self._create_portfolio_model(data)
+        tv.set_model(self.portfolio_model)
         winprogind(win, 0)
 
     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,
@@ -488,20 +909,352 @@ class StocksPy:
         column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
         treeview.append_column(column)
 
-    def on_about(self, widget):
-        dialog = gtk.AboutDialog()
-        dialog.set_name("StockThis")
-        dialog.set_version("0.2")
-        dialog.set_copyright("Copyright © 2009")
-        dialog.set_website("http://stockthis.garage.maemo.org")
-        dialog.set_authors(["Daniel Martin Yerga <dyerga@gmail.com>"])
-        logo = gtk.gdk.pixbuf_new_from_file(imgdir + "stockthis.png")
-        dialog.set_logo(logo)
-        dialog.set_license("This program is released under the GNU\nGeneral Public License. Please visit \nhttp://www.gnu.org/copyleft/gpl.html\nfor details.")
-        dialog.set_artists(["Logo by Daniel Martin Yerga"])
+    def show_confirmation(self, window, msg):
+        dialog = hildon.hildon_note_new_confirmation(window, msg)
+        dialog.show_all()
+        result = dialog.run()
+        if result == gtk.RESPONSE_OK:
+            dialog.destroy()
+            return True
+
+        dialog.destroy()
+        return False
+
+    def show_information_note(self, window, msg):
+        dialog = hildon.hildon_note_new_information(window, msg)
+        dialog.show_all()
+        result = dialog.run()
+        dialog.destroy()
+
+    def show_info_banner(self, widget, msg):
+        hildon.hildon_banner_show_information(widget, 'qgn_note_infoprint', msg)
+
+    def is_treeview_selected(self, treeview):
+        selection = treeview.get_selection()
+        if selection.count_selected_rows() == 0:
+            self.show_info_banner(treeview, 'No selected item')
+            return False
+        else:
+            return True
+
+class About:
+
+    def __init__(self, widget):
+        self.abdialog = gtk.Dialog(title='About', parent=None, flags=0)
+        self.abdialog.set_has_separator(False)
+        self.abdialog.set_size_request(-1, 400)
+
+        self.info_lb = gtk.Label()
+        self.info_lb.set_line_wrap(True)
+
+        self.id = False
+
+        hbox1 = gtk.HBox()
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title('Description')
+        button.connect("clicked", self.show_info, 'description')
+        hbox1.pack_start(button, True, True, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title('Credits')
+        button.connect("clicked", self.show_info, 'credits')
+        hbox1.pack_start(button, True, True, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title('License')
+        button.connect("clicked", self.show_info, 'license')
+        hbox1.pack_start(button, True, True, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title('Donate')
+        button.connect("clicked", self.show_info, 'donate')
+        hbox1.pack_start(button, True, True, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title('Report ')
+        button.connect("clicked", self.show_info, 'report')
+        hbox1.pack_start(button, True, True, 0)
+
+        button = hildon.Button(fhsize, horbtn)
+        button.set_title(' Rate ')
+        button.connect("clicked", self.show_info, 'vote')
+        hbox1.pack_start(button, True, True, 0)
+
+        self.action_btn = hildon.Button(fhsize, horbtn)
+        self.image = gtk.Image()
+
+        self.show_info(None, 'description')
+
+        self.abdialog.vbox.pack_start(self.action_btn, False, False, 0)
+        self.abdialog.vbox.pack_start(self.image, False, False, 5)
+        self.abdialog.vbox.pack_start(self.info_lb, True, True, 0)
+        self.abdialog.vbox.pack_start(hbox1, False, False, 0)
+
+        self.abdialog.show_all()
+        self.action_btn.hide()
+        self.image.hide()
+        self.abdialog.run()
+        self.abdialog.destroy()
+
+    def do_action(self, widget, action):
+        import dbus
+
+        self.abdialog.destroy()
+
+        bus = dbus.SystemBus()
+        proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request")
+        iface = dbus.Interface(proxy, 'com.nokia.osso_browser')
+
+        if action == "donate":
+            url = "http://stockthis.garage.maemo.org/donate.html"
+        elif action == "report":
+            url = "http://stockthis.garage.maemo.org/reporting.html"
+        elif action == "vote":
+            url = "http://maemo.org/downloads/product/stockthis"
+
+        iface.load_url(url)
+
+    def show_info(self, widget, kind):
+        if kind == 'license':
+            self.action_btn.hide()
+            self.image.hide()
+            info = """<small><b>StockThis</b> is free software. It's using a GPL version 2 license or at your election any later version.
+
+Logo by Daniel Martin Yerga.
+</small>"""
+        elif kind == 'credits':
+            self.action_btn.hide()
+            self.image.hide()
+            info = """<small><b>Written by</b> Daniel Martin Yerga (dyerga@gmail.com)
+
+<b>Thanks</b> to everyone who has reported bugs, suggestions, giving spirits, critiques, writing blog articles about StockThis, and so on. Like always the list is extremely big and for not forget anybody, THANKS TO ALL!</small>"""
+        elif kind == 'description':
+            self.action_btn.hide()
+            self.image.hide()
+            info = """<b><big>StockThis 0.3</big></b>
+
+<i>StockThis is a stocks application for Maemo</i>
+
+<b>Web Page</b>:
+stockthis.garage.maemo.org"""
+
+        elif kind == 'donate':
+            self.action_btn.show()
+            self.image.hide()
+            self.action_btn.set_title('Make donation')
+            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.
+
+<b>StockThis's author</b> develops the program in his spare time.
+If you like the program and it's helpful, consider donating a small amount of money.
+Donations are a great incentive and help the developer feel that the hard work is appreciated.</small>
+"""
+        elif kind == 'report':
+            self.action_btn.show()
+            self.image.hide()
+            self.action_btn.set_title('Report bug')
+            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 that users have submitted. The author appreciates 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).
+2) Press the button and write a bug report with as much information as possible.</small>"""
+        elif kind == 'vote':
+            self.action_btn.show()
+            self.image.show()
+            self.image.set_from_file(imgdir + "maemoorg.png")
+            self.action_btn.set_title('Rate StockThis')
+            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):
+        sendtxt = ("You are going to send the log to the developers.\n"
+        "This helps the developers to track problems with the application.\n"
+        "It doesn't send any personal information (like passwords or similar).")
+
+        dialog = hildon.hildon_note_new_confirmation(dlg, sendtxt)
+        dialog.set_button_texts("Send", "Cancel")
+        dialog.show_all()
+        response = dialog.run()
+        if response == gtk.RESPONSE_OK:
+            self.do_pre_send(dlg, logfile)
+
+        dialog.destroy()
+
+    def do_pre_send(self, 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()