3 # Copyright (C) 2008 by Daniel Martin Yerga
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.
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.
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.
19 # StocksThis: Application to get stocks data from Yahoo Finance.
22 _version = "StockThis 0.4 rev1"
34 from portrait import FremantleRotation
37 osso_c = osso.Context("net.yerga.stockthis", "0.3", False)
39 #detect if is ran locally or not
40 runningpath = sys.path[0]
42 if '/opt/' in runningpath:
43 runninglocally = False
47 HOME = os.path.expanduser("~")
49 settingsdb, imgdir, configdir, logfile = \
50 settings.define_paths(runninglocally, HOME)
52 logger = logging.getLogger('st')
53 logging.basicConfig(filename=logfile,level=logging.ERROR, filemode='w')
58 #set the main logger to DEBUG
59 logger.setLevel(logging.DEBUG)
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)
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
79 gtk.gdk.threads_init()
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)
92 FremantleRotation('StockThis', None, "0.3", 0)
94 self.create_menu(self.window)
97 toolbar = self.main_toolbar(False, False, None, '', '', True)
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,
105 tv.set_model(inmodel)
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)
113 self.window.add(vbox)
114 self.window.show_all()
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."))
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)
128 def show_instrument_view(self, widget, path, column, inmodel, names,
130 market = inmodel[path][0]
131 names = names[mindex.index(market)]
132 ids = ids[mindex.index(market)]
134 window = hildon.StackableWindow()
135 self.create_menu(window)
136 window.set_title(inmodel[path][1])
139 toolbar = self.main_toolbar(False, False, None, '', '', False)
141 parea = hildon.PannableArea()
142 parea.connect("horizontal-movement", self.horizontal_mov)
143 tv = hildon.GtkTreeView(ui_normal)
144 model = self.__create_model(names, ids)
146 if market == 'metals':
147 tv.connect("row-activated", self.show_metal_graphs, model)
149 tv.connect("row-activated", self.show_quotes_view, model, False)
155 vbox.pack_start(parea, True, True, 0)
156 vbox.pack_start(gtk.HSeparator(), False, False, 5)
157 vbox.pack_start(toolbar, False, False, 0)
162 def horizontal_mov(self, parea, direction, initial_x, initial_y):
163 #direction = 2 right-to-left
164 #direction = 3 lefto-to-right
166 vadj = parea.get_vadjustment()
167 val = vadj.get_value()
170 if int(val)-2500 < 0:
171 parea.scroll_to(-1, 0)
173 parea.scroll_to(-1, int(val)-2500)
175 parea.scroll_to(-1, int(val)+3500)
179 def show_quotes_view(self, widget, path, column, model, portfolio):
180 quote = model[path][0], model[path][1]
181 #print "quote:", quote[0]
182 #('EURUSD=X', 'EUR/USD')
184 #Currencies and ETFs should show the list now -> view = True
185 #Other items show a new list with options
187 for i in marketdata.localids[(len(marketdata.localids)-2):]:
194 if quote[0] in marketdata.idindexes:
195 self.show_instrument_view(widget, path, column, model,
196 marketdata.wnamesindexes,
197 marketdata.widsindexes,
198 marketdata.idindexes)
200 if quote[0] in marketdata.idotmarkets:
201 self.show_instrument_view(widget, path, column, model,
203 marketdata.omsymbols,
204 marketdata.idotmarkets)
206 if quote[0] in marketdata.ideumarkets:
207 self.show_instrument_view(widget, path, column, model,
209 marketdata.eusymbols,
210 marketdata.ideumarkets)
212 if quote[0] in marketdata.idusmarkets:
213 self.show_instrument_view(widget, path, column, model,
215 marketdata.ussymbols,
216 marketdata.idusmarkets)
220 win = hildon.StackableWindow()
221 self.create_menu(win)
222 win.set_title(quote[1])
226 ltitle = gtk.Label('')
227 ltitle.set_markup('<b><big>' + quote[1].replace('&', '') +
229 color = gtk.gdk.color_parse("#03A5FF")
230 ltitle.modify_fg(gtk.STATE_NORMAL, color)
232 parea = hildon.PannableArea()
233 parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
238 label = gtk.Label('')
239 label.set_markup('<b><big>%39s:</big></b>' % '<u>Price</u>')
240 lprice = gtk.Label('')
241 hbox.pack_start(label, False, False, 0)
242 #if self.is_portrait():
243 hbox.pack_start(lprice, False, False, 25)
245 # hbox.pack_start(lprice, False, False, 245)
247 vbox1.pack_start(hbox, True, True, 0)
250 label = gtk.Label('')
251 label.set_markup('<b><big>%35s:</big></b>' % '<u>Change</u>')
252 lchange = gtk.Label('')
253 lpercent = gtk.Label('')
254 hbox.pack_start(label, False, False, 0)
255 #if self.is_portrait():
256 hbox.pack_start(lchange, False, False, 25)
257 hbox.pack_start(lpercent, False, False, 0)
259 # hbox.pack_start(lchange, False, False, 205)
260 # hbox.pack_start(lpercent, False, False, 0)
262 vbox1.pack_start(hbox, True, True, 0)
265 label = gtk.Label('')
266 label.set_markup('<b><big>%35s:</big></b>' % '<u>Volume</u>')
267 lvolume = gtk.Label('')
268 hbox.pack_start(label, False, False, 0)
269 #if self.is_portrait():
270 hbox.pack_start(lvolume, False, False, 25)
272 # hbox.pack_start(lvolume, False, False, 207)
274 vbox1.pack_start(hbox, True, True, 0)
277 label = gtk.Label('')
278 label.set_markup('<b><big>%30s:</big></b>' % '<u>52 week high</u>')
279 l52whigh = gtk.Label('')
280 hbox.pack_start(label, False, False, 0)
281 #if self.is_portrait():
282 hbox.pack_start(l52whigh, False, False, 25)
284 # hbox.pack_start(l52whigh, False, False, 125)
286 vbox1.pack_start(hbox, True, True, 0)
289 label = gtk.Label('')
290 label.set_markup('<b><big>%30s:</big></b>' % '<u>52 week low</u>')
291 l52wlow = gtk.Label('')
292 hbox.pack_start(label, False, False, 0)
293 #if self.is_portrait():
294 hbox.pack_start(l52wlow, False, False, 26)
296 # hbox.pack_start(l52wlow, False, False, 140)
297 vbox1.pack_start(hbox, True, True, 0)
299 #if self.is_portrait():
303 button1 = hildon.PickerButton(fhsize, horbtn)
304 data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
306 selector = self.create_selector(data, True)
307 button1.set_selector(selector)
308 button1.set_title("Your shares")
309 shares = self.get_shares_from_symbol(quote[0])
310 button1.set_value(shares)
311 hbox.pack_start(button1, True, True, 0)
313 button = hildon.Button(fhsize, horbtn)
314 button.set_title("Add to Portfolio")
315 button.connect("clicked", self.add_to_portfolio, button1, quote[0], quote[1])
316 hbox.pack_start(button, True, True, 0)
319 label = gtk.Label('')
320 label.set_markup('<b><big>%37s:</big></b>' % '<u>Shares</u>')
321 lshares = gtk.Label(shares)
322 hbox1.pack_start(label, False, False, 0)
323 #if self.is_portrait():
324 hbox1.pack_start(lshares, False, False, 25)
326 # hbox1.pack_start(lshares, False, False, 220)
329 label = gtk.Label('')
330 label.set_markup('<b><big>%29s:</big></b>' % '<u>Holdings Value</u>')
331 holdingsvalue = gtk.Label("")
332 hbox2.pack_start(label, False, False, 0)
333 #if self.is_portrait():
334 hbox2.pack_start(holdingsvalue, False, False, 25)
336 # hbox2.pack_start(holdingsvalue, False, False, 105)
339 label = gtk.Label('')
340 label.set_markup("<b><big>%25s:</big></b>" % "<u>Day's Value Change</u>")
341 dayvaluechange = gtk.Label("")
342 hbox3.pack_start(label, False, False, 0)
343 #if self.is_portrait():
344 hbox3.pack_start(dayvaluechange, False, False, 25)
346 # hbox3.pack_start(dayvaluechange, False, False, 45)
349 vbox1.pack_start(hbox, False, False, 0)
351 vbox1.pack_start(hbox1, True, True, 0)
352 vbox1.pack_start(hbox2, True, True, 0)
353 vbox1.pack_start(hbox3, True, True, 0)
355 parea.add_with_viewport(vbox1)
357 widgets = [win, ltitle, lprice, lchange, lpercent, lvolume, l52whigh,
358 l52wlow, lshares, holdingsvalue, dayvaluechange]
360 toolbar = self.main_toolbar(True, portfolio, widgets, quote[0], quote[1], False)
362 vbox.pack_start(ltitle, False, False, 0)
363 vbox.pack_start(gtk.HSeparator(), False, False, 0)
364 vbox.pack_start(parea, True, True, 0)
365 vbox.pack_start(gtk.HSeparator(), False, False, 5)
366 vbox.pack_start(toolbar, False, False, 0)
371 self.show_data(quote[0], widgets, shares)
373 def is_portrait(self):
374 width = gtk.gdk.screen_width()
375 height = gtk.gdk.screen_height()
381 def get_shares_from_symbol(self, symbol):
384 portfolio_data = settings.load_portfolio(settingsdb)
385 for item in portfolio_data :
390 logger.exception("Getting shares from symbol: %s" % symbol)
393 def add_to_portfolio(self, widget, button, symbol, name):
394 shares = button.get_value()
397 portfolio = settings.load_portfolio(settingsdb)
399 for item in portfolio:
401 index = portfolio.index(item)
403 item = [symbol, name, shares, '-']
406 settings.insert_new_item_to_portfolio(settingsdb, item)
408 settings.delete_item_from_portfolio(settingsdb, symbol)
409 settings.insert_new_item_to_portfolio(settingsdb, item)
411 self.show_info_banner(widget, "Added to portfolio")
413 logger.exception("Adding to portfolio: %s, %s" % (symbol, name))
414 self.show_info_banner(widget, "Error adding to portfolio")
417 def create_selector(self, data, entry):
419 selector = hildon.TouchSelectorEntry(text=True)
421 selector = hildon.TouchSelector(text=True)
422 for i in range(len(data)):
423 selector.append_text(data[i])
427 def show_data(self, symbol, widgets, shares):
429 winprogind(widgets[0], 1)
430 thread.start_new_thread(self.get_data, (symbol, widgets, shares))
432 def get_data(self, symbol, widgets, shares):
433 from ystockquote import ystockquote as yt
434 win, ltitle, lprice, lchange, lpercent, lvolume, l52whigh, l52wlow, lshares, holdingsvalue, dayvaluechange = widgets
437 data = yt.get_all(symbol)
439 logger.exception("Getting data from Yahoo: %s" % symbol)
440 data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A',
441 '52_week_high': 'N/A', '52_week_low': 'N/A'}
442 ltitle.set_markup('<b><big>Failed to get data</big></b>')
446 100.0 * float(data['change'])/(float(data['price']) - \
447 float(data['change']))
451 lprice.set_label(data['price'])
452 lchange.set_label(data['change'])
453 lpercent.set_label('%6.2f %%' % ch_percent)
455 if '-' in data['change']:
456 color = gtk.gdk.color_parse("#FF0000")
458 color = gtk.gdk.color_parse("#16EB78")
460 lpercent.modify_fg(gtk.STATE_NORMAL, color)
461 lchange.modify_fg(gtk.STATE_NORMAL, color)
463 lvolume.set_label(data['volume'])
464 l52whigh.set_label(data['52_week_high'])
465 l52wlow.set_label(data['52_week_low'])
468 daychange = float(shares)*float(data['change'])
472 holdvalue = float(shares)*float(data['price'])
476 dayvaluechange.set_label(str(daychange))
477 holdingsvalue.set_label(str(holdvalue))
481 def refresh_stock_data(self, widget, portfolio, widgets, symbol):
483 shares = self.get_shares_from_symbol(symbol)
487 self.show_data(symbol, widgets, shares)
489 def show_graph_view(self, widget, symbol, name):
490 win = hildon.StackableWindow()
491 self.create_menu(win)
495 toolbar = self.main_toolbar(False, True, None, '', '', False)
497 self.graphs_title = gtk.Label(name)
498 color = gtk.gdk.color_parse("#03A5FF")
499 self.graphs_title.modify_fg(gtk.STATE_NORMAL, color)
501 parea = hildon.PannableArea()
502 parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
507 hbox.set_homogeneous(True)
509 button = hildon.Button(fhsize, horbtn)
510 button.set_label('1d')
511 button.connect("clicked", self.show_graph, '1d', win, symbol)
512 hbox.pack_start(button)
514 button = hildon.Button(fhsize, horbtn)
515 button.set_label('5d')
516 button.connect("clicked", self.show_graph, '5d', win, symbol)
517 hbox.pack_start(button)
519 button = hildon.Button(fhsize, horbtn)
520 button.set_label('3m')
521 button.connect("clicked", self.show_graph, '3m', win, symbol)
522 hbox.pack_start(button)
524 button = hildon.Button(fhsize, horbtn)
525 button.set_label('6m')
526 button.connect("clicked", self.show_graph, '6m', win, symbol)
527 hbox.pack_start(button)
529 vbox1.pack_start(hbox, False, False, 0)
531 hbox.set_homogeneous(True)
533 button = hildon.Button(fhsize, horbtn)
534 button.set_label('1y')
535 button.connect("clicked", self.show_graph, '1y', win, symbol)
536 hbox.pack_start(button)
538 button = hildon.Button(fhsize, horbtn)
539 button.set_label('2y')
540 button.connect("clicked", self.show_graph, '2y', win, symbol)
541 hbox.pack_start(button)
543 button = hildon.Button(fhsize, horbtn)
544 button.set_label('5y')
545 button.connect("clicked", self.show_graph, '5y', win, symbol)
546 hbox.pack_start(button)
548 button = hildon.Button(fhsize, horbtn)
549 button.set_label('Max')
550 button.connect("clicked", self.show_graph, 'max', win, symbol)
551 hbox.pack_start(button)
553 vbox1.pack_start(hbox, False, False, 0)
555 self.graph = gtk.Image()
556 vbox1.pack_start(self.graph, True, True, 0)
558 parea.add_with_viewport(vbox1)
560 vbox.pack_start(self.graphs_title, False, False, 0)
561 vbox.pack_start(gtk.HSeparator(), False, False, 0)
562 vbox.pack_start(parea, True, True, 0)
563 vbox.pack_start(gtk.HSeparator(), False, False, 5)
564 vbox.pack_start(toolbar, False, False, 0)
569 self.show_graph(None, '1d', win, symbol)
571 def show_graph(self, widget, option, win, symbol):
574 thread.start_new_thread(self.get_graph_data, (option, win, symbol))
576 def get_graph_data(self, option, win, symbol):
578 url = 'http://uk.ichart.yahoo.com/b?s=%s' % symbol
580 url = 'http://uk.ichart.yahoo.com/w?s=%s' % symbol
582 url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % symbol.lower()
584 url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % symbol.lower()
586 url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % symbol.lower()
588 url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % symbol.lower()
590 url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % symbol.lower()
591 elif option == 'max':
592 url = 'http://chart.finance.yahoo.com/c/my/s/%s' % symbol.lower()
595 myimg = urllib2.urlopen(url)
596 imgdata = myimg.read()
598 pbl = gtk.gdk.PixbufLoader()
601 pbuf = pbl.get_pixbuf()
602 pbuf = pbuf.scale_simple(475, 235, gtk.gdk.INTERP_TILES)
604 self.graph.set_from_pixbuf(pbuf)
607 logger.exception("Getting graph data: %s" % url)
609 self.graphs_title.set_label('Failed to get data')
612 def show_metal_graphs(self, widget, path, column, model):
613 metal = model[path][1]
614 metal_urls = self.get_metal_graphs_urls(metal)
619 win = hildon.StackableWindow()
620 #self.create_menu(win)
624 #toolbar = self.main_toolbar(False, True, None, '', '', False)
626 self.metalgraph_title = gtk.Label(metal)
627 color = gtk.gdk.color_parse("#03A5FF")
628 self.metalgraph_title.modify_fg(gtk.STATE_NORMAL, color)
630 parea = hildon.PannableArea()
631 parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
636 hbox.set_homogeneous(True)
638 button = hildon.Button(fhsize, horbtn)
639 button.set_label('live')
640 button.connect("clicked", self.show_metalgraph, 'live', win, metal_urls)
641 if 'live' in options:
642 hbox.pack_start(button)
644 button = hildon.Button(fhsize, horbtn)
645 button.set_label('30d')
646 button.connect("clicked", self.show_metalgraph, '30d', win, metal_urls)
648 hbox.pack_start(button)
650 button = hildon.Button(fhsize, horbtn)
651 button.set_label('60d')
652 button.connect("clicked", self.show_metalgraph, '60d', win, metal_urls)
654 hbox.pack_start(button)
656 button = hildon.Button(fhsize, horbtn)
657 button.set_label('6m')
658 button.connect("clicked", self.show_metalgraph, '6m', win, metal_urls)
660 hbox.pack_start(button)
662 vbox1.pack_start(hbox, False, False, 0)
664 hbox.set_homogeneous(True)
666 button = hildon.Button(fhsize, horbtn)
667 button.set_label('1y')
668 button.connect("clicked", self.show_metalgraph, '1y', win, metal_urls)
670 hbox.pack_start(button)
672 button = hildon.Button(fhsize, horbtn)
673 button.set_label('5y')
674 button.connect("clicked", self.show_metalgraph, '5y', win, metal_urls)
676 hbox.pack_start(button)
678 button = hildon.Button(fhsize, horbtn)
679 button.set_label('10y')
680 button.connect("clicked", self.show_metalgraph, '10y', win, metal_urls)
682 hbox.pack_start(button)
684 vbox1.pack_start(hbox, False, False, 0)
686 self.metalgraph = gtk.Image()
687 vbox1.pack_start(self.metalgraph, True, True, 0)
689 parea.add_with_viewport(vbox1)
691 vbox.pack_start(self.metalgraph_title, False, False, 0)
692 vbox.pack_start(gtk.HSeparator(), False, False, 0)
693 vbox.pack_start(parea, True, True, 0)
694 vbox.pack_start(gtk.HSeparator(), False, False, 5)
695 #vbox.pack_start(toolbar, False, False, 0)
700 self.show_metalgraph(None, options[0], win, metal_urls)
702 def show_metalgraph(self, widget, option, win, metal_urls):
705 thread.start_new_thread(self.get_metalgraph_data, (option, win, metal_urls))
707 def get_metalgraph_data(self, option, win, metal_urls):
714 myimg = urllib2.urlopen(url)
715 imgdata = myimg.read()
717 pbl = gtk.gdk.PixbufLoader()
721 pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, 475, 235)
722 pixbuf.fill(0xffffffff)
725 pbuf = pbl.get_pixbuf()
726 pbuf = pbuf.scale_simple(475, 235, gtk.gdk.INTERP_TILES)
728 pixbuf.composite(pbuf, 0, 0, pixbuf.props.width, pixbuf.props.height, 0, 0, 1.0, 1.0, gtk.gdk.INTERP_HYPER, 55)
732 self.metalgraph.set_from_pixbuf(pbuf)
735 logger.exception("Getting graph data: %s" % url)
737 self.metalgraph_title.set_label('Failed to get data')
738 self.metalgraph.destroy()
740 def get_metal_graphs_urls(self, metal):
742 liveurl = 'http://www.kitco.com/images/live/%s'
743 graphurl = 'http://www.kitco.com/LFgif/%s'
744 t24url = 'http://www.kitconet.com/charts/metals/base/%s'
746 metal_urls.append(['live', liveurl % 'gold.gif'])
747 metal_urls.append(['30d', graphurl % 'au0030lnb.gif'])
748 metal_urls.append(['60d', graphurl % 'au0060lnb.gif'])
749 metal_urls.append(['6m', graphurl % 'au0182nyb.gif'])
750 metal_urls.append(['1y', graphurl % 'au0365nyb.gif'])
751 metal_urls.append(['5y', graphurl % 'au1825nyb.gif'])
752 metal_urls.append(['10y', graphurl % 'au3650nyb.gif'])
753 elif metal == 'Silver':
754 metal_urls.append(['live', liveurl % 'silver.gif'])
755 metal_urls.append(['30d', graphurl % 'ag0030lnb.gif'])
756 metal_urls.append(['60d', graphurl % 'ag0060lnb.gif'])
757 metal_urls.append(['6m', graphurl % 'ag0182nyb.gif'])
758 metal_urls.append(['1y', graphurl % 'ag0365nyb.gif'])
759 metal_urls.append(['5y', graphurl % 'ag1825nyb.gif'])
760 metal_urls.append(['10y', graphurl % 'ag3650nyb.gif'])
761 elif metal == 'Platinum':
762 metal_urls.append(['live', liveurl % 'plati.gif'])
763 metal_urls.append(['30d', graphurl % 'pt0030lnb.gif'])
764 metal_urls.append(['60d', graphurl % 'pt0060lnb.gif'])
765 metal_urls.append(['6m', graphurl % 'pt0182nyb.gif'])
766 metal_urls.append(['1y', graphurl % 'pt0365nyb.gif'])
767 metal_urls.append(['5y', graphurl % 'pt1825nyb.gif'])
768 elif metal == 'Palladium':
769 metal_urls.append(['live', liveurl % 'plad.gif'])
770 metal_urls.append(['30d', graphurl % 'pd0030lnb.gif'])
771 metal_urls.append(['60d', graphurl % 'pd0060lnb.gif'])
772 metal_urls.append(['6m', graphurl % 'pd0182nyb.gif'])
773 metal_urls.append(['1y', graphurl % 'pd0365nyb.gif'])
774 metal_urls.append(['5y', graphurl % 'pd1825nyb.gif'])
775 elif metal == 'Rhodium':
776 metal_urls.append(['30d', graphurl % 'rh0030lnb.gif'])
777 metal_urls.append(['60d', graphurl % 'rh0060lnb.gif'])
778 metal_urls.append(['6m', graphurl % 'rh0182lnb.gif'])
779 metal_urls.append(['1y', graphurl % 'rh0365lnb.gif'])
780 metal_urls.append(['5y', graphurl % 'rh1825lnb.gif'])
781 elif metal == 'Copper':
782 metal_urls.append(['live', t24url % 't24_cp450x275.gif'])
783 elif metal == 'Nickel':
784 metal_urls.append(['live', t24url % 't24_nk450x275.gif'])
785 elif metal == 'Aluminium':
786 metal_urls.append(['live', t24url % 't24_al450x275.gif'])
787 elif metal == 'Zinc':
788 metal_urls.append(['live', t24url % 't24_zc450x275.gif'])
789 elif metal == 'Lead':
790 metal_urls.append(['live', t24url % 't24_ld450x275.gif'])
794 def _tv_columns(self, treeview):
795 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
796 column.set_visible(False)
797 treeview.append_column(column)
799 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
800 treeview.append_column(column)
802 def __create_model(self, names, ids):
803 lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
804 for item in range(len(names)):
805 iter = lstore.append()
806 lstore.set(iter, 0, ids[item], 1, names[item])
809 def main_toolbar(self, quotesview, portfolio, widgets, symbol, name, initial):
811 #toolbar.set_homogeneous(True)
813 portfolio_btn = hildon.Button(fhsize, horbtn)
814 portfolio_btn.set_title("Portfolio")
815 portfolio_btn.connect("clicked", self.show_portfolio_view)
817 graph_btn = hildon.Button(fhsize, horbtn)
818 graph_btn.set_title("Graph")
819 graph_btn.connect("clicked", self.show_graph_view, symbol, name)
821 refresh_btn = hildon.Button(fhsize, horbtn)
822 refresh_btn.set_title("Refresh")
823 refresh_btn.connect("clicked", self.refresh_stock_data, portfolio,
827 info_btn = hildon.Button(fhsize, horbtn)
828 img = gtk.image_new_from_icon_name("general_information", gtk.ICON_SIZE_SMALL_TOOLBAR)
829 info_btn.set_image(img)
830 info_btn.connect("clicked", self.show_app_information)
832 search_btn = hildon.Button(fhsize, horbtn)
833 img = gtk.image_new_from_icon_name("general_search", gtk.ICON_SIZE_SMALL_TOOLBAR)
834 search_btn.set_image(img)
835 search_btn.connect("clicked", self.show_search_dialog)
838 toolbar.pack_start(portfolio_btn)
840 toolbar.pack_start(info_btn, False, False, 0)
842 toolbar.pack_start(graph_btn)
843 toolbar.pack_start(refresh_btn)
846 toolbar.pack_start(search_btn, False, False, 0)
852 def show_search_dialog(self, widget):
853 dlg = gtk.Dialog(title='Search company', parent=None, flags=0)
854 dlg.set_has_separator(False)
858 entry = hildon.Entry(fhsize)
859 entry.connect("activate", self.do_search, entry, dlg)
860 hbox.pack_start(entry, True, True, 0)
862 button = hildon.Button(fhsize, horbtn)
863 img = gtk.image_new_from_icon_name("general_search", gtk.ICON_SIZE_SMALL_TOOLBAR)
864 button.set_image(img)
865 button.connect("clicked", self.do_search, entry, dlg)
866 hbox.pack_start(button, False, False, 0)
868 dlg.vbox.pack_start(hbox, False, False, 0)
875 def do_search(self, widget, entry, dlg):
877 text = entry.get_text()
880 winprogind(self.window, 1)
881 thread.start_new_thread(self._really_do_search, (text,))
883 def _really_do_search(self, text):
886 for market in marketdata.eunames:
887 for company in market:
888 allnames.append(company)
890 for market in marketdata.omnames:
891 for company in market:
892 allnames.append(company)
894 for market in marketdata.usnames:
895 for company in market:
896 allnames.append(company)
899 for market in marketdata.eusymbols:
900 for company in market:
901 allsymbols.append(company)
903 for market in marketdata.omsymbols:
904 for company in market:
905 allsymbols.append(company)
907 for market in marketdata.ussymbols:
908 for company in market:
909 allsymbols.append(company)
911 new_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
912 for i in range(len(allnames)):
913 if text.lower() in allnames[i].lower():
914 niter = new_model.append()
915 #print allsymbols[i], allnames[i]
916 #FIXME: repeated companies in the results list
917 #print if allnames[i]
919 # if j[1] == allnames[i]:
920 new_model.set(niter, 0, allsymbols[i], 1, allnames[i])
922 if len(new_model) == 0:
923 winprogind(self.window, 0)
924 gtk.gdk.threads_enter()
925 self.show_info_banner(self.window, "No items found for this search")
926 gtk.gdk.threads_leave()
929 gtk.gdk.threads_enter()
930 self.show_search_screen(new_model, text)
931 gtk.gdk.threads_leave()
932 winprogind(self.window, 0)
935 def show_search_screen(self, model, text):
936 window = hildon.StackableWindow()
937 self.create_menu(window)
938 window.set_title("Search for " + text)
941 toolbar = self.main_toolbar(False, False, None, '', '', False)
943 parea = hildon.PannableArea()
944 parea.connect("horizontal-movement", self.horizontal_mov)
945 tv = hildon.GtkTreeView(ui_normal)
946 tv.connect("row-activated", self.show_quotes_view, model, False)
951 vbox.pack_start(parea, True, True, 0)
952 vbox.pack_start(gtk.HSeparator(), False, False, 5)
953 vbox.pack_start(toolbar, False, False, 0)
958 def show_app_information(self, widget):
959 self.show_information_note(self.window, (
960 "The data is got from Yahoo! Finance.\n"
961 "It could be delayed or even wrong.\n"
962 "The author doesn't validate in any way this data and therefore he is not responsible for any damage that may occur.\n\n"
963 "You can scroll large list with gestures:\n"
964 "Left-to-right gesture: scroll down.\n"
965 "Right-to-left gesture: scroll up."))
967 def show_portfolio_view(self, widget):
968 data = settings.load_portfolio(settingsdb)
973 win = hildon.StackableWindow()
974 self.create_menu(win)
975 win.set_title("Portfolio")
979 parea = hildon.PannableArea()
980 parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
981 tv = hildon.GtkTreeView(ui_normal)
982 tv.set_headers_visible(True)
983 self.portfolio_model = self._create_portfolio_model(data)
984 self.quotes_id = tv.connect("row-activated", self.show_quotes_view,
985 self.portfolio_model, True)
986 tv.set_model(self.portfolio_model)
987 self._tv_portfolio_columns(tv)
991 button = hildon.Button(fhsize, horbtn)
992 button.set_title("Refresh All")
993 button.connect("clicked", self.refresh_portfolio, tv, win)
994 hbox.pack_start(button, True, True, 0)
996 button = hildon.Button(fhsize, horbtn)
997 button.set_title("Add manually")
998 button.connect("clicked", self.add_item_dlg, None, None)
999 hbox.pack_start(button, True, True, 0)
1001 button = hildon.Button(fhsize, horbtn)
1002 button.set_title("Remove")
1003 button.connect("clicked", self.remove_item)
1004 hbox.pack_start(button, True, True, 0)
1006 button = hildon.CheckButton(fhsize)
1007 button.set_label("Edit")
1009 button.connect("toggled", self.edit_toggled, tv)
1010 hbox.pack_start(button, True, True, 0)
1013 vbox.pack_start(parea, True, True, 0)
1014 vbox.pack_start(hbox, False, False, 0)
1018 def edit_toggled(self, widget, tv):
1019 if widget.get_active():
1020 tv.disconnect(self.quotes_id)
1021 self.edit_id = tv.connect("row-activated",
1022 self.edit_portfolio_item, self.portfolio_model)
1024 tv.disconnect(self.edit_id)
1025 self.quotes_id = tv.connect("row-activated",
1026 self.show_quotes_view, self.portfolio_model, True)
1028 def edit_portfolio_item(self, widget, path, column, model):
1029 seliter = model.get_iter(path)
1031 symbol = model[path][0]
1032 name = model[path][1]
1033 shares = model[path][2]
1035 data = [shares, symbol, name]
1036 self.add_item_dlg(widget, data, seliter)
1038 def add_item_dlg(self, widget, data, seliter):
1043 title = "Edit item from portfolio"
1050 title = "Add to portfolio"
1054 dlg = gtk.Dialog(title=title, parent=None, flags=0)
1055 dlg.set_has_separator(False)
1057 button1 = hildon.PickerButton(fhsize, horbtn)
1058 data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
1060 selector = self.create_selector(data, True)
1061 button1.set_selector(selector)
1062 button1.set_title("Your shares")
1063 button1.set_value(shares)
1064 dlg.vbox.pack_start(button1, False, False, 0)
1066 entry1 = hildon.Entry(fhsize)
1067 entry1.set_text(name)
1068 entry2 = hildon.Entry(fhsize)
1069 entry2.set_text(symbol)
1071 entry1.set_placeholder("Name")
1072 entry1.connect("activate", self.add_item, dlg, button1, entry1,
1073 entry2, edit, seliter)
1074 dlg.vbox.pack_start(entry1, False, False, 0)
1076 entry2.connect("activate", self.add_item, dlg, button1, entry1,
1077 entry2, edit, seliter)
1078 entry2.set_placeholder("Yahoo Finance symbol")
1079 dlg.vbox.pack_start(entry2, False, False, 0)
1081 button = hildon.Button(fhsize, horbtn)
1082 button.set_label(btntext)
1083 button.connect("clicked", self.add_item, dlg, button1, entry1,
1084 entry2, edit, seliter)
1085 dlg.vbox.pack_start(button, False, False, 0)
1091 def add_item(self, widget, dlg, button, entry1, entry2, edit, seliter):
1092 symbol = entry2.get_text()
1093 name = entry1.get_text()
1094 shares = button.get_value()
1096 if name == '' or symbol == '':
1097 self.show_info_banner(widget, "Must add the name and symbol")
1100 self.add_to_portfolio(widget, button, symbol, name)
1104 self.portfolio_model.set(seliter, 0, symbol, 1, name, 2, shares,
1105 3, "-", 4, "-", 5, "-", 6, "green")
1107 niter = self.portfolio_model.append()
1108 self.portfolio_model.set(niter, 0, symbol, 1, name, 2, shares,
1109 3, "-", 4, "-", 5, "-", 6, "green")
1111 def remove_item(self, widget):
1112 win = hildon.StackableWindow()
1114 toolbar = hildon.EditToolbar("Choose items to delete", "Delete")
1115 win.set_edit_toolbar(toolbar)
1118 parea = hildon.PannableArea()
1119 tv = hildon.GtkTreeView(ui_edit)
1120 selection = tv.get_selection()
1121 selection.set_mode(gtk.SELECTION_MULTIPLE)
1122 tv.set_model(self.portfolio_model)
1123 self._tv_remove_portfolio_columns(tv)
1126 toolbar.connect("button-clicked", self.delete_from_portfolio, win, tv,
1128 toolbar.connect_object("arrow-clicked", gtk.Window.destroy, win)
1130 vbox.pack_start(parea, True, True, 0)
1134 def delete_from_portfolio(self, widget, win, tv, selection):
1135 if not self.is_treeview_selected(tv):
1138 conf = self.show_confirmation(win, "Delete items?")
1142 selmodel, selected = selection.get_selected_rows()
1143 iters = [selmodel.get_iter(path) for path in selected]
1145 symbol = selmodel.get_value(i, 0)
1146 settings.delete_item_from_portfolio(settingsdb, symbol)
1149 logger.exception("Deleting item from portfolio")
1150 self.info_banner(widget, "Error deleting item")
1152 def _tv_remove_portfolio_columns(self, treeview):
1153 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
1154 column.set_visible(False)
1155 treeview.append_column(column)
1157 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
1158 column.set_property("expand", True)
1159 treeview.append_column(column)
1161 column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
1162 column.set_visible(False)
1163 treeview.append_column(column)
1165 column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
1166 column.set_visible(False)
1167 treeview.append_column(column)
1169 def refresh_portfolio(self, widget, tv, win):
1170 data = settings.load_portfolio(settingsdb)
1176 thread.start_new_thread(self._do_refresh_portfolio, (data, tv, win))
1178 def _do_refresh_portfolio(self, data, tv, win):
1181 item[3], item[4] = self.get_portfolio_data(item[0])
1184 100.0 * float(item[4])/(float(item[3]) - \
1189 item[5] = '%6.2f %%' % ch_percent
1193 self.portfolio_model = self._create_portfolio_model(data)
1194 tv.set_model(self.portfolio_model)
1197 def get_portfolio_data(self, symbol):
1198 from ystockquote import ystockquote as yt
1200 data = yt.get_all(symbol)
1201 return data['price'], data['change']
1203 logger.exception("Getting price from Yahoo: %s" % symbol)
1206 def _create_portfolio_model(self, data):
1207 lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
1208 gobject.TYPE_STRING, gobject.TYPE_STRING,
1209 gobject.TYPE_STRING, gobject.TYPE_STRING,
1210 gobject.TYPE_STRING)
1212 iter = lstore.append()
1217 lstore.set(iter, 0, item[0], 1, item[1], 2, item[2], 3, item[3],
1218 4, item[4], 5, item[5], 6, color)
1221 def _tv_portfolio_columns(self, treeview):
1222 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
1223 column.set_visible(False)
1224 treeview.append_column(column)
1226 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
1227 column.set_property("expand", True)
1228 treeview.append_column(column)
1230 column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
1231 treeview.append_column(column)
1233 column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
1234 treeview.append_column(column)
1236 column = gtk.TreeViewColumn('Change', gtk.CellRendererText(), text=4)
1237 treeview.append_column(column)
1240 renderer = gtk.CellRendererText()
1241 renderer.set_property("foreground-set", True)
1242 column = gtk.TreeViewColumn('%', renderer, text=5, foreground=6)
1243 treeview.append_column(column)
1245 def show_confirmation(self, window, msg):
1246 dialog = hildon.hildon_note_new_confirmation(window, msg)
1248 result = dialog.run()
1249 if result == gtk.RESPONSE_OK:
1256 def show_information_note(self, window, msg):
1257 dialog = hildon.hildon_note_new_information(window, msg)
1259 result = dialog.run()
1262 def show_info_banner(self, widget, msg):
1263 hildon.hildon_banner_show_information(widget, 'qgn_note_infoprint', msg)
1265 def is_treeview_selected(self, treeview):
1266 selection = treeview.get_selection()
1267 if selection.count_selected_rows() == 0:
1268 self.show_info_banner(treeview, 'No selected item')
1275 def __init__(self, widget):
1276 self.abdialog = gtk.Dialog()
1277 self.abdialog.set_title("About StockThis")
1279 notebook = gtk.Notebook()
1280 notebook.set_show_tabs(False)
1281 notebook.set_scrollable(False)
1282 notebook.set_show_border(False)
1284 # Description page #
1288 label.set_markup("<b><big>StockThis %s</big></b>" % VERSION)
1289 vbox.pack_start(label, True, True, 0)
1291 label = gtk.Label("Stocks application with big database")
1292 vbox.pack_start(label, True, True, 0)
1294 label = gtk.Label("GNU General Public License")
1295 vbox.pack_start(label, True, True, 0)
1297 url = "http://stockthis.garage.maemo.org"
1298 webbtn = gtk.LinkButton(url, "Web")
1299 vbox.pack_start(webbtn, True, True, 0)
1300 gtk.link_button_set_uri_hook(self.launch_browser)
1302 notebook.append_page(vbox, gtk.Label())
1306 textview = hildon.TextView()
1307 textview.set_cursor_visible(False)
1308 textview.set_wrap_mode(gtk.WRAP_WORD)
1309 text = "Written by Daniel Martin Yerga (dyerga@gmail.com)"
1310 textview.get_buffer().set_text(text)
1312 parea = hildon.PannableArea()
1315 vbox.pack_start(parea, True, True, 0)
1316 notebook.append_page(vbox, gtk.Label())
1322 textview = hildon.TextView()
1323 textview.set_cursor_visible(False)
1324 textview.set_wrap_mode(gtk.WRAP_WORD)
1325 text = """StockThis is a free software application.
1326 Developing good software takes time and hard work.
1327 StockThis's author develops the program in his spare time.
1328 If you like the program and it's helpful, consider donating a small amount of money.
1329 Donations are a great incentive and help the developer feel that the hard work is appreciated.
1331 textview.get_buffer().set_text(text)
1333 parea = hildon.PannableArea()
1336 button = hildon.Button(fhsize, horbtn)
1337 button.set_title("Make donation")
1338 url = "http://stockthis.garage.maemo.org/donate.html"
1339 button.connect("clicked", self.launch_browser, url)
1340 vbox.pack_start(button, False, False, 0)
1341 vbox.pack_start(parea, True, True, 0)
1343 notebook.append_page(vbox, gtk.Label())
1348 textview = hildon.TextView()
1349 textview.set_cursor_visible(False)
1350 textview.set_wrap_mode(gtk.WRAP_WORD)
1351 text = """StockThis is being improved thanks to bug reports that users have submitted. The author appreciates these reports.
1352 If the application is having an error when you're using it, you have two choices to report this error:
1353 1) Send the log from the button above (if there's an error in the log).
1354 2) Press the button and read how to report a bug."""
1355 textview.get_buffer().set_text(text)
1357 parea = hildon.PannableArea()
1361 hbox.set_homogeneous(True)
1363 button = hildon.Button(fhsize, horbtn)
1364 button.set_title("Report error")
1365 url = "http://stockthis.garage.maemo.org/reporting.html"
1366 button.connect("clicked", self.launch_browser, url)
1367 hbox.pack_start(button, True, True, 0)
1369 button = hildon.Button(fhsize, horbtn)
1370 button.set_title("Log")
1371 button.connect("clicked", self.on_show_log)
1372 hbox.pack_start(button, True, True, 0)
1374 vbox.pack_start(hbox, False, False, 0)
1375 vbox.pack_start(parea, True, True, 0)
1377 notebook.append_page(vbox, gtk.Label())
1382 textview = hildon.TextView()
1383 textview.set_cursor_visible(False)
1384 textview.set_wrap_mode(gtk.WRAP_WORD)
1385 text = """The downloads section in maemo.org has a nice system where you can rate applications.
1386 If you consider StockThis a good application (or a bad one too), you could rate it in maemo.org site."""
1387 textview.get_buffer().set_text(text)
1389 button = hildon.Button(fhsize, horbtn)
1390 button.set_title("Rate StockThis")
1391 url = "http://maemo.org/downloads/product/Maemo5/stockthis"
1392 button.connect("clicked", self.launch_browser, url)
1394 image.set_from_file(imgdir + "maemoorg.png")
1395 vbox.pack_start(button, False, False, 0)
1396 vbox.pack_start(image, False, False, 5)
1397 vbox.pack_start(textview, True, True, 0)
1399 notebook.append_page(vbox, gtk.Label())
1402 self.abdialog.vbox.pack_start(notebook, True, True, 0)
1406 descbutton = hildon.GtkRadioButton(fhsize)
1407 descbutton.set_mode(False)
1408 descbutton.set_active(True)
1409 descbutton.set_label('Description')
1410 descbutton.connect("toggled", self.change_tab, notebook, 0)
1411 hbox.pack_start(descbutton, True, True, 0)
1413 button = hildon.GtkRadioButton(fhsize)
1414 button.set_mode(False)
1415 button.set_active(True)
1416 button.set_label('Credits')
1417 button.set_group(descbutton)
1418 button.connect("toggled", self.change_tab, notebook, 1)
1419 hbox.pack_start(button, True, True, 0)
1421 button = hildon.GtkRadioButton(fhsize)
1422 button.set_mode(False)
1423 button.set_label('Donate')
1424 button.set_group(descbutton)
1425 button.connect("clicked", self.change_tab, notebook, 2)
1426 hbox.pack_start(button, True, True, 0)
1428 button = hildon.GtkRadioButton(fhsize)
1429 button.set_mode(False)
1430 button.set_label('Report')
1431 button.set_group(descbutton)
1432 button.connect("clicked", self.change_tab, notebook, 3)
1433 hbox.pack_start(button, True, True, 0)
1435 button = hildon.GtkRadioButton(fhsize)
1436 button.set_mode(False)
1437 button.set_label('Rate')
1438 button.set_group(descbutton)
1439 button.connect("clicked", self.change_tab, notebook, 4)
1440 hbox.pack_start(button, True, True, 0)
1442 self.abdialog.vbox.pack_start(hbox, False, False, 0)
1444 self.abdialog.show_all()
1446 self.abdialog.destroy()
1448 def change_tab(self, widget, notebook, number):
1449 notebook.set_current_page(number)
1451 def launch_browser(self, widget, url):
1453 bus = dbus.SystemBus()
1454 proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request")
1455 iface = dbus.Interface(proxy, 'com.nokia.osso_browser')
1457 self.abdialog.destroy()
1459 iface.open_new_window(url)
1461 def on_show_log(self, widget):
1462 Log(widget, logfile)
1467 def __init__(self, widget, logfile):
1469 dialog = gtk.Dialog(title='Log', parent=None)
1471 dialog.set_size_request(600, 350)
1473 parea = hildon.PannableArea()
1474 parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
1476 textview = hildon.TextView()
1477 textview.set_property("editable", False)
1478 textview.set_property("wrap-mode", gtk.WRAP_WORD)
1480 log = open(logfile, 'r')
1481 logtext = log.read()
1484 textview.get_buffer().set_text(logtext)
1487 dialog.vbox.pack_start(parea, True, True, 0)
1491 save_btn = hildon.Button(fhsize, horbtn)
1492 save_btn.set_title("Save")
1493 save_btn.connect('clicked', self.save, logfile, dialog)
1495 clear_btn = hildon.Button(fhsize, horbtn)
1496 clear_btn.set_title("Clear")
1497 clear_btn.connect('clicked', self.clear, textview, logfile)
1499 send_btn = hildon.Button(fhsize, horbtn)
1500 send_btn.set_title('Send')
1501 send_btn.connect('clicked', self.send, dialog, logfile)
1503 hbox.pack_start(save_btn, True, True, 0)
1504 hbox.pack_start(clear_btn, True, True, 0)
1505 hbox.pack_start(send_btn, True, True, 0)
1507 dialog.vbox.pack_start(hbox, False, False, 0)
1513 def show_filechooser(self, window, title, name, EXT):
1514 action = gtk.FILE_CHOOSER_ACTION_SAVE
1516 m = hildon.FileSystemModel()
1517 file_dialog = hildon.FileChooserDialog(window, action, m)
1518 file_dialog.set_title(title)
1520 file_dialog.set_current_name(name)
1521 HOME = os.path.expanduser("~")
1523 if os.path.exists(HOME + '/MyDocs/.documents'):
1524 file_dialog.set_current_folder(HOME + '/MyDocs/.documents')
1526 file_dialog.set_current_folder(HOME)
1528 file_dialog.set_default_response(gtk.RESPONSE_CANCEL)
1530 result = file_dialog.run()
1531 if result == gtk.RESPONSE_OK:
1532 namefile = file_dialog.get_filename()
1533 namefile, extension = os.path.splitext(namefile)
1534 namefile = namefile + "." + EXT
1537 file_dialog.destroy()
1542 def clear(self, widget, textview, logfile):
1543 textview.get_buffer().set_text('')
1544 f = open(logfile, 'w')
1547 def save(self, widget, logfile, dlg):
1549 filename = self.show_filechooser(dlg, "Save log file",
1550 "stockthis-log", "txt")
1556 shutil.copyfile(logfile, filename)
1557 stockspy.show_info_banner(widget, 'Log file saved')
1559 logger.exception("Saving log file")
1560 stockspy.show_info_banner(widget, 'Error saving the log file')
1562 def send(self, widget, dlg, logfile):
1563 sendtxt = ("You are going to send the log to the developers.\n"
1564 "This helps the developers to track problems with the application.\n"
1565 "It doesn't send any personal information (like passwords or similar).")
1567 dialog = hildon.hildon_note_new_confirmation(dlg, sendtxt)
1568 dialog.set_button_texts("Send", "Cancel")
1570 response = dialog.run()
1571 if response == gtk.RESPONSE_OK:
1572 self.do_pre_send(dlg, logfile)
1576 def do_pre_send(self, dlg, logfile):
1578 hildon.hildon_gtk_window_set_progress_indicator(dlg, 1)
1579 thread.start_new_thread(self._do_send, (dlg, logfile))
1581 def _do_send(self, dlg, logfile):
1582 import pycurl, shutil, random, commands
1585 for i in random.sample('abcdefghijkl123456789', 18):
1588 rnamepath = HOME + "/.stockthis/" + rname
1589 shutil.copyfile(logfile, rnamepath)
1591 gtkversion = "%s.%s.%s" % gtk.ver
1592 if os.path.exists("/etc/maemo_version"):
1593 mfile = open("/etc/maemo_version", 'r')
1594 maemoversion = mfile.read()
1599 opsystem = ' '.join(os.uname())
1600 pyversion = os.sys.version
1602 comm = ("awk '/Private_Dirty/{sum+=$2}END{print sum \"kB\"}'"
1603 " /proc/%s/smaps") % pid
1604 status, dirtymem = commands.getstatusoutput(comm)
1606 lfile = open(rnamepath, 'r')
1611 log = ("%s\nPython version: %s\nGtk version: %s\n"
1612 "Maemo version: %sOperating system: %s\n"
1613 "Dirty Memory: %s\nLog:\n%s") % (_version, pyversion, gtkversion,
1614 maemoversion, opsystem, dirtymem, log)
1616 lfile = open(rnamepath, 'w')
1620 url = "http://yerga.net/logs/uploader.php"
1621 data = [('uploadedfile', (pycurl.FORM_FILE, rnamepath)),]
1622 mycurl = pycurl.Curl()
1623 mycurl.setopt(pycurl.URL, url)
1624 mycurl.setopt(pycurl.HTTPPOST, data)
1628 os.remove(rnamepath)
1630 gtk.gdk.threads_enter()
1631 stockspy.show_info_banner(dlg, 'Log sent')
1632 gtk.gdk.threads_leave()
1633 hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
1635 logger.exception("Sending log file")
1636 gtk.gdk.threads_enter()
1637 stockspy.show_info_banner(dlg, 'Error sending the log file')
1638 gtk.gdk.threads_leave()
1639 hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
1642 if __name__ == "__main__":
1643 stockspy = StocksPy()
1644 gtk.gdk.threads_enter()
1646 gtk.gdk.threads_leave()