X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=stockthis.py;h=7ca72b4eed8a49b1ec88a3b00367cc6199f0edb1;hb=HEAD;hp=15ec37de86c69c6ff4a85166466c05194ea20197;hpb=6822d626561e0c277a668431941eea0978ab1a97;p=stockthis diff --git a/stockthis.py b/stockthis.py index 15ec37d..7ca72b4 100644 --- a/stockthis.py +++ b/stockthis.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.5 +#!/usr/bin/env python # -*- coding: UTF8 -*- # Copyright (C) 2008 by Daniel Martin Yerga # @@ -16,534 +16,1631 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# StocksPy: Application to get stocks data from Yahoo Finance. -# Version 0.1 +# StocksThis: Application to get stocks data from Yahoo Finance. # +_version = "StockThis 0.4 rev1" +VERSION = "0.4" + import urllib2 import gtk, gobject -try: - import hildon - HILDON = True -except: - HILDON = False - -try: - import osso - OSSO = True - osso_c = osso.Context("net.yerga.stockthis", "0.1", False) -except: - OSSO = False - -from marketdata import markets, idmarket, localmarkets, localids - -#TODO: detect if running in Fremantle -FREMANTLE=True +import os +import hildon +import marketdata +import settings +import logging +import sys + +from portrait import FremantleRotation + +import osso +osso_c = osso.Context("net.yerga.stockthis", "0.3", False) #detect if is ran locally or not -import sys runningpath = sys.path[0] -if '/usr/share' in runningpath: - running_locally = False -else: - running_locally = True - -if running_locally: - imgdir = 'pixmaps/' +if '/opt/' in runningpath: + runninglocally = False else: - imgdir = '/usr/share/stockthis/pixmaps/' + runninglocally = True + +HOME = os.path.expanduser("~") + +settingsdb, imgdir, configdir, logfile = \ + settings.define_paths(runninglocally, HOME) + +logger = logging.getLogger('st') +logging.basicConfig(filename=logfile,level=logging.ERROR, filemode='w') + +DEBUG = True + +if DEBUG: + #set the main logger to DEBUG + logger.setLevel(logging.DEBUG) + + #Create a handler for console debug + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) + # set a format which is simpler for console use + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + # tell the handler to use this format + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + +fhsize = gtk.HILDON_SIZE_FINGER_HEIGHT +horbtn = hildon.BUTTON_ARRANGEMENT_HORIZONTAL +ui_normal = gtk.HILDON_UI_MODE_NORMAL +ui_edit = gtk.HILDON_UI_MODE_EDIT +winprogind = hildon.hildon_gtk_window_set_progress_indicator -loading_img = imgdir + 'loading.gif' +allnames = [] +allsymbols = [] gtk.gdk.threads_init() class StocksPy: def __init__(self): - if HILDON: - self.program = hildon.Program() - self.program.__init__() - gtk.set_application_name('') - if FREMANTLE: - self.window = hildon.StackableWindow() - else: - self.window = hildon.Window() - self.program.add_window(self.window) + self.program = hildon.Program() + self.program.__init__() + gtk.set_application_name("StockThis") + self.window = hildon.StackableWindow() + self.window.set_default_size(800, 480) + self.program.add_window(self.window) + self.window.connect("destroy", gtk.main_quit) + + FremantleRotation('StockThis', None, "0.3", 0) + + self.create_menu(self.window) + + vbox = gtk.VBox() + toolbar = self.main_toolbar(False, False, None, '', '', True) + + parea = hildon.PannableArea() + tv = hildon.GtkTreeView(ui_normal) + inmodel = self.__create_model(marketdata.main, marketdata.idmain) + tv.connect("row-activated", self.show_instrument_view, inmodel, + marketdata.localmarkets, marketdata.localids, + marketdata.idmain) + tv.set_model(inmodel) + self._tv_columns(tv) + parea.add(tv) + + vbox.pack_start(parea, True, True, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 5) + vbox.pack_start(toolbar, False, False, 0) + + self.window.add(vbox) + self.window.show_all() + + self.show_info_banner(self.window, + ("StockThis uses your network connection to get data.\n" + "Be aware of the high costs that your network provider may apply.")) + + def create_menu(self, window): + menu = hildon.AppMenu() + window.set_app_menu(menu) + button = gtk.Button("About") + button.connect("clicked", About) + menu.append(button) + menu.show_all() + + def show_instrument_view(self, widget, path, column, inmodel, names, + ids, mindex): + market = inmodel[path][0] + names = names[mindex.index(market)] + ids = ids[mindex.index(market)] + + window = hildon.StackableWindow() + self.create_menu(window) + window.set_title(inmodel[path][1]) + + vbox = gtk.VBox() + toolbar = self.main_toolbar(False, False, None, '', '', False) + + parea = hildon.PannableArea() + parea.connect("horizontal-movement", self.horizontal_mov) + tv = hildon.GtkTreeView(ui_normal) + model = self.__create_model(names, ids) + + if market == 'metals': + tv.connect("row-activated", self.show_metal_graphs, model) else: - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + tv.connect("row-activated", self.show_quotes_view, model, False) - self.window.set_default_size(800, 480) - self.window.set_title('StocksPy') - self.window.connect("destroy", gtk.main_quit) - self.window.connect("key-press-event", self.on_key_press) - self.window.connect("window-state-event", self.on_window_state_change) - self.window_in_fullscreen = False - - if HILDON: - if FREMANTLE: - menu = hildon.AppMenu() - self.window.set_main_menu(menu) - about_menu = gtk.Button("About") + tv.set_model(model) + self._tv_columns(tv) + parea.add(tv) + + vbox.pack_start(parea, True, True, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 5) + vbox.pack_start(toolbar, False, False, 0) + + window.add(vbox) + window.show_all() + + def horizontal_mov(self, parea, direction, initial_x, initial_y): + #direction = 2 right-to-left + #direction = 3 lefto-to-right + + vadj = parea.get_vadjustment() + val = vadj.get_value() + + if direction == 2: + if int(val)-2500 < 0: + parea.scroll_to(-1, 0) else: - menu = gtk.Menu() - self.window.set_menu(menu) - about_menu = gtk.MenuItem("About") - about_menu.set_size_request(-1, 55) - - about_menu.connect("activate", self.on_about) - menu.append(about_menu) - menu.show_all() - else: - #TODO: create a gtk.menubar - pass - - + parea.scroll_to(-1, int(val)-2500) + elif direction == 3: + parea.scroll_to(-1, int(val)+3500) + + #print val + + def show_quotes_view(self, widget, path, column, model, portfolio): + quote = model[path][0], model[path][1] + #print "quote:", quote[0] + #('EURUSD=X', 'EUR/USD') + + #Currencies and ETFs should show the list now -> view = True + #Other items show a new list with options + view = False + for i in marketdata.localids[(len(marketdata.localids)-2):]: + for j in i: + if quote[0] == j: + #print j + view = True + + if not view: + if quote[0] in marketdata.idindexes: + self.show_instrument_view(widget, path, column, model, + marketdata.wnamesindexes, + marketdata.widsindexes, + marketdata.idindexes) + return + if quote[0] in marketdata.idotmarkets: + self.show_instrument_view(widget, path, column, model, + marketdata.omnames, + marketdata.omsymbols, + marketdata.idotmarkets) + return + if quote[0] in marketdata.ideumarkets: + self.show_instrument_view(widget, path, column, model, + marketdata.eunames, + marketdata.eusymbols, + marketdata.ideumarkets) + return + if quote[0] in marketdata.idusmarkets: + self.show_instrument_view(widget, path, column, model, + marketdata.usnames, + marketdata.ussymbols, + marketdata.idusmarkets) + return + + + win = hildon.StackableWindow() + self.create_menu(win) + win.set_title(quote[1]) + vbox = gtk.VBox() - - self.toolbar = gtk.HBox() - self.toolbar.set_property("no-show-all", True) - self.toolbar.hide() - self.toolbar.set_homogeneous(True) - self.toolbar.set_size_request(-1, 55) - - self.markets_btn = gtk.Button('Markets') - self.markets_btn.connect("clicked", self.create_markets_view) - self.markets_btn.set_property("can_focus", False) - - self.components_btn = gtk.Button('Components') - self.components_btn.connect("clicked", self.show_components_view) - self.components_btn.set_property("can_focus", False) - - self.graph_btn = gtk.Button('Graphs') - self.graph_btn.connect("clicked", self.create_graphs_view) - self.graph_btn.set_property("can_focus", False) - - self.refresh_btn = gtk.Button('Refresh') - self.refresh_btn.connect("clicked", self.refresh_stock_data) - self.refresh_btn.set_property("can_focus", False) - - self.quotes_btn = gtk.Button('Quotes') - self.quotes_btn.connect("clicked", self.show_quotes_view) - self.quotes_btn.set_property("can_focus", False) - - self.toolbar.pack_start(self.markets_btn) - self.toolbar.pack_start(self.components_btn) - self.toolbar.pack_start(self.graph_btn) - self.toolbar.pack_start(self.quotes_btn) - self.toolbar.pack_start(self.refresh_btn) - - self.mainbox = gtk.VBox() - - - if FREMANTLE: - self.swin = hildon.PannableArea() + + ltitle = gtk.Label('') + ltitle.set_markup('' + quote[1].replace('&', '') + + '') + color = gtk.gdk.color_parse("#03A5FF") + ltitle.modify_fg(gtk.STATE_NORMAL, color) + + parea = hildon.PannableArea() + parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH) + + vbox1 = gtk.VBox() + + hbox = gtk.HBox() + label = gtk.Label('') + label.set_markup('%39s:' % 'Price') + lprice = gtk.Label('') + hbox.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox.pack_start(lprice, False, False, 25) + #else: + # hbox.pack_start(lprice, False, False, 245) + + vbox1.pack_start(hbox, True, True, 0) + + hbox = gtk.HBox() + label = gtk.Label('') + label.set_markup('%35s:' % 'Change') + lchange = gtk.Label('') + lpercent = gtk.Label('') + hbox.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox.pack_start(lchange, False, False, 25) + hbox.pack_start(lpercent, False, False, 0) + #else: + # hbox.pack_start(lchange, False, False, 205) + # hbox.pack_start(lpercent, False, False, 0) + + vbox1.pack_start(hbox, True, True, 0) + + hbox = gtk.HBox() + label = gtk.Label('') + label.set_markup('%35s:' % 'Volume') + lvolume = gtk.Label('') + hbox.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox.pack_start(lvolume, False, False, 25) + #else: + # hbox.pack_start(lvolume, False, False, 207) + + vbox1.pack_start(hbox, True, True, 0) + + hbox = gtk.HBox() + label = gtk.Label('') + label.set_markup('%30s:' % '52 week high') + l52whigh = gtk.Label('') + hbox.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox.pack_start(l52whigh, False, False, 25) + #else: + # hbox.pack_start(l52whigh, False, False, 125) + + vbox1.pack_start(hbox, True, True, 0) + + hbox = gtk.HBox() + label = gtk.Label('') + label.set_markup('%30s:' % '52 week low') + l52wlow = gtk.Label('') + hbox.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox.pack_start(l52wlow, False, False, 26) + #else: + # hbox.pack_start(l52wlow, False, False, 140) + vbox1.pack_start(hbox, True, True, 0) + + #if self.is_portrait(): + # hbox = gtk.VBox() + #else: + hbox = gtk.HBox() + button1 = hildon.PickerButton(fhsize, horbtn) + data = ["50", "100", "200", "300", "400", "500", "600", "700", "800", + "900", "1000"] + selector = self.create_selector(data, True) + button1.set_selector(selector) + button1.set_title("Your shares") + shares = self.get_shares_from_symbol(quote[0]) + button1.set_value(shares) + hbox.pack_start(button1, True, True, 0) + + button = hildon.Button(fhsize, horbtn) + button.set_title("Add to Portfolio") + button.connect("clicked", self.add_to_portfolio, button1, quote[0], quote[1]) + hbox.pack_start(button, True, True, 0) + + hbox1 = gtk.HBox() + label = gtk.Label('') + label.set_markup('%37s:' % 'Shares') + lshares = gtk.Label(shares) + hbox1.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox1.pack_start(lshares, False, False, 25) + #else: + # hbox1.pack_start(lshares, False, False, 220) + + hbox2 = gtk.HBox() + label = gtk.Label('') + label.set_markup('%29s:' % 'Holdings Value') + holdingsvalue = gtk.Label("") + hbox2.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox2.pack_start(holdingsvalue, False, False, 25) + #else: + # hbox2.pack_start(holdingsvalue, False, False, 105) + + hbox3 = gtk.HBox() + label = gtk.Label('') + label.set_markup("%25s:" % "Day's Value Change") + dayvaluechange = gtk.Label("") + hbox3.pack_start(label, False, False, 0) + #if self.is_portrait(): + hbox3.pack_start(dayvaluechange, False, False, 25) + #else: + # hbox3.pack_start(dayvaluechange, False, False, 45) + + if not portfolio: + vbox1.pack_start(hbox, False, False, 0) else: - self.swin = gtk.ScrolledWindow() - if HILDON: - hildon.hildon_helper_set_thumb_scrollbar(self.swin, True) - self.swin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - self.swin.add_with_viewport(self.mainbox) + vbox1.pack_start(hbox1, True, True, 0) + vbox1.pack_start(hbox2, True, True, 0) + vbox1.pack_start(hbox3, True, True, 0) + + parea.add_with_viewport(vbox1) + + widgets = [win, ltitle, lprice, lchange, lpercent, lvolume, l52whigh, + l52wlow, lshares, holdingsvalue, dayvaluechange] - vbox.pack_start(self.swin, True, True, 0) + toolbar = self.main_toolbar(True, portfolio, widgets, quote[0], quote[1], False) + + vbox.pack_start(ltitle, False, False, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 0) + vbox.pack_start(parea, True, True, 0) vbox.pack_start(gtk.HSeparator(), False, False, 5) - vbox.pack_start(self.toolbar, False, False, 0) + vbox.pack_start(toolbar, False, False, 0) - self.create_markets_view(self.mainbox) - self.window.add(vbox) - self.window.show_all() + win.add(vbox) + win.show_all() + self.show_data(quote[0], widgets, shares) - def create_markets_view(self, widget): - names = markets - ids = idmarket - self.toolbar.hide() - - actual_view = self.mainbox.get_children() - if len(actual_view) > 0: - for a_widget in actual_view: - a_widget.destroy() - - self.marketsbox = gtk.VBox() - lnames = len(names) - - for i in range(lnames): - button = gtk.Button(names[i]) - button.connect("clicked", self.create_components_view, ids[i]) - button.set_size_request(-1, 65) - button.set_property("can_focus", False) - self.marketsbox.pack_start(button, True, True, 2) - - self.mainbox.pack_start(self.marketsbox, True, True, 2) - self.mainbox.show_all() - - def show_components_view(self, widget): - kind = self.market_id - self.create_components_view(widget, kind) - - def create_components_view(self, widget, kind): - actual_view = self.mainbox.get_children() - for i in actual_view: - i.destroy() - - self.market_id = kind - self.toolbar.show() - self.components_btn.hide() - self.markets_btn.show() - self.refresh_btn.hide() - self.graph_btn.hide() - self.quotes_btn.hide() - - names = localmarkets[idmarket.index(kind)] - ids = localids[idmarket.index(kind)] - - self.compbox = gtk.VBox() - - self.components_trv = gtk.TreeView() - - if not FREMANTLE: - selection = self.components_trv.get_selection() - selection.connect("changed", self.changed_selection, ids) + def is_portrait(self): + width = gtk.gdk.screen_width() + height = gtk.gdk.screen_height() + if width > height: + return False else: - self.components_trv.connect("row-activated", self.select_component, ids) - - self.components_trv.set_rubber_banding(True) - self.components_trv.set_headers_visible(False) - self.components_model = self.__create_components_model() - self.components_trv.set_model(self.components_model) - self._components_trv_columns(self.components_trv) - self.add_initial_components(names, ids) - - self.compbox.pack_start(self.components_trv, True, True, 0) - - self.mainbox.pack_start(self.compbox, True, True, 0) - self.mainbox.show_all() - - def select_component(self, widget, path, column, ids): - self.create_quotes_view(widget,self.components_model[path][1] ) - - def changed_selection(self, widget, ids): - n, i, m = self.get_selected_from_treeview(self.components_trv, self.components_model, 1) - if n is not None: - self.create_quotes_view(widget, n) - - def __create_components_model(self): - lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) - return lstore + return True - def _components_trv_columns(self, treeview): - renderer = gtk.CellRendererText() - renderer.set_property('scale', 1.6) - #renderer.set_property("background", 'lightgray') - renderer.set_property("xpad", 15) - column = gtk.TreeViewColumn('Name', renderer, text=0) - column.set_expand(True) - treeview.append_column(column) - - renderer = gtk.CellRendererText() - column = gtk.TreeViewColumn('IDS', renderer, text=1) - column.set_visible(False) - treeview.append_column(column) - - def add_initial_components(self, kind, ids): - for i in range(len(kind)): - niter = self.components_model.append() - self.components_model.set(niter, 0, kind[i], 1, ids[i]) - - def get_selected_from_treeview(self, treeview, model, setting): - selection = treeview.get_selection() - selected_model, selected_iter = selection.get_selected() - if selected_iter: - selected_name = model.get_value(selected_iter, setting) - else: - selected_name = None - return selected_name, selected_iter, selected_model - - def show_quotes_view(self, widget): - kind = self.stocks_id - self.create_quotes_view(widget, kind) - - def create_quotes_view(self, widget, kind): - self.stocks_id = kind - self.toolbar.show() - self.components_btn.show() - self.markets_btn.show() - self.refresh_btn.show() - self.graph_btn.show() - self.quotes_btn.hide() - - #actual_view = self.mainbox.get_children() - #actual_view[0].destroy() - + def get_shares_from_symbol(self, symbol): + shares = "0" try: - self.graphbox.destroy() + portfolio_data = settings.load_portfolio(settingsdb) + for item in portfolio_data : + if symbol in item: + shares = item[2] + return shares except: - pass - - for i in range(len(localids)): - if kind in localids[i]: - ind1, ind2 = i, localids[i].index(kind) - - self.quotesbox = gtk.VBox() - - label1 = gtk.Label('') - label1.set_markup(''+localmarkets[ind1][ind2]+'') - color = gtk.gdk.color_parse("#03A5FF") - label1.modify_fg(gtk.STATE_NORMAL, color) - - self.databox = gtk.VBox() - - self.imagebox = gtk.VBox() - self.dataimg = gtk.Image() - self.imagebox.pack_start(self.dataimg) - - self.show_data(kind) - - hbox1 = gtk.HBox() - - label2 = gtk.Label('') - label2.set_markup('Price:') - self.lprice = gtk.Label('') - - hbox1.pack_start(label2, False, False, 50) - hbox1.pack_start(self.lprice, False, False, 185) - - hbox2 = gtk.HBox() + logger.exception("Getting shares from symbol: %s" % symbol) + return shares - label4 = gtk.Label('') - label4.set_markup('Change:') - self.lchange = gtk.Label('') - self.lpercent = gtk.Label('') - - hbox2.pack_start(label4, False, False, 50) - hbox2.pack_start(self.lchange , False, False, 145) - hbox2.pack_start(self.lpercent, False, False, 0) - - hbox3 = gtk.HBox() - - label7 = gtk.Label('') - label7.set_markup('Volume:') - self.lvolume = gtk.Label('') - - hbox3.pack_start(label7, False, False, 50) - hbox3.pack_start(self.lvolume , False, False, 145) - - hbox4 = gtk.HBox() - - label9 = gtk.Label('') - label9.set_markup('52 week high:') - self.l52whigh = gtk.Label('') - - hbox4.pack_start(label9, False, False, 50) - hbox4.pack_start(self.l52whigh , False, False, 55) - - hbox5 = gtk.HBox() - - label11 = gtk.Label('') - label11.set_markup('52 week low:') - self.l52wlow = gtk.Label('') - - hbox5.pack_start(label11, False, False, 50) - hbox5.pack_start(self.l52wlow , False, False, 70) - - self.databox.pack_start(hbox1, True, True, 0) - self.databox.pack_start(hbox2, True, True, 0) - self.databox.pack_start(hbox3, True, True, 0) - self.databox.pack_start(hbox4, True, True, 0) - self.databox.pack_start(hbox5, True, True, 0) - - self.quotesbox.pack_start(label1, False, False, 0) - self.quotesbox.pack_start(gtk.HSeparator(), False, False, 0) - self.quotesbox.pack_start(self.databox, True, True, 0) - self.quotesbox.pack_start(self.imagebox, True, True, 0) - - self.mainbox.pack_start(self.quotesbox, True, True, 0) - self.mainbox.show_all() - self.compbox.hide() - self.databox.hide() - - def show_data(self, kind): + def add_to_portfolio(self, widget, button, symbol, name): + shares = button.get_value() + + try: + portfolio = settings.load_portfolio(settingsdb) + index = "None" + for item in portfolio: + if symbol in item: + index = portfolio.index(item) + + item = [symbol, name, shares, '-'] + + if index is "None": + settings.insert_new_item_to_portfolio(settingsdb, item) + else: + settings.delete_item_from_portfolio(settingsdb, symbol) + settings.insert_new_item_to_portfolio(settingsdb, item) + + self.show_info_banner(widget, "Added to portfolio") + except: + logger.exception("Adding to portfolio: %s, %s" % (symbol, name)) + self.show_info_banner(widget, "Error adding to portfolio") + + + def create_selector(self, data, entry): + if entry: + selector = hildon.TouchSelectorEntry(text=True) + else: + selector = hildon.TouchSelector(text=True) + for i in range(len(data)): + selector.append_text(data[i]) + + return selector + + def show_data(self, symbol, widgets, shares): import thread - self.dataimg.set_from_file(loading_img) - self.imagebox.show() - self.databox.hide() - thread.start_new_thread(self.get_data, (kind,)) - - def get_data(self, kind): - self.graph_btn.show() - self.refresh_btn.show() - self.quotes_btn.hide() - + winprogind(widgets[0], 1) + thread.start_new_thread(self.get_data, (symbol, widgets, shares)) + + def get_data(self, symbol, widgets, shares): from ystockquote import ystockquote as yt - data = yt.get_all(kind) - + win, ltitle, lprice, lchange, lpercent, lvolume, l52whigh, l52wlow, lshares, holdingsvalue, dayvaluechange = widgets + + try: + data = yt.get_all(symbol) + except: + logger.exception("Getting data from Yahoo: %s" % symbol) + data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A', + '52_week_high': 'N/A', '52_week_low': 'N/A'} + ltitle.set_markup('Failed to get data') + try: - ch_percent = 100.0 * float(data['change'])/float(data['price']) + ch_percent = \ + 100.0 * float(data['change'])/(float(data['price']) - \ + float(data['change'])) except ValueError: ch_percent = 0.0 - self.lprice.set_label(data['price']) - self.lchange.set_label(data['change']) - self.lpercent.set_label('%6.2f %%' % ch_percent) - + lprice.set_label(data['price']) + lchange.set_label(data['change']) + lpercent.set_label('%6.2f %%' % ch_percent) + if '-' in data['change']: color = gtk.gdk.color_parse("#FF0000") else: - color = gtk.gdk.color_parse("#16EB78") - - self.lpercent.modify_fg(gtk.STATE_NORMAL, color) - self.lchange.modify_fg(gtk.STATE_NORMAL, color) - - self.lvolume.set_label(data['volume']) - self.l52whigh.set_label(data['52_week_high']) - self.l52wlow.set_label(data['52_week_low']) - - self.databox.show_all() - self.imagebox.hide() - - def refresh_stock_data(self, widget): - self.show_data(self.stocks_id) - - def create_graphs_view(self, widget): - self.graph_btn.hide() - self.refresh_btn.hide() - self.quotes_btn.show() - - self.graph = gtk.Image() - - kind = self.stocks_id - - self.show_graph(None, '1d', kind) - - for i in range(len(localids)): - if kind in localids[i]: - ind1, ind2 = i, localids[i].index(kind) - - #self.mainbox.destroy() - #self.mainbox = gtk.VBox() - #self.swin.add_with_viewport(self.mainbox) - - actual_view = self.mainbox.get_children() - for a_widget in actual_view: - a_widget.destroy() - - self.graphbox = gtk.VBox() - - label1 = gtk.Label(localmarkets[ind1][ind2]) + color = gtk.gdk.color_parse("#16EB78") + + lpercent.modify_fg(gtk.STATE_NORMAL, color) + lchange.modify_fg(gtk.STATE_NORMAL, color) + + lvolume.set_label(data['volume']) + l52whigh.set_label(data['52_week_high']) + l52wlow.set_label(data['52_week_low']) + + try: + daychange = float(shares)*float(data['change']) + except ValueError: + daychange = 'N/A' + try: + holdvalue = float(shares)*float(data['price']) + except ValueError: + holdvalue = 'N/A' + + dayvaluechange.set_label(str(daychange)) + holdingsvalue.set_label(str(holdvalue)) + + winprogind(win, 0) + + def refresh_stock_data(self, widget, portfolio, widgets, symbol): + if portfolio: + shares = self.get_shares_from_symbol(symbol) + else: + shares = "0" + + self.show_data(symbol, widgets, shares) + + def show_graph_view(self, widget, symbol, name): + win = hildon.StackableWindow() + self.create_menu(win) + win.set_title(name) + + vbox = gtk.VBox() + toolbar = self.main_toolbar(False, True, None, '', '', False) + + self.graphs_title = gtk.Label(name) color = gtk.gdk.color_parse("#03A5FF") - label1.modify_fg(gtk.STATE_NORMAL, color) - - hbox1 = gtk.HBox() - hbox1.set_size_request(-1, 55) - hbox1.set_homogeneous(True) - - self.btn1d = gtk.Button('1d') - self.btn1d.set_property("can_focus", False) - self.btn1d.connect("clicked", self.show_graph, '1d', kind) - self.btn5d = gtk.Button('5d') - self.btn5d.set_property("can_focus", False) - self.btn5d.connect("clicked", self.show_graph, '5d', kind) - self.btn3m = gtk.Button('3m') - self.btn3m.set_property("can_focus", False) - self.btn3m.connect("clicked", self.show_graph, '3m', kind) - self.btn6m = gtk.Button('6m') - self.btn6m.set_property("can_focus", False) - self.btn6m.connect("clicked", self.show_graph, '6m', kind) - self.btn1y = gtk.Button('1y') - self.btn1y.set_property("can_focus", False) - self.btn1y.connect("clicked", self.show_graph, '1y', kind) - self.btn2y = gtk.Button('2y') - self.btn2y.set_property("can_focus", False) - self.btn2y.connect("clicked", self.show_graph, '2y', kind) - self.btn5y = gtk.Button('5y') - self.btn5y.set_property("can_focus", False) - self.btn5y.connect("clicked", self.show_graph, '5y', kind) - self.btnmax = gtk.Button('max') - self.btnmax.set_property("can_focus", False) - self.btnmax.connect("clicked", self.show_graph, 'max', kind) - - hbox1.pack_start(self.btn1d) - hbox1.pack_start(self.btn5d) - hbox1.pack_start(self.btn3m) - hbox1.pack_start(self.btn6m) - hbox1.pack_start(self.btn1y) - hbox1.pack_start(self.btn2y) - hbox1.pack_start(self.btn5y) - hbox1.pack_start(self.btnmax) - - self.graphbox.pack_start(label1, False, False, 2) - self.graphbox.pack_start(hbox1, False, False, 0) - self.graphbox.pack_start(self.graph, True, True, 5) - - self.mainbox.pack_start(self.graphbox, False, False, 2) - self.mainbox.show_all() - - def show_graph(self, widget, option, kind): + self.graphs_title.modify_fg(gtk.STATE_NORMAL, color) + + parea = hildon.PannableArea() + parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH) + + vbox1 = gtk.VBox() + + hbox = gtk.HBox() + hbox.set_homogeneous(True) + + button = hildon.Button(fhsize, horbtn) + button.set_label('1d') + button.connect("clicked", self.show_graph, '1d', win, symbol) + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('5d') + button.connect("clicked", self.show_graph, '5d', win, symbol) + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('3m') + button.connect("clicked", self.show_graph, '3m', win, symbol) + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('6m') + button.connect("clicked", self.show_graph, '6m', win, symbol) + hbox.pack_start(button) + + vbox1.pack_start(hbox, False, False, 0) + hbox = gtk.HBox() + hbox.set_homogeneous(True) + + button = hildon.Button(fhsize, horbtn) + button.set_label('1y') + button.connect("clicked", self.show_graph, '1y', win, symbol) + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('2y') + button.connect("clicked", self.show_graph, '2y', win, symbol) + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('5y') + button.connect("clicked", self.show_graph, '5y', win, symbol) + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('Max') + button.connect("clicked", self.show_graph, 'max', win, symbol) + hbox.pack_start(button) + + vbox1.pack_start(hbox, False, False, 0) + + self.graph = gtk.Image() + vbox1.pack_start(self.graph, True, True, 0) + + parea.add_with_viewport(vbox1) + + vbox.pack_start(self.graphs_title, False, False, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 0) + vbox.pack_start(parea, True, True, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 5) + vbox.pack_start(toolbar, False, False, 0) + + win.add(vbox) + win.show_all() + + self.show_graph(None, '1d', win, symbol) + + def show_graph(self, widget, option, win, symbol): import thread - self.graph.set_from_file(loading_img) - thread.start_new_thread(self.get_graph_data, (option, kind)) + winprogind(win, 1) + thread.start_new_thread(self.get_graph_data, (option, win, symbol)) - def get_graph_data(self, option, kind): + def get_graph_data(self, option, win, symbol): if option == '1d': - url = 'http://uk.ichart.yahoo.com/b?s=%s' % kind - elif option == '5d': - url = 'http://uk.ichart.yahoo.com/w?s=%s' % kind - elif option == '3m': - url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % kind.lower() - elif option == '6m': - url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % kind.lower() - elif option == '1y': - url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % kind.lower() - elif option == '2y': - url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % kind.lower() - elif option == '5y': - url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % kind.lower() - elif option == 'max': - url = 'http://chart.finance.yahoo.com/c/my/s/%s' % kind.lower() - - myimg = urllib2.urlopen(url) - imgdata=myimg.read() - - pbl = gtk.gdk.PixbufLoader() - pbl.write(imgdata) - - pbuf = pbl.get_pixbuf() - pbl.close() - - self.graph.set_from_pixbuf(pbuf) - - #Functions for fullscreen - def on_window_state_change(self, widget, event, *args): - if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: - self.window_in_fullscreen = True + url = 'http://uk.ichart.yahoo.com/b?s=%s' % symbol + elif option == '5d': + url = 'http://uk.ichart.yahoo.com/w?s=%s' % symbol + elif option == '3m': + url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % symbol.lower() + elif option == '6m': + url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % symbol.lower() + elif option == '1y': + url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % symbol.lower() + elif option == '2y': + url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % symbol.lower() + elif option == '5y': + url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % symbol.lower() + elif option == 'max': + url = 'http://chart.finance.yahoo.com/c/my/s/%s' % symbol.lower() + + try: + myimg = urllib2.urlopen(url) + imgdata = myimg.read() + + pbl = gtk.gdk.PixbufLoader() + pbl.write(imgdata) + + pbuf = pbl.get_pixbuf() + pbuf = pbuf.scale_simple(475, 235, gtk.gdk.INTERP_TILES) + pbl.close() + self.graph.set_from_pixbuf(pbuf) + winprogind(win, 0) + except: + logger.exception("Getting graph data: %s" % url) + winprogind(win, 0) + self.graphs_title.set_label('Failed to get data') + self.graph.destroy() + + def show_metal_graphs(self, widget, path, column, model): + metal = model[path][1] + metal_urls = self.get_metal_graphs_urls(metal) + options = [] + for i in metal_urls: + options.append(i[0]) + + win = hildon.StackableWindow() + #self.create_menu(win) + win.set_title(metal) + + vbox = gtk.VBox() + #toolbar = self.main_toolbar(False, True, None, '', '', False) + + self.metalgraph_title = gtk.Label(metal) + color = gtk.gdk.color_parse("#03A5FF") + self.metalgraph_title.modify_fg(gtk.STATE_NORMAL, color) + + parea = hildon.PannableArea() + parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH) + + vbox1 = gtk.VBox() + + hbox = gtk.HBox() + hbox.set_homogeneous(True) + + button = hildon.Button(fhsize, horbtn) + button.set_label('live') + button.connect("clicked", self.show_metalgraph, 'live', win, metal_urls) + if 'live' in options: + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('30d') + button.connect("clicked", self.show_metalgraph, '30d', win, metal_urls) + if '30d' in options: + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('60d') + button.connect("clicked", self.show_metalgraph, '60d', win, metal_urls) + if '60d' in options: + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('6m') + button.connect("clicked", self.show_metalgraph, '6m', win, metal_urls) + if '6m' in options: + hbox.pack_start(button) + + vbox1.pack_start(hbox, False, False, 0) + hbox = gtk.HBox() + hbox.set_homogeneous(True) + + button = hildon.Button(fhsize, horbtn) + button.set_label('1y') + button.connect("clicked", self.show_metalgraph, '1y', win, metal_urls) + if '1y' in options: + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('5y') + button.connect("clicked", self.show_metalgraph, '5y', win, metal_urls) + if '5y' in options: + hbox.pack_start(button) + + button = hildon.Button(fhsize, horbtn) + button.set_label('10y') + button.connect("clicked", self.show_metalgraph, '10y', win, metal_urls) + if '10y' in options: + hbox.pack_start(button) + + vbox1.pack_start(hbox, False, False, 0) + + self.metalgraph = gtk.Image() + vbox1.pack_start(self.metalgraph, True, True, 0) + + parea.add_with_viewport(vbox1) + + vbox.pack_start(self.metalgraph_title, False, False, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 0) + vbox.pack_start(parea, True, True, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 5) + #vbox.pack_start(toolbar, False, False, 0) + + win.add(vbox) + win.show_all() + + self.show_metalgraph(None, options[0], win, metal_urls) + + def show_metalgraph(self, widget, option, win, metal_urls): + import thread + winprogind(win, 1) + thread.start_new_thread(self.get_metalgraph_data, (option, win, metal_urls)) + + def get_metalgraph_data(self, option, win, metal_urls): + for i in metal_urls: + if i[0] == option: + print i[1] + url = i[1] + + try: + myimg = urllib2.urlopen(url) + imgdata = myimg.read() + + pbl = gtk.gdk.PixbufLoader() + pbl.write(imgdata) + + + pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, 475, 235) + pixbuf.fill(0xffffffff) + + + pbuf = pbl.get_pixbuf() + pbuf = pbuf.scale_simple(475, 235, gtk.gdk.INTERP_TILES) + + pixbuf.composite(pbuf, 0, 0, pixbuf.props.width, pixbuf.props.height, 0, 0, 1.0, 1.0, gtk.gdk.INTERP_HYPER, 55) + + + pbl.close() + self.metalgraph.set_from_pixbuf(pbuf) + winprogind(win, 0) + except: + logger.exception("Getting graph data: %s" % url) + winprogind(win, 0) + self.metalgraph_title.set_label('Failed to get data') + self.metalgraph.destroy() + + def get_metal_graphs_urls(self, metal): + metal_urls = [] + liveurl = 'http://www.kitco.com/images/live/%s' + graphurl = 'http://www.kitco.com/LFgif/%s' + t24url = 'http://www.kitconet.com/charts/metals/base/%s' + if metal == 'Gold': + metal_urls.append(['live', liveurl % 'gold.gif']) + metal_urls.append(['30d', graphurl % 'au0030lnb.gif']) + metal_urls.append(['60d', graphurl % 'au0060lnb.gif']) + metal_urls.append(['6m', graphurl % 'au0182nyb.gif']) + metal_urls.append(['1y', graphurl % 'au0365nyb.gif']) + metal_urls.append(['5y', graphurl % 'au1825nyb.gif']) + metal_urls.append(['10y', graphurl % 'au3650nyb.gif']) + elif metal == 'Silver': + metal_urls.append(['live', liveurl % 'silver.gif']) + metal_urls.append(['30d', graphurl % 'ag0030lnb.gif']) + metal_urls.append(['60d', graphurl % 'ag0060lnb.gif']) + metal_urls.append(['6m', graphurl % 'ag0182nyb.gif']) + metal_urls.append(['1y', graphurl % 'ag0365nyb.gif']) + metal_urls.append(['5y', graphurl % 'ag1825nyb.gif']) + metal_urls.append(['10y', graphurl % 'ag3650nyb.gif']) + elif metal == 'Platinum': + metal_urls.append(['live', liveurl % 'plati.gif']) + metal_urls.append(['30d', graphurl % 'pt0030lnb.gif']) + metal_urls.append(['60d', graphurl % 'pt0060lnb.gif']) + metal_urls.append(['6m', graphurl % 'pt0182nyb.gif']) + metal_urls.append(['1y', graphurl % 'pt0365nyb.gif']) + metal_urls.append(['5y', graphurl % 'pt1825nyb.gif']) + elif metal == 'Palladium': + metal_urls.append(['live', liveurl % 'plad.gif']) + metal_urls.append(['30d', graphurl % 'pd0030lnb.gif']) + metal_urls.append(['60d', graphurl % 'pd0060lnb.gif']) + metal_urls.append(['6m', graphurl % 'pd0182nyb.gif']) + metal_urls.append(['1y', graphurl % 'pd0365nyb.gif']) + metal_urls.append(['5y', graphurl % 'pd1825nyb.gif']) + elif metal == 'Rhodium': + metal_urls.append(['30d', graphurl % 'rh0030lnb.gif']) + metal_urls.append(['60d', graphurl % 'rh0060lnb.gif']) + metal_urls.append(['6m', graphurl % 'rh0182lnb.gif']) + metal_urls.append(['1y', graphurl % 'rh0365lnb.gif']) + metal_urls.append(['5y', graphurl % 'rh1825lnb.gif']) + elif metal == 'Copper': + metal_urls.append(['live', t24url % 't24_cp450x275.gif']) + elif metal == 'Nickel': + metal_urls.append(['live', t24url % 't24_nk450x275.gif']) + elif metal == 'Aluminium': + metal_urls.append(['live', t24url % 't24_al450x275.gif']) + elif metal == 'Zinc': + metal_urls.append(['live', t24url % 't24_zc450x275.gif']) + elif metal == 'Lead': + metal_urls.append(['live', t24url % 't24_ld450x275.gif']) + + return metal_urls + + def _tv_columns(self, treeview): + column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0) + column.set_visible(False) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1) + treeview.append_column(column) + + def __create_model(self, names, ids): + lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + for item in range(len(names)): + iter = lstore.append() + lstore.set(iter, 0, ids[item], 1, names[item]) + return lstore + + def main_toolbar(self, quotesview, portfolio, widgets, symbol, name, initial): + toolbar = gtk.HBox() + #toolbar.set_homogeneous(True) + + portfolio_btn = hildon.Button(fhsize, horbtn) + portfolio_btn.set_title("Portfolio") + portfolio_btn.connect("clicked", self.show_portfolio_view) + + graph_btn = hildon.Button(fhsize, horbtn) + graph_btn.set_title("Graph") + graph_btn.connect("clicked", self.show_graph_view, symbol, name) + + refresh_btn = hildon.Button(fhsize, horbtn) + refresh_btn.set_title("Refresh") + refresh_btn.connect("clicked", self.refresh_stock_data, portfolio, + widgets, symbol) + + + info_btn = hildon.Button(fhsize, horbtn) + img = gtk.image_new_from_icon_name("general_information", gtk.ICON_SIZE_SMALL_TOOLBAR) + info_btn.set_image(img) + info_btn.connect("clicked", self.show_app_information) + + search_btn = hildon.Button(fhsize, horbtn) + img = gtk.image_new_from_icon_name("general_search", gtk.ICON_SIZE_SMALL_TOOLBAR) + search_btn.set_image(img) + search_btn.connect("clicked", self.show_search_dialog) + + if not portfolio: + toolbar.pack_start(portfolio_btn) + if not quotesview: + toolbar.pack_start(info_btn, False, False, 0) + if quotesview: + toolbar.pack_start(graph_btn) + toolbar.pack_start(refresh_btn) + + if initial: + toolbar.pack_start(search_btn, False, False, 0) + + toolbar.show_all() + + return toolbar + + def show_search_dialog(self, widget): + dlg = gtk.Dialog(title='Search company', parent=None, flags=0) + dlg.set_has_separator(False) + + hbox = gtk.HBox() + + entry = hildon.Entry(fhsize) + entry.connect("activate", self.do_search, entry, dlg) + hbox.pack_start(entry, True, True, 0) + + button = hildon.Button(fhsize, horbtn) + img = gtk.image_new_from_icon_name("general_search", gtk.ICON_SIZE_SMALL_TOOLBAR) + button.set_image(img) + button.connect("clicked", self.do_search, entry, dlg) + hbox.pack_start(button, False, False, 0) + + dlg.vbox.pack_start(hbox, False, False, 0) + + dlg.show_all() + dlg.run() + dlg.destroy() + + + def do_search(self, widget, entry, dlg): + import thread + text = entry.get_text() + dlg.destroy() + + winprogind(self.window, 1) + thread.start_new_thread(self._really_do_search, (text,)) + + def _really_do_search(self, text): + + if allnames == []: + for market in marketdata.eunames: + for company in market: + allnames.append(company) + + for market in marketdata.omnames: + for company in market: + allnames.append(company) + + for market in marketdata.usnames: + for company in market: + allnames.append(company) + + if allsymbols == []: + for market in marketdata.eusymbols: + for company in market: + allsymbols.append(company) + + for market in marketdata.omsymbols: + for company in market: + allsymbols.append(company) + + for market in marketdata.ussymbols: + for company in market: + allsymbols.append(company) + + new_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + for i in range(len(allnames)): + if text.lower() in allnames[i].lower(): + niter = new_model.append() + #print allsymbols[i], allnames[i] + #FIXME: repeated companies in the results list + #print if allnames[i] + #for j in new_model: + # if j[1] == allnames[i]: + new_model.set(niter, 0, allsymbols[i], 1, allnames[i]) + + if len(new_model) == 0: + winprogind(self.window, 0) + gtk.gdk.threads_enter() + self.show_info_banner(self.window, "No items found for this search") + gtk.gdk.threads_leave() + return + + gtk.gdk.threads_enter() + self.show_search_screen(new_model, text) + gtk.gdk.threads_leave() + winprogind(self.window, 0) + + + def show_search_screen(self, model, text): + window = hildon.StackableWindow() + self.create_menu(window) + window.set_title("Search for " + text) + + vbox = gtk.VBox() + toolbar = self.main_toolbar(False, False, None, '', '', False) + + parea = hildon.PannableArea() + parea.connect("horizontal-movement", self.horizontal_mov) + tv = hildon.GtkTreeView(ui_normal) + tv.connect("row-activated", self.show_quotes_view, model, False) + tv.set_model(model) + self._tv_columns(tv) + parea.add(tv) + + vbox.pack_start(parea, True, True, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 5) + vbox.pack_start(toolbar, False, False, 0) + + window.add(vbox) + window.show_all() + + def show_app_information(self, widget): + self.show_information_note(self.window, ( + "The data is got from Yahoo! Finance.\n" + "It could be delayed or even wrong.\n" + "The author doesn't validate in any way this data and therefore he is not responsible for any damage that may occur.\n\n" + "You can scroll large list with gestures:\n" + "Left-to-right gesture: scroll down.\n" + "Right-to-left gesture: scroll up.")) + + def show_portfolio_view(self, widget): + data = settings.load_portfolio(settingsdb) + for item in data: + item.append('-') + item.append('-') + + win = hildon.StackableWindow() + self.create_menu(win) + win.set_title("Portfolio") + + vbox = gtk.VBox() + + parea = hildon.PannableArea() + parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH) + tv = hildon.GtkTreeView(ui_normal) + tv.set_headers_visible(True) + self.portfolio_model = self._create_portfolio_model(data) + self.quotes_id = tv.connect("row-activated", self.show_quotes_view, + self.portfolio_model, True) + tv.set_model(self.portfolio_model) + self._tv_portfolio_columns(tv) + parea.add(tv) + + hbox = gtk.HBox() + button = hildon.Button(fhsize, horbtn) + button.set_title("Refresh All") + button.connect("clicked", self.refresh_portfolio, tv, win) + hbox.pack_start(button, True, True, 0) + + button = hildon.Button(fhsize, horbtn) + button.set_title("Add manually") + button.connect("clicked", self.add_item_dlg, None, None) + hbox.pack_start(button, True, True, 0) + + button = hildon.Button(fhsize, horbtn) + button.set_title("Remove") + button.connect("clicked", self.remove_item) + hbox.pack_start(button, True, True, 0) + + button = hildon.CheckButton(fhsize) + button.set_label("Edit") + + button.connect("toggled", self.edit_toggled, tv) + hbox.pack_start(button, True, True, 0) + + + vbox.pack_start(parea, True, True, 0) + vbox.pack_start(hbox, False, False, 0) + win.add(vbox) + win.show_all() + + def edit_toggled(self, widget, tv): + if widget.get_active(): + tv.disconnect(self.quotes_id) + self.edit_id = tv.connect("row-activated", + self.edit_portfolio_item, self.portfolio_model) else: - self.window_in_fullscreen = False + tv.disconnect(self.edit_id) + self.quotes_id = tv.connect("row-activated", + self.show_quotes_view, self.portfolio_model, True) + + def edit_portfolio_item(self, widget, path, column, model): + seliter = model.get_iter(path) + + symbol = model[path][0] + name = model[path][1] + shares = model[path][2] + + data = [shares, symbol, name] + self.add_item_dlg(widget, data, seliter) + + def add_item_dlg(self, widget, data, seliter): + if data: + shares = data[0] + symbol = data[1] + name = data[2] + title = "Edit item from portfolio" + btntext = "Edit" + edit = True + else: + shares = "0" + symbol = "" + name = "" + title = "Add to portfolio" + btntext = "Add" + edit = False + + dlg = gtk.Dialog(title=title, parent=None, flags=0) + dlg.set_has_separator(False) + + button1 = hildon.PickerButton(fhsize, horbtn) + data = ["50", "100", "200", "300", "400", "500", "600", "700", "800", + "900", "1000"] + selector = self.create_selector(data, True) + button1.set_selector(selector) + button1.set_title("Your shares") + button1.set_value(shares) + dlg.vbox.pack_start(button1, False, False, 0) + + entry1 = hildon.Entry(fhsize) + entry1.set_text(name) + entry2 = hildon.Entry(fhsize) + entry2.set_text(symbol) + + entry1.set_placeholder("Name") + entry1.connect("activate", self.add_item, dlg, button1, entry1, + entry2, edit, seliter) + dlg.vbox.pack_start(entry1, False, False, 0) + + entry2.connect("activate", self.add_item, dlg, button1, entry1, + entry2, edit, seliter) + entry2.set_placeholder("Yahoo Finance symbol") + dlg.vbox.pack_start(entry2, False, False, 0) + + button = hildon.Button(fhsize, horbtn) + button.set_label(btntext) + button.connect("clicked", self.add_item, dlg, button1, entry1, + entry2, edit, seliter) + dlg.vbox.pack_start(button, False, False, 0) + + dlg.show_all() + dlg.run() + dlg.destroy() - #F6 fullscreen, F7 bigger font, F8 smaller font - def on_key_press(self, widget, event, *args): - if event.keyval == gtk.keysyms.F6: - if self.window_in_fullscreen: - self.window.unfullscreen () + def add_item(self, widget, dlg, button, entry1, entry2, edit, seliter): + symbol = entry2.get_text() + name = entry1.get_text() + shares = button.get_value() + + if name == '' or symbol == '': + self.show_info_banner(widget, "Must add the name and symbol") + return + + self.add_to_portfolio(widget, button, symbol, name) + dlg.destroy() + + if edit: + self.portfolio_model.set(seliter, 0, symbol, 1, name, 2, shares, + 3, "-", 4, "-", 5, "-", 6, "green") + else: + niter = self.portfolio_model.append() + self.portfolio_model.set(niter, 0, symbol, 1, name, 2, shares, + 3, "-", 4, "-", 5, "-", 6, "green") + + def remove_item(self, widget): + win = hildon.StackableWindow() + win.fullscreen() + toolbar = hildon.EditToolbar("Choose items to delete", "Delete") + win.set_edit_toolbar(toolbar) + + vbox = gtk.VBox() + parea = hildon.PannableArea() + tv = hildon.GtkTreeView(ui_edit) + selection = tv.get_selection() + selection.set_mode(gtk.SELECTION_MULTIPLE) + tv.set_model(self.portfolio_model) + self._tv_remove_portfolio_columns(tv) + parea.add(tv) + + toolbar.connect("button-clicked", self.delete_from_portfolio, win, tv, + selection) + toolbar.connect_object("arrow-clicked", gtk.Window.destroy, win) + + vbox.pack_start(parea, True, True, 0) + win.add(vbox) + win.show_all() + + def delete_from_portfolio(self, widget, win, tv, selection): + if not self.is_treeview_selected(tv): + return + + conf = self.show_confirmation(win, "Delete items?") + + if conf: + try: + selmodel, selected = selection.get_selected_rows() + iters = [selmodel.get_iter(path) for path in selected] + for i in iters: + symbol = selmodel.get_value(i, 0) + settings.delete_item_from_portfolio(settingsdb, symbol) + selmodel.remove(i) + except: + logger.exception("Deleting item from portfolio") + self.info_banner(widget, "Error deleting item") + + def _tv_remove_portfolio_columns(self, treeview): + column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0) + column.set_visible(False) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1) + column.set_property("expand", True) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2) + column.set_visible(False) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3) + column.set_visible(False) + treeview.append_column(column) + + def refresh_portfolio(self, widget, tv, win): + data = settings.load_portfolio(settingsdb) + for item in data: + item.append('-') + item.append('-') + import thread + winprogind(win, 1) + thread.start_new_thread(self._do_refresh_portfolio, (data, tv, win)) + + def _do_refresh_portfolio(self, data, tv, win): + print data + for item in data: + item[3], item[4] = self.get_portfolio_data(item[0]) + try: + ch_percent = \ + 100.0 * float(item[4])/(float(item[3]) - \ + float(item[4])) + except ValueError: + ch_percent = 0.0 + + item[5] = '%6.2f %%' % ch_percent + + + print data + self.portfolio_model = self._create_portfolio_model(data) + tv.set_model(self.portfolio_model) + winprogind(win, 0) + + def get_portfolio_data(self, symbol): + from ystockquote import ystockquote as yt + try: + data = yt.get_all(symbol) + return data['price'], data['change'] + except: + logger.exception("Getting price from Yahoo: %s" % symbol) + return "-", "-" + + def _create_portfolio_model(self, data): + lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, + gobject.TYPE_STRING, gobject.TYPE_STRING, + gobject.TYPE_STRING, gobject.TYPE_STRING, + gobject.TYPE_STRING) + for item in data: + iter = lstore.append() + if '+' in item[4]: + color = 'green' else: - self.window.fullscreen () - - def on_about(self, widget): - dialog = gtk.AboutDialog() - dialog.set_name("StockThis") - dialog.set_version("0.1") - dialog.set_copyright("Copyright © 2009") - dialog.set_website("http://stockthis.garage.maemo.org") - dialog.set_authors(["Daniel Martin Yerga "]) - logo = gtk.gdk.pixbuf_new_from_file(imgdir + "stockthis.png") - dialog.set_logo(logo) - dialog.set_license("This program is released under the GNU\nGeneral Public License. Please visit \nhttp://www.gnu.org/copyleft/gpl.html\nfor details.") - dialog.set_artists(["Logo by Daniel Martin Yerga"]) + color = 'red' + lstore.set(iter, 0, item[0], 1, item[1], 2, item[2], 3, item[3], + 4, item[4], 5, item[5], 6, color) + return lstore + + def _tv_portfolio_columns(self, treeview): + column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0) + column.set_visible(False) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1) + column.set_property("expand", True) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Shares', gtk.CellRendererText(), text=2) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3) + treeview.append_column(column) + + column = gtk.TreeViewColumn('Change', gtk.CellRendererText(), text=4) + treeview.append_column(column) + + + renderer = gtk.CellRendererText() + renderer.set_property("foreground-set", True) + column = gtk.TreeViewColumn('%', renderer, text=5, foreground=6) + treeview.append_column(column) + + def show_confirmation(self, window, msg): + dialog = hildon.hildon_note_new_confirmation(window, msg) + dialog.show_all() + result = dialog.run() + if result == gtk.RESPONSE_OK: + dialog.destroy() + return True + + dialog.destroy() + return False + + def show_information_note(self, window, msg): + dialog = hildon.hildon_note_new_information(window, msg) + dialog.show_all() + result = dialog.run() + dialog.destroy() + + def show_info_banner(self, widget, msg): + hildon.hildon_banner_show_information(widget, 'qgn_note_infoprint', msg) + + def is_treeview_selected(self, treeview): + selection = treeview.get_selection() + if selection.count_selected_rows() == 0: + self.show_info_banner(treeview, 'No selected item') + return False + else: + return True + +class About: + + def __init__(self, widget): + self.abdialog = gtk.Dialog() + self.abdialog.set_title("About StockThis") + + notebook = gtk.Notebook() + notebook.set_show_tabs(False) + notebook.set_scrollable(False) + notebook.set_show_border(False) + + # Description page # + vbox = gtk.VBox() + + label = gtk.Label() + label.set_markup("StockThis %s" % VERSION) + vbox.pack_start(label, True, True, 0) + + label = gtk.Label("Stocks application with big database") + vbox.pack_start(label, True, True, 0) + + label = gtk.Label("GNU General Public License") + vbox.pack_start(label, True, True, 0) + + url = "http://stockthis.garage.maemo.org" + webbtn = gtk.LinkButton(url, "Web") + vbox.pack_start(webbtn, True, True, 0) + gtk.link_button_set_uri_hook(self.launch_browser) + + notebook.append_page(vbox, gtk.Label()) + + # Credits page # + vbox = gtk.VBox() + textview = hildon.TextView() + textview.set_cursor_visible(False) + textview.set_wrap_mode(gtk.WRAP_WORD) + text = "Written by Daniel Martin Yerga (dyerga@gmail.com)" + textview.get_buffer().set_text(text) + + parea = hildon.PannableArea() + parea.add(textview) + + vbox.pack_start(parea, True, True, 0) + notebook.append_page(vbox, gtk.Label()) + + + # Donate page # + vbox = gtk.VBox() + + textview = hildon.TextView() + textview.set_cursor_visible(False) + textview.set_wrap_mode(gtk.WRAP_WORD) + text = """StockThis is a free software application. +Developing good software takes time and hard work. +StockThis's author develops the program in his spare time. +If you like the program and it's helpful, consider donating a small amount of money. +Donations are a great incentive and help the developer feel that the hard work is appreciated. +""" + textview.get_buffer().set_text(text) + + parea = hildon.PannableArea() + parea.add(textview) + + button = hildon.Button(fhsize, horbtn) + button.set_title("Make donation") + url = "http://stockthis.garage.maemo.org/donate.html" + button.connect("clicked", self.launch_browser, url) + vbox.pack_start(button, False, False, 0) + vbox.pack_start(parea, True, True, 0) + + notebook.append_page(vbox, gtk.Label()) + + # Report page # + vbox = gtk.VBox() + + textview = hildon.TextView() + textview.set_cursor_visible(False) + textview.set_wrap_mode(gtk.WRAP_WORD) + text = """StockThis is being improved thanks to bug reports that users have submitted. The author appreciates these reports. +If the application is having an error when you're using it, you have two choices to report this error: +1) Send the log from the button above (if there's an error in the log). +2) Press the button and read how to report a bug.""" + textview.get_buffer().set_text(text) + + parea = hildon.PannableArea() + parea.add(textview) + + hbox = gtk.HBox() + hbox.set_homogeneous(True) + + button = hildon.Button(fhsize, horbtn) + button.set_title("Report error") + url = "http://stockthis.garage.maemo.org/reporting.html" + button.connect("clicked", self.launch_browser, url) + hbox.pack_start(button, True, True, 0) + + button = hildon.Button(fhsize, horbtn) + button.set_title("Log") + button.connect("clicked", self.on_show_log) + hbox.pack_start(button, True, True, 0) + + vbox.pack_start(hbox, False, False, 0) + vbox.pack_start(parea, True, True, 0) + + notebook.append_page(vbox, gtk.Label()) + + # Rate page # + vbox = gtk.VBox() + + textview = hildon.TextView() + textview.set_cursor_visible(False) + textview.set_wrap_mode(gtk.WRAP_WORD) + text = """The downloads section in maemo.org has a nice system where you can rate applications. +If you consider StockThis a good application (or a bad one too), you could rate it in maemo.org site.""" + textview.get_buffer().set_text(text) + + button = hildon.Button(fhsize, horbtn) + button.set_title("Rate StockThis") + url = "http://maemo.org/downloads/product/Maemo5/stockthis" + button.connect("clicked", self.launch_browser, url) + image = gtk.Image() + image.set_from_file(imgdir + "maemoorg.png") + vbox.pack_start(button, False, False, 0) + vbox.pack_start(image, False, False, 5) + vbox.pack_start(textview, True, True, 0) + + notebook.append_page(vbox, gtk.Label()) + + # Buttons # + self.abdialog.vbox.pack_start(notebook, True, True, 0) + + hbox = gtk.HBox() + + descbutton = hildon.GtkRadioButton(fhsize) + descbutton.set_mode(False) + descbutton.set_active(True) + descbutton.set_label('Description') + descbutton.connect("toggled", self.change_tab, notebook, 0) + hbox.pack_start(descbutton, True, True, 0) + + button = hildon.GtkRadioButton(fhsize) + button.set_mode(False) + button.set_active(True) + button.set_label('Credits') + button.set_group(descbutton) + button.connect("toggled", self.change_tab, notebook, 1) + hbox.pack_start(button, True, True, 0) + + button = hildon.GtkRadioButton(fhsize) + button.set_mode(False) + button.set_label('Donate') + button.set_group(descbutton) + button.connect("clicked", self.change_tab, notebook, 2) + hbox.pack_start(button, True, True, 0) + + button = hildon.GtkRadioButton(fhsize) + button.set_mode(False) + button.set_label('Report') + button.set_group(descbutton) + button.connect("clicked", self.change_tab, notebook, 3) + hbox.pack_start(button, True, True, 0) + + button = hildon.GtkRadioButton(fhsize) + button.set_mode(False) + button.set_label('Rate') + button.set_group(descbutton) + button.connect("clicked", self.change_tab, notebook, 4) + hbox.pack_start(button, True, True, 0) + + self.abdialog.vbox.pack_start(hbox, False, False, 0) + + self.abdialog.show_all() + self.abdialog.run() + self.abdialog.destroy() + + def change_tab(self, widget, notebook, number): + notebook.set_current_page(number) + + def launch_browser(self, widget, url): + import dbus + bus = dbus.SystemBus() + proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request") + iface = dbus.Interface(proxy, 'com.nokia.osso_browser') + + self.abdialog.destroy() + + iface.open_new_window(url) + + def on_show_log(self, widget): + Log(widget, logfile) + + +class Log: + + def __init__(self, widget, logfile): + #Log dialog UI + dialog = gtk.Dialog(title='Log', parent=None) + + dialog.set_size_request(600, 350) + + parea = hildon.PannableArea() + parea.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH) + + textview = hildon.TextView() + textview.set_property("editable", False) + textview.set_property("wrap-mode", gtk.WRAP_WORD) + + log = open(logfile, 'r') + logtext = log.read() + log.close() + + textview.get_buffer().set_text(logtext) + parea.add(textview) + + dialog.vbox.pack_start(parea, True, True, 0) + + hbox = gtk.HBox() + + save_btn = hildon.Button(fhsize, horbtn) + save_btn.set_title("Save") + save_btn.connect('clicked', self.save, logfile, dialog) + + clear_btn = hildon.Button(fhsize, horbtn) + clear_btn.set_title("Clear") + clear_btn.connect('clicked', self.clear, textview, logfile) + + send_btn = hildon.Button(fhsize, horbtn) + send_btn.set_title('Send') + send_btn.connect('clicked', self.send, dialog, logfile) + + hbox.pack_start(save_btn, True, True, 0) + hbox.pack_start(clear_btn, True, True, 0) + hbox.pack_start(send_btn, True, True, 0) + + dialog.vbox.pack_start(hbox, False, False, 0) + + dialog.show_all() dialog.run() dialog.destroy() - + + def show_filechooser(self, window, title, name, EXT): + action = gtk.FILE_CHOOSER_ACTION_SAVE + + m = hildon.FileSystemModel() + file_dialog = hildon.FileChooserDialog(window, action, m) + file_dialog.set_title(title) + + file_dialog.set_current_name(name) + HOME = os.path.expanduser("~") + + if os.path.exists(HOME + '/MyDocs/.documents'): + file_dialog.set_current_folder(HOME + '/MyDocs/.documents') + else: + file_dialog.set_current_folder(HOME) + + file_dialog.set_default_response(gtk.RESPONSE_CANCEL) + + result = file_dialog.run() + if result == gtk.RESPONSE_OK: + namefile = file_dialog.get_filename() + namefile, extension = os.path.splitext(namefile) + namefile = namefile + "." + EXT + else: + namefile = None + file_dialog.destroy() + + return namefile + + + def clear(self, widget, textview, logfile): + textview.get_buffer().set_text('') + f = open(logfile, 'w') + f.close() + + def save(self, widget, logfile, dlg): + import shutil + filename = self.show_filechooser(dlg, "Save log file", + "stockthis-log", "txt") + + if not filename: + return + + try: + shutil.copyfile(logfile, filename) + stockspy.show_info_banner(widget, 'Log file saved') + except: + logger.exception("Saving log file") + stockspy.show_info_banner(widget, 'Error saving the log file') + + def send(self, widget, dlg, logfile): + sendtxt = ("You are going to send the log to the developers.\n" + "This helps the developers to track problems with the application.\n" + "It doesn't send any personal information (like passwords or similar).") + + dialog = hildon.hildon_note_new_confirmation(dlg, sendtxt) + dialog.set_button_texts("Send", "Cancel") + dialog.show_all() + response = dialog.run() + if response == gtk.RESPONSE_OK: + self.do_pre_send(dlg, logfile) + + dialog.destroy() + + def do_pre_send(self, dlg, logfile): + import thread + hildon.hildon_gtk_window_set_progress_indicator(dlg, 1) + thread.start_new_thread(self._do_send, (dlg, logfile)) + + def _do_send(self, dlg, logfile): + import pycurl, shutil, random, commands + try: + rname = '' + for i in random.sample('abcdefghijkl123456789', 18): + rname += i + + rnamepath = HOME + "/.stockthis/" + rname + shutil.copyfile(logfile, rnamepath) + + gtkversion = "%s.%s.%s" % gtk.ver + if os.path.exists("/etc/maemo_version"): + mfile = open("/etc/maemo_version", 'r') + maemoversion = mfile.read() + mfile.close() + else: + maemoversion = '' + + opsystem = ' '.join(os.uname()) + pyversion = os.sys.version + pid = os.getpid() + comm = ("awk '/Private_Dirty/{sum+=$2}END{print sum \"kB\"}'" + " /proc/%s/smaps") % pid + status, dirtymem = commands.getstatusoutput(comm) + + lfile = open(rnamepath, 'r') + log = lfile.read() + lfile.close() + + + log = ("%s\nPython version: %s\nGtk version: %s\n" + "Maemo version: %sOperating system: %s\n" + "Dirty Memory: %s\nLog:\n%s") % (_version, pyversion, gtkversion, + maemoversion, opsystem, dirtymem, log) + + lfile = open(rnamepath, 'w') + lfile.write(log) + lfile.close() + + url = "http://yerga.net/logs/uploader.php" + data = [('uploadedfile', (pycurl.FORM_FILE, rnamepath)),] + mycurl = pycurl.Curl() + mycurl.setopt(pycurl.URL, url) + mycurl.setopt(pycurl.HTTPPOST, data) + + mycurl.perform() + mycurl.close() + os.remove(rnamepath) + + gtk.gdk.threads_enter() + stockspy.show_info_banner(dlg, 'Log sent') + gtk.gdk.threads_leave() + hildon.hildon_gtk_window_set_progress_indicator(dlg, 0) + except: + logger.exception("Sending log file") + gtk.gdk.threads_enter() + stockspy.show_info_banner(dlg, 'Error sending the log file') + gtk.gdk.threads_leave() + hildon.hildon_gtk_window_set_progress_indicator(dlg, 0) + + if __name__ == "__main__": stockspy = StocksPy() gtk.gdk.threads_enter() gtk.main() gtk.gdk.threads_leave() -