change and % columns added to portfolio
[stockthis] / stockthis.py
1 #!/usr/bin/env python
2 # -*- coding: UTF8 -*-
3 # Copyright (C) 2008 by Daniel Martin Yerga
4 # <dyerga@gmail.com>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #
19 # StocksThis: Application to get stocks data from Yahoo Finance.
20 #
21
22 _version = "StockThis 0.3 rev1"
23
24 import urllib2
25 import gtk, gobject
26 import os
27 import hildon
28 import marketdata
29 import settings
30 import logging
31 import sys
32
33 from portrait import FremantleRotation
34
35 import osso
36 osso_c = osso.Context("net.yerga.stockthis", "0.3", False)
37
38 #detect if is ran locally or not
39 runningpath = sys.path[0]
40
41 if '/opt/' in runningpath:
42     runninglocally = False
43 else:
44     runninglocally = True
45
46 HOME = os.path.expanduser("~")
47
48 settingsdb, imgdir, configdir, logfile = \
49     settings.define_paths(runninglocally, HOME)
50
51 logger = logging.getLogger('st')
52 logging.basicConfig(filename=logfile,level=logging.ERROR, filemode='w')
53
54 DEBUG = True
55
56 if DEBUG:
57     #set the main logger to DEBUG
58     logger.setLevel(logging.DEBUG)
59
60     #Create a handler for console debug
61     console = logging.StreamHandler()
62     console.setLevel(logging.DEBUG)
63     # set a format which is simpler for console use
64     formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
65     # tell the handler to use this format
66     console.setFormatter(formatter)
67     logging.getLogger('').addHandler(console)
68
69 fhsize = gtk.HILDON_SIZE_FINGER_HEIGHT
70 horbtn = hildon.BUTTON_ARRANGEMENT_HORIZONTAL
71 ui_normal = gtk.HILDON_UI_MODE_NORMAL
72 ui_edit = gtk.HILDON_UI_MODE_EDIT
73 winprogind = hildon.hildon_gtk_window_set_progress_indicator
74
75 allnames = []
76 allsymbols = []
77
78 gtk.gdk.threads_init()
79
80 class StocksPy:
81
82     def __init__(self):
83         self.program = hildon.Program()
84         self.program.__init__()
85         gtk.set_application_name("StockThis")
86         self.window = hildon.StackableWindow()
87         self.window.set_default_size(800, 480)
88         self.program.add_window(self.window)
89         self.window.connect("destroy", gtk.main_quit)
90
91         FremantleRotation('StockThis', None, "0.3", 0)
92
93         self.create_menu(self.window)
94
95         vbox = gtk.VBox()
96         toolbar = self.main_toolbar(False, False, None, '', '', True)
97
98         parea = hildon.PannableArea()
99         tv = hildon.GtkTreeView(ui_normal)
100         inmodel = self.__create_model(marketdata.main, marketdata.idmain)
101         tv.connect("row-activated", self.show_instrument_view, inmodel,
102                     marketdata.localmarkets, marketdata.localids,
103                     marketdata.idmain)
104         tv.set_model(inmodel)
105         self._tv_columns(tv)
106         parea.add(tv)
107
108         vbox.pack_start(parea, True, True, 0)
109         vbox.pack_start(gtk.HSeparator(), False, False, 5)
110         vbox.pack_start(toolbar, False, False, 0)
111
112         self.window.add(vbox)
113         self.window.show_all()
114
115         self.show_info_banner(self.window,
116             ("StockThis uses your network connection to get data.\n"
117             "Be aware of the high costs that your network provider may apply."))
118
119     def create_menu(self, window):
120         menu = hildon.AppMenu()
121         window.set_app_menu(menu)
122         button = gtk.Button("About")
123         button.connect("clicked", About)
124         menu.append(button)
125         button = gtk.Button("Log")
126         button.connect("clicked", Log, logfile)
127         menu.append(button)
128         menu.show_all()
129
130     def show_instrument_view(self, widget, path, column, inmodel, names,
131         ids, mindex):
132         market = inmodel[path][0]
133         names = names[mindex.index(market)]
134         ids = ids[mindex.index(market)]
135
136         window = hildon.StackableWindow()
137         self.create_menu(window)
138         window.set_title(inmodel[path][1])
139
140         vbox = gtk.VBox()
141         toolbar = self.main_toolbar(False, False, None, '', '', False)
142
143         parea = hildon.PannableArea()
144         parea.connect("horizontal-movement", self.horizontal_mov)
145         tv = hildon.GtkTreeView(ui_normal)
146         model = self.__create_model(names, ids)
147         tv.connect("row-activated", self.show_quotes_view, model, False)
148         tv.set_model(model)
149         self._tv_columns(tv)
150         parea.add(tv)
151
152         vbox.pack_start(parea, True, True, 0)
153         vbox.pack_start(gtk.HSeparator(), False, False, 5)
154         vbox.pack_start(toolbar, False, False, 0)
155
156         window.add(vbox)
157         window.show_all()
158
159     def horizontal_mov(self, parea, direction, initial_x, initial_y):
160         #direction = 2 right-to-left
161         #direction = 3 lefto-to-right
162
163         vadj = parea.get_vadjustment()
164         val = vadj.get_value()
165
166         if direction == 2:
167             if int(val)-2500 < 0:
168                  parea.scroll_to(-1, 0)
169             else:
170                 parea.scroll_to(-1, int(val)-2500)
171         elif direction == 3:
172             parea.scroll_to(-1, int(val)+3500)
173
174         #print val
175
176     def show_quotes_view(self, widget, path, column, model, portfolio):
177         quote = model[path][0], model[path][1]
178         #print "quote:", quote[0]
179         #('EURUSD=X', 'EUR/USD')
180
181         #Currencies and ETFs should show the list now -> view = True
182         #Other items show a new list with options
183         view = False
184         for i in marketdata.localids[(len(marketdata.localids)-2):]:
185             for j in i:
186                 if quote[0] == j:
187                     #print j
188                     view = True
189
190         if not view:
191             if quote[0] in marketdata.idindexes:
192                 self.show_instrument_view(widget, path, column, model,
193                                         marketdata.wnamesindexes,
194                                         marketdata.widsindexes,
195                                         marketdata.idindexes)
196                 return
197             if quote[0] in marketdata.idotmarkets:
198                 self.show_instrument_view(widget, path, column, model,
199                                         marketdata.omnames,
200                                         marketdata.omsymbols,
201                                         marketdata.idotmarkets)
202                 return
203             if quote[0] in marketdata.ideumarkets:
204                 self.show_instrument_view(widget, path, column, model,
205                                         marketdata.eunames,
206                                         marketdata.eusymbols,
207                                         marketdata.ideumarkets)
208                 return
209             if quote[0] in marketdata.idusmarkets:
210                 self.show_instrument_view(widget, path, column, model,
211                                         marketdata.usnames,
212                                         marketdata.ussymbols,
213                                         marketdata.idusmarkets)
214                 return
215
216
217         win = hildon.StackableWindow()
218         self.create_menu(win)
219         win.set_title(quote[1])
220
221         vbox = gtk.VBox()
222
223         ltitle = gtk.Label('')
224         ltitle.set_markup('<b><big>' + quote[1].replace('&', '') +
225                                  '</big></b>')
226         color = gtk.gdk.color_parse("#03A5FF")
227         ltitle.modify_fg(gtk.STATE_NORMAL, color)
228
229         parea = hildon.PannableArea()
230         parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
231
232         vbox1 = gtk.VBox()
233
234         hbox = gtk.HBox()
235         label = gtk.Label('')
236         label.set_markup('<b><big>%39s:</big></b>' % '<u>Price</u>')
237         lprice = gtk.Label('')
238         hbox.pack_start(label, False, False, 0)
239         #if self.is_portrait():
240         hbox.pack_start(lprice, False, False, 25)
241         #else:
242         #    hbox.pack_start(lprice, False, False, 245)
243
244         vbox1.pack_start(hbox, True, True, 0)
245
246         hbox = gtk.HBox()
247         label = gtk.Label('')
248         label.set_markup('<b><big>%35s:</big></b>' % '<u>Change</u>')
249         lchange = gtk.Label('')
250         lpercent = gtk.Label('')
251         hbox.pack_start(label, False, False, 0)
252         #if self.is_portrait():
253         hbox.pack_start(lchange, False, False, 25)
254         hbox.pack_start(lpercent, False, False, 0)
255         #else:
256         #    hbox.pack_start(lchange, False, False, 205)
257         #    hbox.pack_start(lpercent, False, False, 0)
258
259         vbox1.pack_start(hbox, True, True, 0)
260
261         hbox = gtk.HBox()
262         label = gtk.Label('')
263         label.set_markup('<b><big>%35s:</big></b>' % '<u>Volume</u>')
264         lvolume = gtk.Label('')
265         hbox.pack_start(label, False, False, 0)
266         #if self.is_portrait():
267         hbox.pack_start(lvolume, False, False, 25)
268         #else:
269         #    hbox.pack_start(lvolume, False, False, 207)
270
271         vbox1.pack_start(hbox, True, True, 0)
272
273         hbox = gtk.HBox()
274         label = gtk.Label('')
275         label.set_markup('<b><big>%30s:</big></b>' % '<u>52 week high</u>')
276         l52whigh = gtk.Label('')
277         hbox.pack_start(label, False, False, 0)
278         #if self.is_portrait():
279         hbox.pack_start(l52whigh, False, False, 25)
280         #else:
281         #    hbox.pack_start(l52whigh, False, False, 125)
282
283         vbox1.pack_start(hbox, True, True, 0)
284
285         hbox = gtk.HBox()
286         label = gtk.Label('')
287         label.set_markup('<b><big>%30s:</big></b>' % '<u>52 week low</u>')
288         l52wlow = gtk.Label('')
289         hbox.pack_start(label, False, False, 0)
290         #if self.is_portrait():
291         hbox.pack_start(l52wlow, False, False, 26)
292         #else:
293         #    hbox.pack_start(l52wlow, False, False, 140)
294         vbox1.pack_start(hbox, True, True, 0)
295
296         #if self.is_portrait():
297         #    hbox = gtk.VBox()
298         #else:
299         hbox = gtk.HBox()
300         button1 = hildon.PickerButton(fhsize, horbtn)
301         data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
302                 "900", "1000"]
303         selector = self.create_selector(data, True)
304         button1.set_selector(selector)
305         button1.set_title("Your shares")
306         shares = self.get_shares_from_symbol(quote[0])
307         button1.set_value(shares)
308         hbox.pack_start(button1, True, True, 0)
309
310         button = hildon.Button(fhsize, horbtn)
311         button.set_title("Add to Portfolio")
312         button.connect("clicked", self.add_to_portfolio, button1, quote[0], quote[1])
313         hbox.pack_start(button, True, True, 0)
314
315         hbox1 = gtk.HBox()
316         label = gtk.Label('')
317         label.set_markup('<b><big>%37s:</big></b>' % '<u>Shares</u>')
318         lshares = gtk.Label(shares)
319         hbox1.pack_start(label, False, False, 0)
320         #if self.is_portrait():
321         hbox1.pack_start(lshares, False, False, 25)
322         #else:
323         #    hbox1.pack_start(lshares, False, False, 220)
324
325         hbox2 = gtk.HBox()
326         label = gtk.Label('')
327         label.set_markup('<b><big>%29s:</big></b>' % '<u>Holdings Value</u>')
328         holdingsvalue = gtk.Label("")
329         hbox2.pack_start(label, False, False, 0)
330         #if self.is_portrait():
331         hbox2.pack_start(holdingsvalue, False, False, 25)
332         #else:
333         #    hbox2.pack_start(holdingsvalue, False, False, 105)
334
335         hbox3 = gtk.HBox()
336         label = gtk.Label('')
337         label.set_markup("<b><big>%25s:</big></b>" % "<u>Day's Value Change</u>")
338         dayvaluechange = gtk.Label("")
339         hbox3.pack_start(label, False, False, 0)
340         #if self.is_portrait():
341         hbox3.pack_start(dayvaluechange, False, False, 25)
342         #else:
343         #    hbox3.pack_start(dayvaluechange, False, False, 45)
344
345         if not portfolio:
346             vbox1.pack_start(hbox, False, False, 0)
347         else:
348             vbox1.pack_start(hbox1, True, True, 0)
349             vbox1.pack_start(hbox2, True, True, 0)
350             vbox1.pack_start(hbox3, True, True, 0)
351
352         parea.add_with_viewport(vbox1)
353
354         widgets = [win, ltitle, lprice, lchange,  lpercent, lvolume, l52whigh,
355                     l52wlow, lshares, holdingsvalue, dayvaluechange]
356
357         toolbar = self.main_toolbar(True, portfolio, widgets, quote[0], quote[1], False)
358
359         vbox.pack_start(ltitle, False, False, 0)
360         vbox.pack_start(gtk.HSeparator(), False, False, 0)
361         vbox.pack_start(parea, True, True, 0)
362         vbox.pack_start(gtk.HSeparator(), False, False, 5)
363         vbox.pack_start(toolbar, False, False, 0)
364
365
366         win.add(vbox)
367         win.show_all()
368         self.show_data(quote[0], widgets, shares)
369
370     def is_portrait(self):
371         width = gtk.gdk.screen_width()
372         height = gtk.gdk.screen_height()
373         if width > height:
374             return False
375         else:
376             return True
377
378     def get_shares_from_symbol(self, symbol):
379         shares = "0"
380         try:
381             portfolio_data = settings.load_portfolio(settingsdb)
382             for item in portfolio_data :
383                 if symbol in item:
384                     shares = item[2]
385             return shares
386         except:
387             logger.exception("Getting shares from symbol: %s" % symbol)
388             return shares
389
390     def add_to_portfolio(self, widget, button, symbol, name):
391         shares = button.get_value()
392
393         try:
394             portfolio = settings.load_portfolio(settingsdb)
395             index = "None"
396             for item in portfolio:
397                 if symbol in item:
398                     index = portfolio.index(item)
399
400             item = [symbol, name, shares, '-']
401
402             if index is "None":
403                 settings.insert_new_item_to_portfolio(settingsdb, item)
404             else:
405                 settings.delete_item_from_portfolio(settingsdb, symbol)
406                 settings.insert_new_item_to_portfolio(settingsdb, item)
407
408             self.show_info_banner(widget, "Added to portfolio")
409         except:
410             logger.exception("Adding to portfolio: %s, %s" % (symbol, name))
411             self.show_info_banner(widget, "Error adding to portfolio")
412
413
414     def create_selector(self, data, entry):
415         if entry:
416             selector = hildon.TouchSelectorEntry(text=True)
417         else:
418             selector = hildon.TouchSelector(text=True)
419         for i in range(len(data)):
420             selector.append_text(data[i])
421
422         return selector
423
424     def show_data(self, symbol, widgets, shares):
425         import thread
426         winprogind(widgets[0], 1)
427         thread.start_new_thread(self.get_data, (symbol, widgets, shares))
428
429     def get_data(self, symbol, widgets, shares):
430         from ystockquote import ystockquote as yt
431         win, ltitle, lprice, lchange,  lpercent, lvolume, l52whigh, l52wlow, lshares, holdingsvalue, dayvaluechange = widgets
432
433         try:
434             data = yt.get_all(symbol)
435         except:
436             logger.exception("Getting data from Yahoo: %s" % symbol)
437             data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A',
438                     '52_week_high': 'N/A', '52_week_low': 'N/A'}
439             ltitle.set_markup('<b><big>Failed to get data</big></b>')
440
441         try:
442             ch_percent = \
443                     100.0 * float(data['change'])/(float(data['price']) - \
444                     float(data['change']))
445         except ValueError:
446             ch_percent = 0.0
447
448         lprice.set_label(data['price'])
449         lchange.set_label(data['change'])
450         lpercent.set_label('%6.2f %%' % ch_percent)
451
452         if '-' in data['change']:
453             color = gtk.gdk.color_parse("#FF0000")
454         else:
455             color = gtk.gdk.color_parse("#16EB78")
456
457         lpercent.modify_fg(gtk.STATE_NORMAL, color)
458         lchange.modify_fg(gtk.STATE_NORMAL, color)
459
460         lvolume.set_label(data['volume'])
461         l52whigh.set_label(data['52_week_high'])
462         l52wlow.set_label(data['52_week_low'])
463
464         try:
465             daychange = float(shares)*float(data['change'])
466         except ValueError:
467             daychange = 'N/A'
468         try:
469             holdvalue = float(shares)*float(data['price'])
470         except ValueError:
471             holdvalue = 'N/A'
472
473         dayvaluechange.set_label(str(daychange))
474         holdingsvalue.set_label(str(holdvalue))
475
476         winprogind(win, 0)
477
478     def refresh_stock_data(self, widget, portfolio, widgets, symbol):
479         if portfolio:
480             shares = self.get_shares_from_symbol(symbol)
481         else:
482             shares = "0"
483
484         self.show_data(symbol, widgets, shares)
485
486     def show_graph_view(self, widget, symbol, name):
487         win = hildon.StackableWindow()
488         self.create_menu(win)
489         win.set_title(name)
490
491         vbox = gtk.VBox()
492         toolbar = self.main_toolbar(False, True, None, '', '', False)
493
494         self.graphs_title = gtk.Label(name)
495         color = gtk.gdk.color_parse("#03A5FF")
496         self.graphs_title.modify_fg(gtk.STATE_NORMAL, color)
497
498         parea = hildon.PannableArea()
499         parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
500
501         vbox1 = gtk.VBox()
502
503         hbox = gtk.HBox()
504         hbox.set_homogeneous(True)
505
506         button = hildon.Button(fhsize, horbtn)
507         button.set_label('1d')
508         button.connect("clicked", self.show_graph, '1d', win, symbol)
509         hbox.pack_start(button)
510
511         button = hildon.Button(fhsize, horbtn)
512         button.set_label('5d')
513         button.connect("clicked", self.show_graph, '5d', win, symbol)
514         hbox.pack_start(button)
515
516         button = hildon.Button(fhsize, horbtn)
517         button.set_label('3m')
518         button.connect("clicked", self.show_graph, '3m', win, symbol)
519         hbox.pack_start(button)
520
521         button = hildon.Button(fhsize, horbtn)
522         button.set_label('6m')
523         button.connect("clicked", self.show_graph, '6m', win, symbol)
524         hbox.pack_start(button)
525
526         vbox1.pack_start(hbox, False, False, 0)
527         hbox = gtk.HBox()
528         hbox.set_homogeneous(True)
529
530         button = hildon.Button(fhsize, horbtn)
531         button.set_label('1y')
532         button.connect("clicked", self.show_graph, '1y', win, symbol)
533         hbox.pack_start(button)
534
535         button = hildon.Button(fhsize, horbtn)
536         button.set_label('2y')
537         button.connect("clicked", self.show_graph, '2y', win, symbol)
538         hbox.pack_start(button)
539
540         button = hildon.Button(fhsize, horbtn)
541         button.set_label('5y')
542         button.connect("clicked", self.show_graph, '5y', win, symbol)
543         hbox.pack_start(button)
544
545         button = hildon.Button(fhsize, horbtn)
546         button.set_label('Max')
547         button.connect("clicked", self.show_graph, 'max', win, symbol)
548         hbox.pack_start(button)
549
550         vbox1.pack_start(hbox, False, False, 0)
551
552         self.graph = gtk.Image()
553         vbox1.pack_start(self.graph, True, True, 0)
554
555         parea.add_with_viewport(vbox1)
556
557         vbox.pack_start(self.graphs_title, False, False, 0)
558         vbox.pack_start(gtk.HSeparator(), False, False, 0)
559         vbox.pack_start(parea, True, True, 0)
560         vbox.pack_start(gtk.HSeparator(), False, False, 5)
561         vbox.pack_start(toolbar, False, False, 0)
562
563         win.add(vbox)
564         win.show_all()
565
566         self.show_graph(None, '1d', win, symbol)
567
568     def show_graph(self, widget, option, win, symbol):
569         import thread
570         winprogind(win, 1)
571         thread.start_new_thread(self.get_graph_data, (option, win, symbol))
572
573     def get_graph_data(self, option, win, symbol):
574         if option == '1d':
575             url = 'http://uk.ichart.yahoo.com/b?s=%s' % symbol
576         elif option == '5d':
577             url = 'http://uk.ichart.yahoo.com/w?s=%s' % symbol
578         elif option == '3m':
579             url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % symbol.lower()
580         elif option == '6m':
581             url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % symbol.lower()
582         elif option == '1y':
583             url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % symbol.lower()
584         elif option == '2y':
585             url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % symbol.lower()
586         elif option == '5y':
587             url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % symbol.lower()
588         elif option == 'max':
589             url = 'http://chart.finance.yahoo.com/c/my/s/%s' % symbol.lower()
590
591         try:
592             myimg = urllib2.urlopen(url)
593             imgdata = myimg.read()
594
595             pbl = gtk.gdk.PixbufLoader()
596             pbl.write(imgdata)
597
598             pbuf = pbl.get_pixbuf()
599             pbuf = pbuf.scale_simple(475, 235, gtk.gdk.INTERP_TILES)
600             pbl.close()
601             self.graph.set_from_pixbuf(pbuf)
602             winprogind(win, 0)
603         except:
604             logger.exception("Getting graph data: %s" % url)
605             winprogind(win, 0)
606             self.graphs_title.set_label('Failed to get data')
607             self.graph.destroy()
608
609     def _tv_columns(self, treeview):
610         column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
611         column.set_visible(False)
612         treeview.append_column(column)
613
614         column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
615         treeview.append_column(column)
616
617     def __create_model(self, names, ids):
618         lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
619         for item in range(len(names)):
620             iter = lstore.append()
621             lstore.set(iter, 0, ids[item], 1, names[item])
622         return lstore
623
624     def main_toolbar(self, quotesview, portfolio, widgets, symbol, name, initial):
625         toolbar = gtk.HBox()
626         #toolbar.set_homogeneous(True)
627
628         portfolio_btn = hildon.Button(fhsize, horbtn)
629         portfolio_btn.set_title("Portfolio")
630         portfolio_btn.connect("clicked", self.show_portfolio_view)
631
632         graph_btn = hildon.Button(fhsize, horbtn)
633         graph_btn.set_title("Graph")
634         graph_btn.connect("clicked", self.show_graph_view, symbol, name)
635
636         refresh_btn = hildon.Button(fhsize, horbtn)
637         refresh_btn.set_title("Refresh")
638         refresh_btn.connect("clicked", self.refresh_stock_data, portfolio,
639                             widgets, symbol)
640
641
642         stockiconspath = "/usr/share/icons/hicolor/48x48/hildon/"
643         info_btn = hildon.Button(fhsize, horbtn)
644         img = gtk.Image()
645         img.set_from_file(stockiconspath + "general_information.png")
646         info_btn.set_image(img)
647         info_btn.connect("clicked", self.show_app_information)
648
649         search_btn = hildon.Button(fhsize, horbtn)
650         img = gtk.Image()
651         img.set_from_file(stockiconspath + "general_search.png")
652         search_btn.set_image(img)
653         search_btn.connect("clicked", self.show_search_dialog)
654
655         if not portfolio:
656             toolbar.pack_start(portfolio_btn)
657             if not quotesview:
658                 toolbar.pack_start(info_btn, False, False, 0)
659         if quotesview:
660             toolbar.pack_start(graph_btn)
661             toolbar.pack_start(refresh_btn)
662
663         if initial:
664             toolbar.pack_start(search_btn, False, False, 0)
665
666         toolbar.show_all()
667
668         return toolbar
669
670     def show_search_dialog(self, widget):
671         dlg = gtk.Dialog(title='Search company', parent=None, flags=0)
672         dlg.set_has_separator(False)
673
674         entry = hildon.Entry(fhsize)
675         dlg.vbox.pack_start(entry, False, False, 0)
676
677         button = hildon.Button(fhsize, horbtn)
678         button.set_label("Search")
679         button.connect("clicked", self.do_search, entry, dlg)
680         dlg.vbox.pack_start(button, False, False, 0)
681
682         dlg.show_all()
683         dlg.run()
684         dlg.destroy()
685
686
687     def do_search(self, widget, entry, dlg):
688         import thread
689         text = entry.get_text()
690         dlg.destroy()
691
692         winprogind(self.window, 1)
693         thread.start_new_thread(self._really_do_search, (text,))
694
695     def _really_do_search(self, text):
696
697         if allnames == []:
698             for market in marketdata.eunames:
699                 for company in market:
700                     allnames.append(company)
701
702             for market in marketdata.omnames:
703                 for company in market:
704                     allnames.append(company)
705
706             for market in marketdata.usnames:
707                 for company in market:
708                     allnames.append(company)
709
710         if allsymbols == []:
711             for market in marketdata.eusymbols:
712                 for company in market:
713                     allsymbols.append(company)
714
715             for market in marketdata.omsymbols:
716                 for company in market:
717                     allsymbols.append(company)
718
719             for market in marketdata.ussymbols:
720                 for company in market:
721                     allsymbols.append(company)
722
723         new_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
724         for i in range(len(allnames)):
725             if text.lower() in allnames[i].lower():
726                 niter = new_model.append()
727                 #print allsymbols[i], allnames[i]
728                 #FIXME: repeated companies in the results list
729                 #print if allnames[i]
730                 #for j in new_model:
731                 #    if j[1] == allnames[i]:
732                 new_model.set(niter, 0, allsymbols[i], 1, allnames[i])
733
734         if len(new_model) == 0:
735             winprogind(self.window, 0)
736             gtk.gdk.threads_enter()
737             self.show_info_banner(self.window, "No items found for this search")
738             gtk.gdk.threads_leave()
739             return
740
741         gtk.gdk.threads_enter()
742         self.show_search_screen(new_model, text)
743         gtk.gdk.threads_leave()
744         winprogind(self.window, 0)
745
746
747     def show_search_screen(self, model, text):
748         window = hildon.StackableWindow()
749         self.create_menu(window)
750         window.set_title("Search for " + text)
751
752         vbox = gtk.VBox()
753         toolbar = self.main_toolbar(False, False, None, '', '', False)
754
755         parea = hildon.PannableArea()
756         parea.connect("horizontal-movement", self.horizontal_mov)
757         tv = hildon.GtkTreeView(ui_normal)
758         tv.connect("row-activated", self.show_quotes_view, model, False)
759         tv.set_model(model)
760         self._tv_columns(tv)
761         parea.add(tv)
762
763         vbox.pack_start(parea, True, True, 0)
764         vbox.pack_start(gtk.HSeparator(), False, False, 5)
765         vbox.pack_start(toolbar, False, False, 0)
766
767         window.add(vbox)
768         window.show_all()
769
770
771     def show_app_information(self, widget):
772         self.show_information_note(self.window, (
773         "The data is got from Yahoo! Finance.\n"
774         "It could be delayed or even wrong.\n"
775         "The author doesn't validate in any way this data and therefore he is not responsible for any damage that may occur.\n\n"
776         "You can scroll large list with gestures:\n"
777         "Left-to-right gesture: scroll down.\n"
778         "Right-to-left gesture: scroll up."))
779
780     def show_portfolio_view(self, widget):
781         data = settings.load_portfolio(settingsdb)
782         for item in data:
783             item.append('-')
784             item.append('-')
785
786         win = hildon.StackableWindow()
787         self.create_menu(win)
788         win.set_title("Portfolio")
789
790         vbox = gtk.VBox()
791
792         parea = hildon.PannableArea()
793         parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
794         tv = hildon.GtkTreeView(ui_normal)
795         tv.set_headers_visible(True)
796         self.portfolio_model = self._create_portfolio_model(data)
797         tv.connect("row-activated", self.show_quotes_view, self.portfolio_model, True)
798         tv.set_model(self.portfolio_model)
799         self._tv_portfolio_columns(tv)
800         parea.add(tv)
801
802         hbox = gtk.HBox()
803         button = hildon.Button(fhsize, horbtn)
804         button.set_title("Refresh All")
805         button.connect("clicked", self.refresh_portfolio, tv, win)
806         hbox.pack_start(button, True, True, 0)
807
808         button = hildon.Button(fhsize, horbtn)
809         button.set_title("Add manually")
810         button.connect("clicked", self.add_item_dlg)
811         hbox.pack_start(button, True, True, 0)
812
813         button = hildon.Button(fhsize, horbtn)
814         button.set_title("Remove")
815         button.connect("clicked", self.remove_item)
816         hbox.pack_start(button, True, True, 0)
817
818         vbox.pack_start(parea, True, True, 0)
819         vbox.pack_start(hbox, False, False, 0)
820         win.add(vbox)
821         win.show_all()
822
823     def add_item_dlg(self, widget):
824         dlg = gtk.Dialog(title='Add to portfolio', parent=None, flags=0)
825         dlg.set_has_separator(False)
826
827         button1 = hildon.PickerButton(fhsize, horbtn)
828         data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
829                 "900", "1000"]
830         selector = self.create_selector(data, True)
831         button1.set_selector(selector)
832         button1.set_title("Your shares")
833         button1.set_value("0")
834         dlg.vbox.pack_start(button1, False, False, 0)
835
836         entry1 = hildon.Entry(fhsize)
837         entry1.set_placeholder("Name")
838         dlg.vbox.pack_start(entry1, False, False, 0)
839
840         entry2 = hildon.Entry(fhsize)
841         entry2.set_placeholder("Yahoo Finance symbol")
842         dlg.vbox.pack_start(entry2, False, False, 0)
843
844         button = hildon.Button(fhsize, horbtn)
845         button.set_label("Add")
846         button.connect("clicked", self.add_item, dlg, button1, entry1, entry2)
847         dlg.vbox.pack_start(button, False, False, 0)
848
849         dlg.show_all()
850         dlg.run()
851         dlg.destroy()
852
853     def add_item(self, widget, dlg, button, entry1, entry2):
854         symbol = entry2.get_text()
855         name = entry1.get_text()
856         shares = button.get_value()
857
858         if name == '' or symbol == '':
859             self.show_info_banner(widget, "Must add the name and symbol")
860             return
861
862         self.add_to_portfolio(widget, button, symbol, name)
863         dlg.destroy()
864
865         niter = self.portfolio_model.append()
866         self.portfolio_model.set(niter, 0, symbol, 1, name, 2, shares, 3, "-")
867
868     def remove_item(self, widget):
869         win = hildon.StackableWindow()
870         win.fullscreen()
871         toolbar = hildon.EditToolbar("Choose items to delete", "Delete")
872         win.set_edit_toolbar(toolbar)
873
874         vbox = gtk.VBox()
875         parea = hildon.PannableArea()
876         tv = hildon.GtkTreeView(ui_edit)
877         selection = tv.get_selection()
878         selection.set_mode(gtk.SELECTION_MULTIPLE)
879         tv.set_model(self.portfolio_model)
880         self._tv_remove_portfolio_columns(tv)
881         parea.add(tv)
882
883         toolbar.connect("button-clicked", self.delete_from_portfolio, win, tv,
884                         selection)
885         toolbar.connect_object("arrow-clicked", gtk.Window.destroy, win)
886
887         vbox.pack_start(parea, True, True, 0)
888         win.add(vbox)
889         win.show_all()
890
891     def delete_from_portfolio(self, widget, win, tv, selection):
892         if not self.is_treeview_selected(tv):
893             return
894
895         conf = self.show_confirmation(win, "Delete items?")
896
897         if conf:
898             try:
899                 selmodel, selected = selection.get_selected_rows()
900                 iters = [selmodel.get_iter(path) for path in selected]
901                 for i in iters:
902                     symbol = selmodel.get_value(i, 0)
903                     settings.delete_item_from_portfolio(settingsdb, symbol)
904                     selmodel.remove(i)
905             except:
906                 logger.exception("Deleting item from portfolio")
907                 self.info_banner(widget, "Error deleting item")
908
909     def _tv_remove_portfolio_columns(self, treeview):
910         column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
911         column.set_visible(False)
912         treeview.append_column(column)
913
914         column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
915         column.set_property("expand", True)
916         treeview.append_column(column)
917
918         column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
919         column.set_visible(False)
920         treeview.append_column(column)
921
922         column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
923         column.set_visible(False)
924         treeview.append_column(column)
925
926     def refresh_portfolio(self, widget, tv, win):
927         data = settings.load_portfolio(settingsdb)
928         for item in data:
929             item.append('-')
930             item.append('-')
931         import thread
932         winprogind(win, 1)
933         thread.start_new_thread(self._do_refresh_portfolio, (data, tv, win))
934
935     def _do_refresh_portfolio(self, data, tv, win):
936         print data
937         for item in data:
938             item[3], item[4] = self.get_portfolio_data(item[0])
939             try:
940                 ch_percent = \
941                         100.0 * float(item[4])/(float(item[3]) - \
942                         float(item[4]))
943             except ValueError:
944                 ch_percent = 0.0
945
946             item[5] = '%6.2f %%' % ch_percent
947
948
949         print data
950         self.portfolio_model = self._create_portfolio_model(data)
951         tv.set_model(self.portfolio_model)
952         winprogind(win, 0)
953
954     def get_portfolio_data(self, symbol):
955         from ystockquote import ystockquote as yt
956         try:
957             data = yt.get_all(symbol)
958             return data['price'], data['change']
959         except:
960             logger.exception("Getting price from Yahoo: %s" % symbol)
961             return "-", "-"
962
963     def _create_portfolio_model(self, data):
964         lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
965                                 gobject.TYPE_STRING, gobject.TYPE_STRING,
966                                 gobject.TYPE_STRING, gobject.TYPE_STRING,
967                                 gobject.TYPE_STRING)
968         for item in data:
969             iter = lstore.append()
970             if '+' in item[4]:
971                 color = 'green'
972             else:
973                 color = 'red'
974             lstore.set(iter, 0, item[0], 1, item[1], 2, item[2], 3, item[3],
975                         4, item[4], 5, item[5], 6, color)
976         return lstore
977
978     def _tv_portfolio_columns(self, treeview):
979         column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
980         column.set_visible(False)
981         treeview.append_column(column)
982
983         column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
984         column.set_property("expand", True)
985         treeview.append_column(column)
986
987         column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
988         treeview.append_column(column)
989
990         column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
991         treeview.append_column(column)
992
993         column = gtk.TreeViewColumn('Change', gtk.CellRendererText(), text=4)
994         treeview.append_column(column)
995
996
997         renderer = gtk.CellRendererText()
998         renderer.set_property("foreground-set", True)
999         column = gtk.TreeViewColumn('%', renderer, text=5, foreground=6)
1000         treeview.append_column(column)
1001
1002     def show_confirmation(self, window, msg):
1003         dialog = hildon.hildon_note_new_confirmation(window, msg)
1004         dialog.show_all()
1005         result = dialog.run()
1006         if result == gtk.RESPONSE_OK:
1007             dialog.destroy()
1008             return True
1009
1010         dialog.destroy()
1011         return False
1012
1013     def show_information_note(self, window, msg):
1014         dialog = hildon.hildon_note_new_information(window, msg)
1015         dialog.show_all()
1016         result = dialog.run()
1017         dialog.destroy()
1018
1019     def show_info_banner(self, widget, msg):
1020         hildon.hildon_banner_show_information(widget, 'qgn_note_infoprint', msg)
1021
1022     def is_treeview_selected(self, treeview):
1023         selection = treeview.get_selection()
1024         if selection.count_selected_rows() == 0:
1025             self.show_info_banner(treeview, 'No selected item')
1026             return False
1027         else:
1028             return True
1029
1030 class About:
1031
1032     def __init__(self, widget):
1033         self.abdialog = gtk.Dialog(title='About', parent=None, flags=0)
1034         self.abdialog.set_has_separator(False)
1035         self.abdialog.set_size_request(-1, 400)
1036
1037         self.info_lb = gtk.Label()
1038         self.info_lb.set_line_wrap(True)
1039
1040         self.id = False
1041
1042         hbox1 = gtk.HBox()
1043
1044         button = hildon.Button(fhsize, horbtn)
1045         button.set_title('Description')
1046         button.connect("clicked", self.show_info, 'description')
1047         hbox1.pack_start(button, True, True, 0)
1048
1049         button = hildon.Button(fhsize, horbtn)
1050         button.set_title('Credits')
1051         button.connect("clicked", self.show_info, 'credits')
1052         hbox1.pack_start(button, True, True, 0)
1053
1054         button = hildon.Button(fhsize, horbtn)
1055         button.set_title('License')
1056         button.connect("clicked", self.show_info, 'license')
1057         hbox1.pack_start(button, True, True, 0)
1058
1059         button = hildon.Button(fhsize, horbtn)
1060         button.set_title('Donate')
1061         button.connect("clicked", self.show_info, 'donate')
1062         hbox1.pack_start(button, True, True, 0)
1063
1064         button = hildon.Button(fhsize, horbtn)
1065         button.set_title('Report ')
1066         button.connect("clicked", self.show_info, 'report')
1067         hbox1.pack_start(button, True, True, 0)
1068
1069         button = hildon.Button(fhsize, horbtn)
1070         button.set_title(' Rate ')
1071         button.connect("clicked", self.show_info, 'vote')
1072         hbox1.pack_start(button, True, True, 0)
1073
1074         self.action_btn = hildon.Button(fhsize, horbtn)
1075         self.image = gtk.Image()
1076
1077         self.show_info(None, 'description')
1078
1079         self.abdialog.vbox.pack_start(self.action_btn, False, False, 0)
1080         self.abdialog.vbox.pack_start(self.image, False, False, 5)
1081         self.abdialog.vbox.pack_start(self.info_lb, True, True, 0)
1082         self.abdialog.vbox.pack_start(hbox1, False, False, 0)
1083
1084         self.abdialog.show_all()
1085         self.action_btn.hide()
1086         self.image.hide()
1087         self.abdialog.run()
1088         self.abdialog.destroy()
1089
1090     def do_action(self, widget, action):
1091         import dbus
1092
1093         self.abdialog.destroy()
1094
1095         bus = dbus.SystemBus()
1096         proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request")
1097         iface = dbus.Interface(proxy, 'com.nokia.osso_browser')
1098
1099         if action == "donate":
1100             url = "http://stockthis.garage.maemo.org/donate.html"
1101         elif action == "report":
1102             url = "http://stockthis.garage.maemo.org/reporting.html"
1103         elif action == "vote":
1104             url = "http://maemo.org/downloads/product/Maemo5/stockthis"
1105
1106         iface.open_new_window(url)
1107
1108     def show_info(self, widget, kind):
1109         if kind == 'license':
1110             self.action_btn.hide()
1111             self.image.hide()
1112             info = """<small><b>StockThis</b> is free software. It's using a GPL version 2 license or at your election any later version.
1113
1114 Logo by Daniel Martin Yerga.
1115 </small>"""
1116         elif kind == 'credits':
1117             self.action_btn.hide()
1118             self.image.hide()
1119             info = """<small><b>Written by</b> Daniel Martin Yerga (dyerga@gmail.com)
1120
1121 <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>"""
1122         elif kind == 'description':
1123             self.action_btn.hide()
1124             self.image.hide()
1125             info = """<b><big>StockThis 0.3</big></b>
1126
1127 <i>StockThis is a stocks application for Maemo</i>
1128
1129 <b>Web Page</b>:
1130 stockthis.garage.maemo.org"""
1131
1132         elif kind == 'donate':
1133             self.action_btn.show()
1134             self.image.hide()
1135             self.action_btn.set_title('Make donation')
1136             if self.id:
1137                 self.action_btn.disconnect(self.id)
1138             self.id = self.action_btn.connect("clicked", self.do_action, "donate")
1139             info = """<small><b>StockThis</b> is a free (and gratis) software application.
1140 Developing good software takes time and hard work.
1141
1142 <b>StockThis's author</b> develops the program in his spare time.
1143 If you like the program and it's helpful, consider donating a small amount of money.
1144 Donations are a great incentive and help the developer feel that the hard work is appreciated.</small>
1145 """
1146         elif kind == 'report':
1147             self.action_btn.show()
1148             self.image.hide()
1149             self.action_btn.set_title('Report bug')
1150             if self.id:
1151                 self.action_btn.disconnect(self.id)
1152             self.id = self.action_btn.connect("clicked", self.do_action, "report")
1153             info = """<small>StockThis is being improved thanks to bug reports that users have submitted. The author appreciates these reports.
1154 If the application is raising an error when you're using it, you have two choices to report this error:
1155 1) Send the log from the application menu (if there's an error in the log).
1156 2) Press the button and write a bug report with as much information as possible.</small>"""
1157         elif kind == 'vote':
1158             self.action_btn.show()
1159             self.image.show()
1160             self.image.set_from_file(imgdir + "maemoorg.png")
1161             self.action_btn.set_title('Rate StockThis')
1162             if self.id:
1163                 self.action_btn.disconnect(self.id)
1164             self.id = self.action_btn.connect("clicked", self.do_action, "vote")
1165             info = """<small>The downloads section in maemo.org has a nice system where you can rate applications.
1166 If you consider StockThis a good application (or a bad one too), you could rate it in maemo.org site.</small>"""
1167
1168         self.info_lb.set_markup(info)
1169
1170
1171 class Log:
1172
1173     def __init__(self, widget, logfile):
1174         #Log dialog UI
1175         dialog = gtk.Dialog(title='Log', parent=None)
1176
1177         dialog.set_size_request(600, 350)
1178
1179         parea = hildon.PannableArea()
1180         parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
1181
1182         textview = hildon.TextView()
1183         textview.set_property("editable", False)
1184         textview.set_property("wrap-mode", gtk.WRAP_WORD)
1185
1186         log = open(logfile, 'r')
1187         logtext = log.read()
1188         log.close()
1189
1190         textview.get_buffer().set_text(logtext)
1191         parea.add(textview)
1192
1193         dialog.vbox.pack_start(parea, True, True, 0)
1194
1195         hbox = gtk.HBox()
1196
1197         save_btn = hildon.Button(fhsize, horbtn)
1198         save_btn.set_title("Save")
1199         save_btn.connect('clicked', self.save, logfile, dialog)
1200
1201         clear_btn = hildon.Button(fhsize, horbtn)
1202         clear_btn.set_title("Clear")
1203         clear_btn.connect('clicked', self.clear, textview, logfile)
1204
1205         send_btn = hildon.Button(fhsize, horbtn)
1206         send_btn.set_title('Send')
1207         send_btn.connect('clicked', self.send, dialog, logfile)
1208
1209         hbox.pack_start(save_btn, True, True, 0)
1210         hbox.pack_start(clear_btn, True, True, 0)
1211         hbox.pack_start(send_btn, True, True, 0)
1212
1213         dialog.vbox.pack_start(hbox, False, False, 0)
1214
1215         dialog.show_all()
1216         dialog.run()
1217         dialog.destroy()
1218
1219     def show_filechooser(self, window, title, name, EXT):
1220         action = gtk.FILE_CHOOSER_ACTION_SAVE
1221
1222         m = hildon.FileSystemModel()
1223         file_dialog = hildon.FileChooserDialog(window, action, m)
1224         file_dialog.set_title(title)
1225
1226         file_dialog.set_current_name(name)
1227         HOME = os.path.expanduser("~")
1228
1229         if os.path.exists(HOME + '/MyDocs/.documents'):
1230             file_dialog.set_current_folder(HOME + '/MyDocs/.documents')
1231         else:
1232             file_dialog.set_current_folder(HOME)
1233
1234         file_dialog.set_default_response(gtk.RESPONSE_CANCEL)
1235
1236         result = file_dialog.run()
1237         if result == gtk.RESPONSE_OK:
1238             namefile = file_dialog.get_filename()
1239             namefile, extension = os.path.splitext(namefile)
1240             namefile = namefile + "." + EXT
1241         else:
1242             namefile = None
1243         file_dialog.destroy()
1244
1245         return namefile
1246
1247
1248     def clear(self, widget, textview, logfile):
1249         textview.get_buffer().set_text('')
1250         f = open(logfile, 'w')
1251         f.close()
1252
1253     def save(self, widget, logfile, dlg):
1254         import shutil
1255         filename = self.show_filechooser(dlg, "Save log file",
1256                     "stockthis-log", "txt")
1257
1258         if not filename:
1259             return
1260
1261         try:
1262             shutil.copyfile(logfile, filename)
1263             stockspy.show_info_banner(widget, 'Log file saved')
1264         except:
1265             logger.exception("Saving log file")
1266             stockspy.show_info_banner(widget, 'Error saving the log file')
1267
1268     def send(self, widget, dlg, logfile):
1269         sendtxt = ("You are going to send the log to the developers.\n"
1270         "This helps the developers to track problems with the application.\n"
1271         "It doesn't send any personal information (like passwords or similar).")
1272
1273         dialog = hildon.hildon_note_new_confirmation(dlg, sendtxt)
1274         dialog.set_button_texts("Send", "Cancel")
1275         dialog.show_all()
1276         response = dialog.run()
1277         if response == gtk.RESPONSE_OK:
1278             self.do_pre_send(dlg, logfile)
1279
1280         dialog.destroy()
1281
1282     def do_pre_send(self, dlg, logfile):
1283         import thread
1284         hildon.hildon_gtk_window_set_progress_indicator(dlg, 1)
1285         thread.start_new_thread(self._do_send, (dlg, logfile))
1286
1287     def _do_send(self, dlg, logfile):
1288         import pycurl, shutil, random, commands
1289         try:
1290             rname = ''
1291             for i in random.sample('abcdefghijkl123456789', 18):
1292                 rname += i
1293
1294             rnamepath = HOME + "/.stockthis/" + rname
1295             shutil.copyfile(logfile, rnamepath)
1296
1297             gtkversion = "%s.%s.%s" % gtk.ver
1298             if os.path.exists("/etc/maemo_version"):
1299                 mfile = open("/etc/maemo_version", 'r')
1300                 maemoversion = mfile.read()
1301                 mfile.close()
1302             else:
1303                 maemoversion = ''
1304
1305             opsystem = ' '.join(os.uname())
1306             pyversion = os.sys.version
1307             pid = os.getpid()
1308             comm = ("awk '/Private_Dirty/{sum+=$2}END{print sum \"kB\"}'"
1309             " /proc/%s/smaps") % pid
1310             status, dirtymem = commands.getstatusoutput(comm)
1311
1312             lfile = open(rnamepath, 'r')
1313             log = lfile.read()
1314             lfile.close()
1315
1316
1317             log = ("%s\nPython version: %s\nGtk version: %s\n"
1318             "Maemo version: %sOperating system: %s\n"
1319             "Dirty Memory: %s\nLog:\n%s") % (_version, pyversion, gtkversion,
1320             maemoversion, opsystem, dirtymem, log)
1321
1322             lfile = open(rnamepath, 'w')
1323             lfile.write(log)
1324             lfile.close()
1325
1326             url = "http://yerga.net/logs/uploader.php"
1327             data = [('uploadedfile', (pycurl.FORM_FILE, rnamepath)),]
1328             mycurl = pycurl.Curl()
1329             mycurl.setopt(pycurl.URL, url)
1330             mycurl.setopt(pycurl.HTTPPOST, data)
1331
1332             mycurl.perform()
1333             mycurl.close()
1334             os.remove(rnamepath)
1335
1336             gtk.gdk.threads_enter()
1337             stockspy.show_info_banner(dlg, 'Log sent')
1338             gtk.gdk.threads_leave()
1339             hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
1340         except:
1341             logger.exception("Sending log file")
1342             gtk.gdk.threads_enter()
1343             stockspy.show_info_banner(dlg, 'Error sending the log file')
1344             gtk.gdk.threads_leave()
1345             hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
1346
1347
1348 if __name__ == "__main__":
1349     stockspy = StocksPy()
1350     gtk.gdk.threads_enter()
1351     gtk.main()
1352     gtk.gdk.threads_leave()