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 # StocksPy: Application to get stocks data from Yahoo Finance.
23 _version = "StockThis 0.3 alpha1 rev1"
35 osso_c = osso.Context("net.yerga.stockthis", "0.3", False)
37 #detect if is ran locally or not
38 runningpath = sys.path[0]
40 if '/usr/share' in runningpath:
41 runninglocally = False
45 HOME = os.path.expanduser("~")
47 settingsdb, imgdir, configdir, logfile = \
48 settings.define_paths(runninglocally, HOME)
51 logger = logging.getLogger('st')
52 logging.basicConfig(filename=logfile,level=logging.ERROR, filemode='w')
57 #set the main logger to DEBUG
58 logger.setLevel(logging.DEBUG)
60 #Create a handler for console debug
61 console = logging.StreamHandler()
62 console.setLevel(logging.DEBUG)
63 # set a format which is simpler for console use
64 formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
65 # tell the handler to use this format
66 console.setFormatter(formatter)
67 logging.getLogger('').addHandler(console)
69 fhsize = gtk.HILDON_SIZE_FINGER_HEIGHT
70 horbtn = hildon.BUTTON_ARRANGEMENT_HORIZONTAL
71 ui_normal = gtk.HILDON_UI_MODE_NORMAL
72 ui_edit = gtk.HILDON_UI_MODE_EDIT
73 winprogind = hildon.hildon_gtk_window_set_progress_indicator
75 logger.debug("test this log")
77 gtk.gdk.threads_init()
82 self.program = hildon.Program()
83 self.program.__init__()
84 gtk.set_application_name("StockThis")
85 self.window = hildon.StackableWindow()
86 self.window.set_default_size(800, 480)
87 self.program.add_window(self.window)
88 self.window.connect("destroy", gtk.main_quit)
90 self.create_menu(self.window)
93 toolbar = self.main_toolbar(False, False, None, '', '')
95 parea = hildon.PannableArea()
96 tv = hildon.GtkTreeView(ui_normal)
97 inmodel = self.__create_model(marketdata.main, marketdata.idmain)
98 tv.connect("row-activated", self.show_instrument_view, inmodel,
99 marketdata.localmarkets, marketdata.localids,
101 tv.set_model(inmodel)
105 vbox.pack_start(parea, True, True, 0)
106 vbox.pack_start(gtk.HSeparator(), False, False, 5)
107 vbox.pack_start(toolbar, False, False, 0)
109 self.window.add(vbox)
110 self.window.show_all()
112 def create_menu(self, window):
113 menu = hildon.AppMenu()
114 window.set_app_menu(menu)
115 button = gtk.Button("About")
116 button.connect("clicked", About)
118 button = gtk.Button("Log")
119 button.connect("clicked", Log, logfile)
123 def show_instrument_view(self, widget, path, column, inmodel, names,
125 market = inmodel[path][0]
126 names = names[mindex.index(market)]
127 ids = ids[mindex.index(market)]
129 window = hildon.StackableWindow()
130 self.create_menu(window)
131 window.set_title("StockThis - " + inmodel[path][1])
134 toolbar = self.main_toolbar(False, False, None, '', '')
136 parea = hildon.PannableArea()
137 parea.connect("horizontal-movement", self.horizontal_mov)
138 tv = hildon.GtkTreeView(ui_normal)
139 model = self.__create_model(names, ids)
140 tv.connect("row-activated", self.show_quotes_view, model, False)
145 vbox.pack_start(parea, True, True, 0)
146 vbox.pack_start(gtk.HSeparator(), False, False, 5)
147 vbox.pack_start(toolbar, False, False, 0)
152 def horizontal_mov(self, parea, direction, initial_x, initial_y):
153 #direction = 2 right-to-left
154 #direction = 3 lefto-to-right
157 parea.scroll_to(-1, initial_y-400)
159 parea.scroll_to(-1, initial_y+400)
166 def show_quotes_view(self, widget, path, column, model, portfolio):
167 quote = model[path][0], model[path][1]
168 #print "quote:", quote[0]
169 #('EURUSD=X', 'EUR/USD')
171 #Currencies and ETFs should show the list now -> view = True
172 #Other items show a new list with options
174 for i in marketdata.localids[(len(marketdata.localids)-2):]:
181 if quote[0] in marketdata.idindexes:
182 self.show_instrument_view(widget, path, column, model,
183 marketdata.wnamesindexes,
184 marketdata.widsindexes,
185 marketdata.idindexes)
187 if quote[0] in marketdata.idotmarkets:
188 self.show_instrument_view(widget, path, column, model,
190 marketdata.omsymbols,
191 marketdata.idotmarkets)
193 if quote[0] in marketdata.ideumarkets:
194 self.show_instrument_view(widget, path, column, model,
196 marketdata.eusymbols,
197 marketdata.ideumarkets)
199 if quote[0] in marketdata.idusmarkets:
200 self.show_instrument_view(widget, path, column, model,
202 marketdata.ussymbols,
203 marketdata.idusmarkets)
207 win = hildon.StackableWindow()
208 self.create_menu(win)
209 win.set_title("StockThis - Quotes View - " + quote[1])
213 ltitle = gtk.Label('')
214 ltitle.set_markup('<b><big>' + quote[1].replace('&', '') +
216 color = gtk.gdk.color_parse("#03A5FF")
217 ltitle.modify_fg(gtk.STATE_NORMAL, color)
219 parea = hildon.PannableArea()
224 label = gtk.Label('')
225 label.set_markup('<b><big>Price:</big></b>')
226 lprice = gtk.Label('')
227 hbox.pack_start(label, False, False, 20)
228 hbox.pack_start(lprice, False, False, 245)
229 vbox1.pack_start(hbox, True, True, 0)
232 label = gtk.Label('')
233 label.set_markup('<b><big>Change:</big></b>')
234 lchange = gtk.Label('')
235 lpercent = gtk.Label('')
236 hbox.pack_start(label, False, False, 20)
237 hbox.pack_start(lchange, False, False, 205)
238 hbox.pack_start(lpercent, False, False, 0)
239 vbox1.pack_start(hbox, True, True, 0)
242 label = gtk.Label('')
243 label.set_markup('<b><big>Volume:</big></b>')
244 lvolume = gtk.Label('')
245 hbox.pack_start(label, False, False, 20)
246 hbox.pack_start(lvolume, False, False, 207)
247 vbox1.pack_start(hbox, True, True, 0)
250 label = gtk.Label('')
251 label.set_markup('<b><big>52 week high:</big></b>')
252 l52whigh = gtk.Label('')
253 hbox.pack_start(label, False, False, 20)
254 hbox.pack_start(l52whigh, False, False, 125)
255 vbox1.pack_start(hbox, True, True, 0)
258 label = gtk.Label('')
259 label.set_markup('<b><big>52 week low:</big></b>')
260 l52wlow = gtk.Label('')
261 hbox.pack_start(label, False, False, 20)
262 hbox.pack_start(l52wlow, False, False, 140)
263 vbox1.pack_start(hbox, True, True, 0)
266 button1 = hildon.PickerButton(fhsize, horbtn)
267 data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
269 selector = self.create_selector(data, True)
270 button1.set_selector(selector)
271 button1.set_title("Your shares")
272 shares = self.get_shares_from_symbol(quote[0])
273 button1.set_value(shares)
274 hbox.pack_start(button1, True, True, 0)
276 button = hildon.Button(fhsize, horbtn)
277 button.set_title("Add to Portfolio")
278 button.connect("clicked", self.add_to_portfolio, button1, quote[0], quote[1])
279 hbox.pack_start(button, True, True, 0)
282 label = gtk.Label('')
283 label.set_markup('<b><big>Shares:</big></b>')
284 lshares = gtk.Label(shares)
285 hbox1.pack_start(label, False, False, 20)
286 hbox1.pack_start(lshares, False, False, 220)
289 label = gtk.Label('')
290 label.set_markup('<b><big>Holdings Value:</big></b>')
291 holdingsvalue = gtk.Label("")
292 hbox2.pack_start(label, False, False, 20)
293 hbox2.pack_start(holdingsvalue, False, False, 105)
296 label = gtk.Label('')
297 label.set_markup("<b><big>Day's Value Change:</big></b>")
298 dayvaluechange = gtk.Label("")
299 hbox3.pack_start(label, False, False, 20)
300 hbox3.pack_start(dayvaluechange, False, False, 45)
303 vbox1.pack_start(hbox, False, False, 0)
305 vbox1.pack_start(hbox1, True, True, 0)
306 vbox1.pack_start(hbox2, True, True, 0)
307 vbox1.pack_start(hbox3, True, True, 0)
309 parea.add_with_viewport(vbox1)
311 widgets = [win, ltitle, lprice, lchange, lpercent, lvolume, l52whigh,
312 l52wlow, lshares, holdingsvalue, dayvaluechange]
314 toolbar = self.main_toolbar(True, portfolio, widgets, quote[0], quote[1])
316 vbox.pack_start(ltitle, False, False, 0)
317 vbox.pack_start(gtk.HSeparator(), False, False, 0)
318 vbox.pack_start(parea, True, True, 0)
319 vbox.pack_start(gtk.HSeparator(), False, False, 5)
320 vbox.pack_start(toolbar, False, False, 0)
325 self.show_data(quote[0], widgets, shares)
327 def get_shares_from_symbol(self, symbol):
330 portfolio_data = settings.load_portfolio(settingsdb)
331 for item in portfolio_data :
336 logger.exception("Getting shares from symbol")
339 def add_to_portfolio(self, widget, button, symbol, name):
340 shares = button.get_value()
343 portfolio = settings.load_portfolio(settingsdb)
345 for item in portfolio:
347 index = portfolio.index(item)
349 item = [symbol, name, shares, '-']
352 settings.insert_new_item_to_portfolio(settingsdb, item)
354 settings.delete_item_from_portfolio(settingsdb, symbol)
355 settings.insert_new_item_to_portfolio(settingsdb, item)
357 self.show_info_banner(widget, "Added to portfolio")
359 logger.exception("Adding to portfolio")
360 self.show_info_banner(widget, "Error adding to portfolio")
363 def create_selector(self, data, entry):
365 selector = hildon.TouchSelectorEntry(text=True)
367 selector = hildon.TouchSelector(text=True)
368 for i in range(len(data)):
369 selector.append_text(data[i])
373 def show_data(self, symbol, widgets, shares):
375 winprogind(widgets[0], 1)
376 thread.start_new_thread(self.get_data, (symbol, widgets, shares))
378 def get_data(self, symbol, widgets, shares):
379 from ystockquote import ystockquote as yt
380 win, ltitle, lprice, lchange, lpercent, lvolume, l52whigh, l52wlow, lshares, holdingsvalue, dayvaluechange = widgets
383 data = yt.get_all(symbol)
385 logger.exception("Getting data from Yahoo")
386 data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A',
387 '52_week_high': 'N/A', '52_week_low': 'N/A'}
388 ltitle.set_markup('<b><big>Failed to get data</big></b>')
392 100.0 * float(data['change'])/(float(data['price']) - \
393 float(data['change']))
397 lprice.set_label(data['price'])
398 lchange.set_label(data['change'])
399 lpercent.set_label('%6.2f %%' % ch_percent)
401 if '-' in data['change']:
402 color = gtk.gdk.color_parse("#FF0000")
404 color = gtk.gdk.color_parse("#16EB78")
406 lpercent.modify_fg(gtk.STATE_NORMAL, color)
407 lchange.modify_fg(gtk.STATE_NORMAL, color)
409 lvolume.set_label(data['volume'])
410 l52whigh.set_label(data['52_week_high'])
411 l52wlow.set_label(data['52_week_low'])
414 daychange = float(shares)*float(data['change'])
418 holdvalue = float(shares)*float(data['price'])
422 dayvaluechange.set_label(str(daychange))
423 holdingsvalue.set_label(str(holdvalue))
427 def refresh_stock_data(self, widget, portfolio, widgets, symbol):
429 shares = self.get_shares_from_symbol(symbol)
433 self.show_data(symbol, widgets, shares)
435 def show_graph_view(self, widget, symbol, name):
436 win = hildon.StackableWindow()
437 self.create_menu(win)
438 win.set_title("StockThis - Graph View - " + name)
441 toolbar = self.main_toolbar(False, True, None, '', '')
443 self.graphs_title = gtk.Label(name)
444 color = gtk.gdk.color_parse("#03A5FF")
445 self.graphs_title.modify_fg(gtk.STATE_NORMAL, color)
447 parea = hildon.PannableArea()
450 hbox.set_homogeneous(True)
452 button = hildon.Button(fhsize, horbtn)
453 button.set_label('1d')
454 button.connect("clicked", self.show_graph, '1d', win, symbol)
455 hbox.pack_start(button)
457 button = hildon.Button(fhsize, horbtn)
458 button.set_label('5d')
459 button.connect("clicked", self.show_graph, '5d', win, symbol)
460 hbox.pack_start(button)
462 button = hildon.Button(fhsize, horbtn)
463 button.set_label('3m')
464 button.connect("clicked", self.show_graph, '3m', win, symbol)
465 hbox.pack_start(button)
467 button = hildon.Button(fhsize, horbtn)
468 button.set_label('6m')
469 button.connect("clicked", self.show_graph, '6m', win, symbol)
470 hbox.pack_start(button)
472 button = hildon.Button(fhsize, horbtn)
473 button.set_label('1y')
474 button.connect("clicked", self.show_graph, '1y', win, symbol)
475 hbox.pack_start(button)
477 button = hildon.Button(fhsize, horbtn)
478 button.set_label('2y')
479 button.connect("clicked", self.show_graph, '2y', win, symbol)
480 hbox.pack_start(button)
482 button = hildon.Button(fhsize, horbtn)
483 button.set_label('5y')
484 button.connect("clicked", self.show_graph, '5y', win, symbol)
485 hbox.pack_start(button)
487 button = hildon.Button(fhsize, horbtn)
488 button.set_label('Max')
489 button.connect("clicked", self.show_graph, 'max', win, symbol)
490 hbox.pack_start(button)
493 vbox1.pack_start(hbox, False, False, 0)
495 self.graph = gtk.Image()
496 vbox1.pack_start(self.graph, True, True, 0)
498 parea.add_with_viewport(vbox1)
500 vbox.pack_start(self.graphs_title, False, False, 0)
501 vbox.pack_start(gtk.HSeparator(), False, False, 0)
502 vbox.pack_start(parea, True, True, 0)
503 vbox.pack_start(gtk.HSeparator(), False, False, 5)
504 vbox.pack_start(toolbar, False, False, 0)
509 self.show_graph(None, '1d', win, symbol)
511 def show_graph(self, widget, option, win, symbol):
514 thread.start_new_thread(self.get_graph_data, (option, win, symbol))
516 def get_graph_data(self, option, win, symbol):
518 url = 'http://uk.ichart.yahoo.com/b?s=%s' % symbol
520 url = 'http://uk.ichart.yahoo.com/w?s=%s' % symbol
522 url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % symbol.lower()
524 url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % symbol.lower()
526 url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % symbol.lower()
528 url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % symbol.lower()
530 url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % symbol.lower()
531 elif option == 'max':
532 url = 'http://chart.finance.yahoo.com/c/my/s/%s' % symbol.lower()
535 myimg = urllib2.urlopen(url)
536 imgdata = myimg.read()
538 pbl = gtk.gdk.PixbufLoader()
541 pbuf = pbl.get_pixbuf()
543 self.graph.set_from_pixbuf(pbuf)
546 logger.exception("Getting graph data")
548 self.graphs_title.set_label('Failed to get data')
551 def _tv_columns(self, treeview):
552 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
553 column.set_visible(False)
554 treeview.append_column(column)
556 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
557 treeview.append_column(column)
559 def __create_model(self, names, ids):
560 lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
561 for item in range(len(names)):
562 iter = lstore.append()
563 lstore.set(iter, 0, ids[item], 1, names[item])
566 def main_toolbar(self, quotesview, portfolio, widgets, symbol, name):
568 toolbar.set_homogeneous(True)
570 portfolio_btn = hildon.Button(fhsize, horbtn)
571 portfolio_btn.set_title("Portfolio")
572 portfolio_btn.connect("clicked", self.show_portfolio_view)
574 graph_btn = hildon.Button(fhsize, horbtn)
575 graph_btn.set_title("Graph")
576 graph_btn.connect("clicked", self.show_graph_view, symbol, name)
578 refresh_btn = hildon.Button(fhsize, horbtn)
579 refresh_btn.set_title("Refresh")
580 refresh_btn.connect("clicked", self.refresh_stock_data, portfolio,
584 toolbar.pack_start(portfolio_btn)
586 toolbar.pack_start(graph_btn)
587 toolbar.pack_start(refresh_btn)
593 def show_portfolio_view(self, widget):
594 data = settings.load_portfolio(settingsdb)
596 win = hildon.StackableWindow()
597 self.create_menu(win)
598 win.set_title("StockThis - Portfolio")
602 parea = hildon.PannableArea()
603 tv = hildon.GtkTreeView(ui_normal)
604 tv.set_headers_visible(True)
605 self.portfolio_model = self._create_portfolio_model(data)
606 tv.connect("row-activated", self.show_quotes_view, self.portfolio_model, True)
607 tv.set_model(self.portfolio_model)
608 self._tv_portfolio_columns(tv)
612 button = hildon.Button(fhsize, horbtn)
613 button.set_title("Refresh All")
614 button.connect("clicked", self.refresh_portfolio, tv, win)
615 hbox.pack_start(button, True, True, 0)
617 button = hildon.Button(fhsize, horbtn)
618 button.set_title("Add manually")
619 button.connect("clicked", self.add_item_dlg)
620 hbox.pack_start(button, True, True, 0)
622 button = hildon.Button(fhsize, horbtn)
623 button.set_title("Remove")
624 button.connect("clicked", self.remove_item)
625 hbox.pack_start(button, True, True, 0)
627 vbox.pack_start(parea, True, True, 0)
628 vbox.pack_start(hbox, False, False, 0)
632 def add_item_dlg(self, widget):
633 dlg = gtk.Dialog(title='Add to portfolio', parent=None, flags=0)
634 dlg.set_has_separator(False)
636 button1 = hildon.PickerButton(fhsize, horbtn)
637 data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
639 selector = self.create_selector(data, True)
640 button1.set_selector(selector)
641 button1.set_title("Your shares")
642 button1.set_value("0")
643 dlg.vbox.pack_start(button1, False, False, 0)
645 entry1 = hildon.Entry(fhsize)
646 entry1.set_placeholder("Name")
647 dlg.vbox.pack_start(entry1, False, False, 0)
649 entry2 = hildon.Entry(fhsize)
650 entry2.set_placeholder("Yahoo Finance symbol")
651 dlg.vbox.pack_start(entry2, False, False, 0)
653 button = hildon.Button(fhsize, horbtn)
654 button.set_label("Add")
655 button.connect("clicked", self.add_item, dlg, button1, entry1, entry2)
656 dlg.vbox.pack_start(button, False, False, 0)
663 def add_item(self, widget, dlg, button, entry1, entry2):
664 symbol = entry2.get_text()
665 name = entry1.get_text()
666 shares = button.get_value()
668 self.add_to_portfolio(widget, button, symbol, name)
671 niter = self.portfolio_model.append()
672 self.portfolio_model.set(niter, 0, symbol, 1, name, 2, shares, 3, "-")
674 def remove_item(self, widget):
675 win = hildon.StackableWindow()
677 toolbar = hildon.EditToolbar("Choose items to delete", "Delete")
678 win.set_edit_toolbar(toolbar)
681 parea = hildon.PannableArea()
682 tv = hildon.GtkTreeView(ui_edit)
683 selection = tv.get_selection()
684 selection.set_mode(gtk.SELECTION_MULTIPLE)
685 tv.set_model(self.portfolio_model)
686 self._tv_remove_portfolio_columns(tv)
689 toolbar.connect("button-clicked", self.delete_from_portfolio, win, tv,
691 toolbar.connect_object("arrow-clicked", gtk.Window.destroy, win)
693 vbox.pack_start(parea, True, True, 0)
697 def delete_from_portfolio(self, widget, win, tv, selection):
698 if not self.is_treeview_selected(tv):
701 conf = self.show_confirmation(win, "Delete items?")
705 selmodel, selected = selection.get_selected_rows()
706 iters = [selmodel.get_iter(path) for path in selected]
708 symbol = selmodel.get_value(i, 0)
709 settings.delete_item_from_portfolio(settingsdb, symbol)
712 logger.exception("Deleting item from portfolio")
713 self.info_banner(widget, "Error deleting item")
715 def _tv_remove_portfolio_columns(self, treeview):
716 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
717 column.set_visible(False)
718 treeview.append_column(column)
720 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
721 column.set_property("expand", True)
722 treeview.append_column(column)
724 column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
725 column.set_visible(False)
726 treeview.append_column(column)
728 column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
729 column.set_visible(False)
730 treeview.append_column(column)
732 def refresh_portfolio(self, widget, tv, win):
733 data = settings.load_portfolio(settingsdb)
736 thread.start_new_thread(self._do_refresh_portfolio, (data, tv, win))
738 def _do_refresh_portfolio(self, data, tv, win):
740 item[3] = self.get_price(item[0])
742 self.portfolio_model = self._create_portfolio_model(data)
743 tv.set_model(self.portfolio_model)
746 def get_price(self, symbol):
747 from ystockquote import ystockquote as yt
749 price = yt.get_price(symbol)
752 logger.exception("Getting price from Yahoo")
755 def _create_portfolio_model(self, data):
756 lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
757 gobject.TYPE_STRING, gobject.TYPE_STRING)
759 iter = lstore.append()
760 lstore.set(iter, 0, item[0], 1, item[1], 2, item[2], 3, item[3])
763 def _tv_portfolio_columns(self, treeview):
764 column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
765 column.set_visible(False)
766 treeview.append_column(column)
768 column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1)
769 column.set_property("expand", True)
770 treeview.append_column(column)
772 column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2)
773 treeview.append_column(column)
775 column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
776 treeview.append_column(column)
778 def show_confirmation(self, window, msg):
779 dialog = hildon.hildon_note_new_confirmation(window, msg)
781 result = dialog.run()
782 if result == gtk.RESPONSE_OK:
789 def show_info_banner(self, widget, msg):
790 hildon.hildon_banner_show_information(widget, 'qgn_note_infoprint', msg)
792 def is_treeview_selected(self, treeview):
793 selection = treeview.get_selection()
794 if selection.count_selected_rows() == 0:
795 self.show_info_banner(treeview, 'No selected item')
802 def __init__(self, widget):
803 dialog = gtk.Dialog(title='About', parent=None, flags=0)
804 dialog.set_has_separator(False)
805 dialog.set_size_request(-1, 400)
807 self.info_lb = gtk.Label()
808 self.info_lb.set_line_wrap(True)
814 button = hildon.Button(fhsize, horbtn)
815 button.set_title('Description')
816 button.connect("clicked", self.show_info, 'description')
817 hbox1.pack_start(button, True, True, 0)
819 button = hildon.Button(fhsize, horbtn)
820 button.set_title('Credits')
821 button.connect("clicked", self.show_info, 'credits')
822 hbox1.pack_start(button, True, True, 0)
824 button = hildon.Button(fhsize, horbtn)
825 button.set_title('License')
826 button.connect("clicked", self.show_info, 'license')
827 hbox1.pack_start(button, True, True, 0)
829 button = hildon.Button(fhsize, horbtn)
830 button.set_title('Donate')
831 button.connect("clicked", self.show_info, 'donate')
832 hbox1.pack_start(button, True, True, 0)
834 button = hildon.Button(fhsize, horbtn)
835 button.set_title('Report ')
836 button.connect("clicked", self.show_info, 'report')
837 hbox1.pack_start(button, True, True, 0)
839 button = hildon.Button(fhsize, horbtn)
840 button.set_title(' Rate ')
841 button.connect("clicked", self.show_info, 'vote')
842 hbox1.pack_start(button, True, True, 0)
844 self.action_btn = hildon.Button(fhsize, horbtn)
845 self.image = gtk.Image()
847 self.show_info(None, 'description')
849 dialog.vbox.pack_start(self.action_btn, False, False, 0)
850 dialog.vbox.pack_start(self.image, False, False, 5)
851 dialog.vbox.pack_start(self.info_lb, True, True, 0)
852 dialog.vbox.pack_start(hbox1, False, False, 0)
855 self.action_btn.hide()
860 def do_action(self, widget, action):
862 if action == "donate":
863 url = "http://stockthis.garage.maemo.org/donate.html"
864 elif action == "report":
865 url = "http://stockthis.garage.maemo.org/reporting.html"
866 elif action == "vote":
867 url = "http://maemo.org/downloads/product/stockthis"
868 webbrowser.open_new(url)
870 def show_info(self, widget, kind):
871 if kind == 'license':
872 self.action_btn.hide()
874 info = """<small><b>StockThis</b> is free software. It's using a GPL version 2 license or at your election any later version.
876 Logo by Daniel Martin Yerga.
878 elif kind == 'credits':
879 self.action_btn.hide()
881 info = """<small><b>Written by</b> Daniel Martin Yerga (dyerga@gmail.com)
883 <b>Thanks</b> to everyone who has reported bugs, suggestions, giving spirits, critiques, writing blog articles about StockThis, and so on. Like always the list is extremely big and for not forget anybody, THANKS TO ALL!</small>"""
884 elif kind == 'description':
885 self.action_btn.hide()
887 info = """<b><big>StockThis 0.3</big></b>
889 <i>StockThis is a stocks application for Maemo</i>
892 stockthis.garage.maemo.org"""
894 elif kind == 'donate':
895 self.action_btn.show()
897 self.action_btn.set_title('Make donation')
899 self.action_btn.disconnect(self.id)
900 self.id = self.action_btn.connect("clicked", self.do_action, "donate")
901 info = """<small><b>StockThis</b> is a free (and gratis) software application.
902 Developing good software takes time and hard work.
904 <b>StockThis's author</b> develops the program in his spare time.
905 If you like the program and it's helpful, consider donating a small amount of money.
906 Donations are a great incentive and help the developer feel that the hard work is appreciated.</small>
909 elif kind == 'report':
910 self.action_btn.show()
912 self.action_btn.set_title('Report bug')
914 self.action_btn.disconnect(self.id)
915 self.id = self.action_btn.connect("clicked", self.do_action, "report")
916 info = """<small>StockThis is being improved thanks to bug reports. The author appreciates very much all these reports.
917 If the application is raising an error when you're using it, you have two choices to report this error:
918 1) Send the log from the application menu (if there's an error in the log).
919 2) Write a bug report in the bugtracker of StockThis with as much information as possible (especially the log from the menu).</small>"""
922 self.action_btn.show()
924 self.image.set_from_file(imgdir + "maemoorg.png")
925 self.action_btn.set_title('Rate StockThis')
927 self.action_btn.disconnect(self.id)
928 self.id = self.action_btn.connect("clicked", self.do_action, "vote")
929 info = """<small>The downloads section in maemo.org has a nice system where you can rate applications.
930 If you consider StockThis a good application (or a bad one too), you could rate it in maemo.org site.</small>"""
932 self.info_lb.set_markup(info)
937 def __init__(self, widget, logfile):
939 dialog = gtk.Dialog(title='Log', parent=None)
941 dialog.set_size_request(600, 350)
943 parea = hildon.PannableArea()
944 parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
946 textview = hildon.TextView()
947 textview.set_property("editable", False)
948 textview.set_property("wrap-mode", gtk.WRAP_WORD)
950 log = open(logfile, 'r')
954 textview.get_buffer().set_text(logtext)
957 dialog.vbox.pack_start(parea, True, True, 0)
961 save_btn = hildon.Button(fhsize, horbtn)
962 save_btn.set_title("Save")
963 save_btn.connect('clicked', self.save, logfile, dialog)
965 clear_btn = hildon.Button(fhsize, horbtn)
966 clear_btn.set_title("Clear")
967 clear_btn.connect('clicked', self.clear, textview, logfile)
969 send_btn = hildon.Button(fhsize, horbtn)
970 send_btn.set_title('Send')
971 send_btn.connect('clicked', self.send, dialog, logfile)
973 hbox.pack_start(save_btn, True, True, 0)
974 hbox.pack_start(clear_btn, True, True, 0)
975 hbox.pack_start(send_btn, True, True, 0)
977 dialog.vbox.pack_start(hbox, False, False, 0)
983 def show_filechooser(self, window, title, name, EXT):
984 action = gtk.FILE_CHOOSER_ACTION_SAVE
986 m = hildon.FileSystemModel()
987 file_dialog = hildon.FileChooserDialog(window, action, m)
988 file_dialog.set_title(title)
990 file_dialog.set_current_name(name)
991 HOME = os.path.expanduser("~")
993 if os.path.exists(HOME + '/MyDocs/.documents'):
994 file_dialog.set_current_folder(HOME + '/MyDocs/.documents')
996 file_dialog.set_current_folder(HOME)
998 file_dialog.set_default_response(gtk.RESPONSE_CANCEL)
1000 result = file_dialog.run()
1001 if result == gtk.RESPONSE_OK:
1002 namefile = file_dialog.get_filename()
1003 namefile, extension = os.path.splitext(namefile)
1004 namefile = namefile + "." + EXT
1007 file_dialog.destroy()
1012 def clear(self, widget, textview, logfile):
1013 textview.get_buffer().set_text('')
1014 f = open(logfile, 'w')
1017 def save(self, widget, logfile, dlg):
1019 filename = self.show_filechooser(dlg, "Save log file",
1020 "stockthis-log", "txt")
1026 shutil.copyfile(logfile, filename)
1027 stockspy.show_info_banner(widget, 'Log file saved')
1029 logger.exception("Saving log file")
1030 stockspy.show_info_banner(widget, 'Error saving the log file')
1032 def send(self, widget, dlg, logfile):
1034 hildon.hildon_gtk_window_set_progress_indicator(dlg, 1)
1035 thread.start_new_thread(self._do_send, (dlg, logfile))
1037 def _do_send(self, dlg, logfile):
1038 import pycurl, shutil, random, commands
1041 for i in random.sample('abcdefghijkl123456789', 18):
1044 rnamepath = HOME + "/.stockthis/" + rname
1045 shutil.copyfile(logfile, rnamepath)
1047 gtkversion = "%s.%s.%s" % gtk.ver
1048 if os.path.exists("/etc/maemo_version"):
1049 mfile = open("/etc/maemo_version", 'r')
1050 maemoversion = mfile.read()
1055 opsystem = ' '.join(os.uname())
1056 pyversion = os.sys.version
1058 comm = ("awk '/Private_Dirty/{sum+=$2}END{print sum \"kB\"}'"
1059 " /proc/%s/smaps") % pid
1060 status, dirtymem = commands.getstatusoutput(comm)
1062 lfile = open(rnamepath, 'r')
1067 log = ("%s\nPython version: %s\nGtk version: %s\n"
1068 "Maemo version: %sOperating system: %s\n"
1069 "Dirty Memory: %s\nLog:\n%s") % (_version, pyversion, gtkversion,
1070 maemoversion, opsystem, dirtymem, log)
1072 lfile = open(rnamepath, 'w')
1076 url = "http://yerga.net/logs/uploader.php"
1077 data = [('uploadedfile', (pycurl.FORM_FILE, rnamepath)),]
1078 mycurl = pycurl.Curl()
1079 mycurl.setopt(pycurl.URL, url)
1080 mycurl.setopt(pycurl.HTTPPOST, data)
1084 os.remove(rnamepath)
1086 gtk.gdk.threads_enter()
1087 stockspy.show_info_banner(dlg, 'Log sent')
1088 gtk.gdk.threads_leave()
1089 hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
1091 logger.exception("Sending log file")
1092 gtk.gdk.threads_enter()
1093 stockspy.show_info_banner(dlg, 'Error sending the log file')
1094 gtk.gdk.threads_leave()
1095 hildon.hildon_gtk_window_set_progress_indicator(dlg, 0)
1098 if __name__ == "__main__":
1099 stockspy = StocksPy()
1100 gtk.gdk.threads_enter()
1102 gtk.gdk.threads_leave()