added portfolio section
authorDaniel Martin Yerga <yerga@debian.(none)>
Wed, 29 Jul 2009 16:01:53 +0000 (18:01 +0200)
committerDaniel Martin Yerga <yerga@debian.(none)>
Wed, 29 Jul 2009 16:01:53 +0000 (18:01 +0200)
changelog
settings.py [new file with mode: 0644]
stockthis.py

index 9d696cf..9d1fe19 100644 (file)
--- a/changelog
+++ b/changelog
@@ -1,3 +1,10 @@
+2009-07-29  Daniel Martín Yerga  <dyerga@gmail.com>
+
+    * stockthis.py: Getting and saving data from portfolio settings.
+    Remove and add items to portfolio.
+
+    * settings.py: Module to manage the sqlite db for the portfolio data.
+
 2009-07-28  Daniel Martín Yerga  <dyerga@gmail.com>
 
     * stockthis.py: Added portfolio section.
diff --git a/settings.py b/settings.py
new file mode 100644 (file)
index 0000000..0419ef8
--- /dev/null
@@ -0,0 +1,66 @@
+import sqlite3
+import os
+
+def create_initial_portfolio(sqlite_db):
+    cursor_sql = sqlite_db.cursor()
+    cursor_sql.execute('CREATE TABLE Portfolio (symbol text, name text, '
+                        'shares text, price text)')
+    sqlite_db.commit()
+    cursor_sql.close()
+
+def load_portfolio(sqlite_db):
+    portfolio = []
+    for table in sqlite_db.execute('select * from Portfolio'):
+        portfolio.append([table[0], table[1], table[2], table[3]])
+
+    return portfolio
+
+def insert_new_item_to_portfolio(sqlite_db, item):
+    cursor_sql = sqlite_db.cursor()
+    cursor_sql.execute('INSERT INTO Portfolio VALUES (?, ?, ?, ?)',
+                            (item[0], item[1], item[2], item[3]))
+
+    sqlite_db.commit()
+    cursor_sql.close()
+
+def save_portfolio(sqlite_db, portfolio):
+    cursor_sql = sqlite_db.cursor()
+
+    for item in portfolio:
+        cursor_sql.execute('INSERT INTO Portfolio VALUES (?, ?, ?, ?)',
+                            (item[0], item[1], item[2], item[3]))
+
+        sqlite_db.commit()
+    cursor_sql.close()
+
+def clear_portfolio(sqlite_db):
+    cursor_sql = sqlite_db.cursor()
+    sqlite_db.execute('delete from Portfolio')
+    sqlite_db.commit()
+    cursor_sql.close()
+
+def delete_item_from_portfolio(sqlite_db, symbol):
+    cursor_sql = sqlite_db.cursor()
+    sqlite_db.execute('delete from Portfolio where symbol="%s"' % symbol)
+    sqlite_db.commit()
+    cursor_sql.close()
+
+def define_paths(locally, HOME):
+    configdir = HOME + '/.stockthis/'
+    logfile = configdir + 'log.txt'
+
+    if not os.path.exists(configdir):
+        os.mkdir(configdir)
+
+    if os.path.exists(configdir + 'settings'):
+        settingsdb = sqlite3.connect(configdir + 'settings')
+    else:
+        settingsdb = sqlite3.connect(configdir + 'settings')
+        create_initial_portfolio(settingsdb)
+
+    if locally:
+        imgdir = 'pixmaps/'
+    else:
+        imgdir = '/usr/share/stockthis/pixmaps/'
+
+    return settingsdb, imgdir, configdir, logfile
index 3e86a93..578af6d 100644 (file)
 
 import urllib2
 import gtk, gobject
-
+import os
 import hildon
 
 #import osso
-#osso_c = osso.Context("net.yerga.stockthis", "0.2", False)
+#osso_c = osso.Context("net.yerga.stockthis", "0.3", False)
 
 from marketdata import markets, idmarket, localmarkets, localids
+import settings
+
 
 #detect if is ran locally or not
 import sys
 runningpath = sys.path[0]
 
 if '/usr/share' in runningpath:
-    running_locally = False
+    runninglocally = False
 else:
