adding fremantle version, and portfolio section
[stockthis] / stockthis-diablo.py
diff --git a/stockthis-diablo.py b/stockthis-diablo.py
new file mode 100644 (file)
index 0000000..b80ffc7
--- /dev/null
@@ -0,0 +1,561 @@
+#!/usr/bin/env python
+# -*- coding: UTF8 -*-
+# Copyright (C) 2008 by Daniel Martin Yerga
+# <dyerga@gmail.com>
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# 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
+#
+
+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.2", False)
+except:
+    OSSO = False
+
+from marketdata import markets, idmarket, localmarkets, localids
+
+#TODO: detect if running in Fremantle
+FREMANTLE=True
+
+#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/'
+else:
+    imgdir = '/usr/share/stockthis/pixmaps/'
+
+loading_img = imgdir + 'loading.gif'
+
+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)
+        else:
+            self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+
+        self.window.set_default_size(800, 480)
+        self.window.set_title('StockThis')
+        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_app_menu(menu)
+                about_menu = gtk.Button("About")
+                about_menu.connect("clicked", self.on_about)
+            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
+
+
+        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('Instruments')
+        self.components_btn.connect("clicked", self.show_components_view)
+        self.components_btn.set_property("can_focus", False)
+
+        self.graph_btn = gtk.Button('Graph')
+        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('Quote')
+        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()
+        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)
+
+        vbox.pack_start(self.swin, True, True, 0)
+        vbox.pack_start(gtk.HSeparator(), False, False, 5)
+        vbox.pack_start(self.toolbar, False, False, 0)
+
+        self.create_markets_view(self.mainbox)
+        self.window.add(vbox)
+
+        self.window.show_all()
+
+    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()
+        self.components_trv.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_HORIZONTAL)
+
+        if not FREMANTLE:
+            selection = self.components_trv.get_selection()
+            selection.connect("changed", self.changed_selection, ids)
+        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
+
+    def _components_trv_columns(self, treeview):
+        renderer = gtk.CellRendererText()
+        renderer.set_property('scale', 1.3)
+        #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()
+
+        try:
+            self.graphbox.destroy()
+        except:
+            pass
+
+        for i in range(len(localids)):
+            if kind in localids[i]:
+                ind1, ind2 = i, localids[i].index(kind)
+
+        self.quotesbox = gtk.VBox()
+
+        self.titlelbl = gtk.Label('')
+        self.titlelbl.set_markup('<b><big>'+localmarkets[ind1][ind2].replace('&', '')+'</big></b>')
+        color = gtk.gdk.color_parse("#03A5FF")
+        self.titlelbl.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('<b><big>Price:</big></b>')
+        self.lprice = gtk.Label('')
+
+        hbox1.pack_start(label2, False, False, 50)
+        hbox1.pack_start(self.lprice, False, False, 185)
+
+        hbox2 = gtk.HBox()
+
+        label4 = gtk.Label('')
+        label4.set_markup('<b><big>Change:</big></b>')
+        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('<b><big>Volume:</big></b>')
+        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('<b><big>52 week high:</big></b>')
+        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('<b><big>52 week low:</big></b>')
+        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(self.titlelbl, 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):
+        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()
+
+        from ystockquote import ystockquote as yt
+        try:
+            data = yt.get_all(kind)
+        except:
+            print 'Failed to get internet data'
+            data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A',
+                    '52_week_high': 'N/A', '52_week_low': 'N/A'}
+            self.titlelbl.set_markup('<b><big>Failed to get data</big></b>')
+
+        try:
+            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)
+
+        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()
+
+        self.graphs_title = gtk.Label(localmarkets[ind1][ind2])
+        color = gtk.gdk.color_parse("#03A5FF")
+        self.graphs_title.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(self.graphs_title, 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):
+        import thread
+        self.graph.set_from_file(loading_img)
+        thread.start_new_thread(self.get_graph_data, (option, kind))
+
+    def get_graph_data(self, option, kind):
+        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()
+
+        try:
+            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)
+        except:
+            print 'no internet data'
+            self.graphs_title.set_label('Failed to get data')
+            self.graph.destroy()
+
+
+    #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
+        else:
+            self.window_in_fullscreen = False
+
+    #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 ()
+            else:
+                self.window.fullscreen ()
+
+    def on_about(self, widget):
+        dialog = gtk.AboutDialog()
+        dialog.set_name("StockThis")
+        dialog.set_version("0.2")
+        dialog.set_copyright("Copyright © 2009")
+        dialog.set_website("http://stockthis.garage.maemo.org")
+        dialog.set_authors(["Daniel Martin Yerga <dyerga@gmail.com>"])
+        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"])
+        dialog.run()
+        dialog.destroy()
+
+if __name__ == "__main__":
+    stockspy = StocksPy()
+    gtk.gdk.threads_enter()
+    gtk.main()
+    gtk.gdk.threads_leave()