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