-    running_locally = True
+    runninglocally = True
 
-if running_locally:
-    imgdir = 'pixmaps/'
-else:
-    imgdir = '/usr/share/stockthis/pixmaps/'
+HOME = os.path.expanduser("~")
+
+settingsdb, imgdir, configdir, logfile = \
+    settings.define_paths(runninglocally, HOME)
 
-loading_img = imgdir + 'loading.gif'
 
 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
 
 gtk.gdk.threads_init()
@@ -72,7 +74,7 @@ class StocksPy:
         menu.show_all()
 
         vbox = gtk.VBox()
-        toolbar = self.main_toolbar(False)
+        toolbar = self.main_toolbar(False, False)
 
         parea = hildon.PannableArea()
         tv = hildon.GtkTreeView(ui_normal)
@@ -98,12 +100,12 @@ class StocksPy:
         window = hildon.StackableWindow()
 
         vbox = gtk.VBox()
-        toolbar = self.main_toolbar(False)
+        toolbar = self.main_toolbar(False, False)
 
         parea = hildon.PannableArea()
         tv = hildon.GtkTreeView(ui_normal)
         model = self.__create_model(names, ids)
-        tv.connect("row-activated", self.show_quotes_view, model)
+        tv.connect("row-activated", self.show_quotes_view, model, False)
         tv.set_model(model)
         self._tv_columns(tv)
         parea.add(tv)
@@ -116,7 +118,7 @@ class StocksPy:
         window.show_all()
 
 
-    def show_quotes_view(self, widget, path, column, model):
+    def show_quotes_view(self, widget, path, column, model, portfolio):
         quote = model[path][0], model[path][1]
 
         self.stocks_id = quote[0]
@@ -126,7 +128,7 @@ class StocksPy:
         self.quotes_win = hildon.StackableWindow()
 
         vbox = gtk.VBox()
-        toolbar = self.main_toolbar(True)
+        toolbar = self.main_toolbar(True, portfolio)
 
 
         self.titlelbl = gtk.Label('')
@@ -143,8 +145,8 @@ class StocksPy:
         label = gtk.Label('')
         label.set_markup('<b><big>Price:</big></b>')
         self.lprice = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.lprice, False, False, 185)
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(self.lprice, False, False, 245)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
@@ -152,8 +154,8 @@ class StocksPy:
         label.set_markup('<b><big>Change:</big></b>')
         self.lchange = gtk.Label('')
         self.lpercent = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.lchange, False, False, 145)
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(self.lchange, False, False, 205)
         hbox.pack_start(self.lpercent, False, False, 0)
         vbox1.pack_start(hbox, True, True, 0)
 
@@ -161,44 +163,70 @@ class StocksPy:
         label = gtk.Label('')
         label.set_markup('<b><big>Volume:</big></b>')
         self.lvolume = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.lvolume, False, False, 145)
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(self.lvolume, False, False, 207)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
         label = gtk.Label('')
         label.set_markup('<b><big>52 week high:</big></b>')
         self.l52whigh = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.l52whigh, False, False, 55)
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(self.l52whigh, False, False, 110)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
         label = gtk.Label('')
         label.set_markup('<b><big>52 week low:</big></b>')
         self.l52wlow = gtk.Label('')
-        hbox.pack_start(label, False, False, 50)
-        hbox.pack_start(self.l52wlow, False, False, 70)
+        hbox.pack_start(label, False, False, 20)
+        hbox.pack_start(self.l52wlow, False, False, 125)
         vbox1.pack_start(hbox, True, True, 0)
 
         hbox = gtk.HBox()
-
-        button = hildon.PickerButton(fhsize, horbtn)
-        #FIXME: touchentry selector
+        button1 = hildon.PickerButton(fhsize, horbtn)
         data = ["50", "100", "200", "300", "400", "500", "600", "700", "800",
                 "900", "1000"]
-        selector = self.create_selector(data)
-        button.set_selector(selector)
-        button.set_title("Shares")
-        #FIXME: check portfolio and see if there's quotes
-        button.set_value(data[0])
-        hbox.pack_start(button, True, True, 0)
+        selector = self.create_selector(data, True)
+        button1.set_selector(selector)
+        button1.set_title("Shares")
+        #FIXME: Improve as it's shown you have a component in your portfolio
+        shares = self.get_shares_from_symbol()
+        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.publish_opt_screen)
+        button.connect("clicked", self.add_to_portfolio, button1)
         hbox.pack_start(button, True, True, 0)
-        vbox1.pack_start(hbox, False, False, 0)
+
+        hbox1 = gtk.HBox()
+        label = gtk.Label('')
+        label.set_markup('<b><big>Shares:</big></b>')
+        self.shares = gtk.Label(shares)
+        hbox1.pack_start(label, False, False, 20)
+        hbox1.pack_start(self.shares, False, False, 215)
+
+        hbox2 = gtk.HBox()
+        label = gtk.Label('')
+        label.set_markup('<b><big>Holdings Value:</big></b>')
+        self.holdingsvalue = gtk.Label("")
+        hbox2.pack_start(label, False, False, 20)
+        hbox2.pack_start(self.holdingsvalue, False, False, 85)
+
+        hbox3 = gtk.HBox()
+        label = gtk.Label('')
+        label.set_markup("<b><big>Day's Value Change:</big></b>")
+        self.dayvaluechange = gtk.Label("")
+        hbox3.pack_start(label, False, False, 20)
+        hbox3.pack_start(self.dayvaluechange, False, False, 10)
+
+        if not portfolio:
+            vbox1.pack_start(hbox, False, False, 0)
+        else:
+            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)
 
@@ -210,21 +238,54 @@ class StocksPy:
 
         self.quotes_win.add(vbox)
         self.quotes_win.show_all()
-        self.show_data(quote[0], self.quotes_win)
+        self.show_data(quote[0], self.quotes_win, shares)
+
+    def get_shares_from_symbol(self):
+        portfolio_data = settings.load_portfolio(settingsdb)
+        shares = "0"
+        for item in portfolio_data :
+            if self.stocks_id in item:
+                shares = item[2]
+        return shares
+
+    def add_to_portfolio(self, widget, button):
+        shares = button.get_value()
+        self.stocks_id
+        self.stocks_name
+
+        portfolio = settings.load_portfolio(settingsdb)
+        index = "None"
+        for item in portfolio:
+            if self.stocks_id in item:
+                index = portfolio.index(item)
+
+        item = [self.stocks_id, self.stocks_name, shares, '-']
+
+        if index is "None":
+            settings.insert_new_item_to_portfolio(settingsdb, item)
+        else:
+            settings.delete_item_from_portfolio(settingsdb, self.stocks_id)
+            settings.insert_new_item_to_portfolio(settingsdb, item)
+
+        self.show_info_banner(widget, "Added to portfolio")
 
-    def create_selector(self, data):
-        selector = hildon.hildon_touch_selector_new_text()
+
+    def create_selector(self, data, entry):
+        if entry:
+            selector = hildon.TouchSelectorEntry(text=True)
+        else:
+            selector = hildon.hildon_touch_selector_new_text()
         for i in range(len(data)):
             selector.append_text(data[i])
 
         return selector
 
-    def show_data(self, quote, win):
+    def show_data(self, quote, win, shares):
         import thread
         winprogind(win, 1)
-        thread.start_new_thread(self.get_data, (quote, win))
+        thread.start_new_thread(self.get_data, (quote, win, shares))
 
-    def get_data(self, quote, win):
+    def get_data(self, quote, win, shares):
         from ystockquote import ystockquote as yt
         try:
             data = yt.get_all(quote)
@@ -257,17 +318,33 @@ class StocksPy:
         self.l52whigh.set_label(data['52_week_high'])
         self.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'
+
+        self.dayvaluechange.set_label(str(daychange))
+        self.holdingsvalue.set_label(str(holdvalue))
+
         winprogind(win, 0)
 
-    def refresh_stock_data(self, widget):
-        self.show_data(self.stocks_id, self.quotes_win)
+    def refresh_stock_data(self, widget, portfolio):
+        if portfolio:
+            shares = self.get_shares_from_symbol()
+        else:
+            shares = "0"
 
+        self.show_data(self.stocks_id, self.quotes_win, shares)
 
     def show_graph_view(self, widget):
         win = hildon.StackableWindow()
 
         vbox = gtk.VBox()
-        toolbar = self.main_toolbar(False)
+        toolbar = self.main_toolbar(False, True)
 
         self.graphs_title = gtk.Label(self.stocks_name)
         color = gtk.gdk.color_parse("#03A5FF")
@@ -377,8 +454,6 @@ class StocksPy:
             self.graphs_title.set_label('Failed to get data')
             self.graph.destroy()
 
-
-
     def _tv_columns(self, treeview):
         column = gtk.TreeViewColumn('ID', gtk.CellRendererText(), text=0)
         column.set_visible(False)
@@ -394,7 +469,7 @@ class StocksPy:
             lstore.set(iter, 0, ids[item], 1, names[item])
         return lstore
 
-    def main_toolbar(self, quotesview):
+    def main_toolbar(self, quotesview, portfolio):
         toolbar = gtk.HBox()
         toolbar.set_homogeneous(True)
 
@@ -408,9 +483,10 @@ class StocksPy:
 
         refresh_btn = hildon.Button(fhsize, horbtn)
         refresh_btn.set_title("Refresh")
-        refresh_btn.connect("clicked", self.refresh_stock_data)
+        refresh_btn.connect("clicked", self.refresh_stock_data, portfolio)
 
-        toolbar.pack_start(portfolio_btn)
+        if not portfolio:
+            toolbar.pack_start(portfolio_btn)
         if quotesview:
             toolbar.pack_start(graph_btn)
             toolbar.pack_start(refresh_btn)
@@ -420,9 +496,8 @@ class StocksPy:
         return toolbar
 
     def show_portfolio_view(self, widget):
-        #FIXME: get data from sqlite settings
-        data = [["SAN.MC", "BANCO SANTANDER R", "200", "-"],
-                ["BBVA.MC", "BBVA R", "300", "-"]]
+        data = settings.load_portfolio(settingsdb)
+
         win = hildon.StackableWindow()
 
         vbox = gtk.VBox()
@@ -430,33 +505,94 @@ class StocksPy:
         parea = hildon.PannableArea()
         tv = hildon.GtkTreeView(ui_normal)
         tv.set_headers_visible(True)
-        inmodel = self._create_portfolio_model(data)
-        #tv.connect("row-activated", self.show_instrument_view, inmodel)
-        tv.set_model(inmodel)
+        self.portfolio_model = self._create_portfolio_model(data)
+        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, data)
+        button.connect("clicked", self.refresh_portfolio, tv, win)
+        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)
 
         vbox.pack_start(parea, True, True, 0)
-        vbox.pack_start(button, False, False, 0)
+        vbox.pack_start(hbox, False, False, 0)
         win.add(vbox)
         win.show_all()
 
-    def refresh_portfolio(self, widget, tv, win, data):
+    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:
+            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)
+
+    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)
         import thread
         winprogind(win, 1)
         thread.start_new_thread(self._do_refresh_portfolio, (data, tv, win))
 
-
     def _do_refresh_portfolio(self, data, tv, win):
         for item in data:
             item[3] = self.get_price(item[0])
 
-        model = self._create_portfolio_model(data)
-        tv.set_model(model)
+        self.portfolio_model = self._create_portfolio_model(data)
+        tv.set_model(self.portfolio_model)
         winprogind(win, 0)
 
     def get_price(self, symbol):
@@ -488,10 +624,32 @@ class StocksPy:
         column = gtk.TreeViewColumn('Price', gtk.CellRendererText(), text=3)
         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_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
+
     def on_about(self, widget):
         dialog = gtk.AboutDialog()
         dialog.set_name("StockThis")
-        dialog.set_version("0.2")
+        dialog.set_version("0.3")
         dialog.set_copyright("Copyright © 2009")
         dialog.set_website("http://stockthis.garage.maemo.org")
         dialog.set_authors(["Daniel Martin Yerga <dyerga@gmail.com>"])