3 # Copyright (C) 2008 by Daniel Martin Yerga
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # StocksPy: Application to get stocks data from Yahoo Finance.
34 osso_c = osso.Context("net.yerga.stockthis", "0.2", False)
38 from marketdata import markets, idmarket, localmarkets, localids
40 #TODO: detect if running in Fremantle
43 #detect if is ran locally or not
45 runningpath = sys.path[0]
47 if '/usr/share' in runningpath:
48 running_locally = False
50 running_locally = True
55 imgdir = '/usr/share/stockthis/pixmaps/'
57 loading_img = imgdir + 'loading.gif'
59 gtk.gdk.threads_init()
65 self.program = hildon.Program()
66 self.program.__init__()
67 gtk.set_application_name('')
69 self.window = hildon.StackableWindow()
71 self.window = hildon.Window()
72 self.program.add_window(self.window)
74 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
76 self.window.set_default_size(800, 480)
77 self.window.set_title('StockThis')
78 self.window.connect("destroy", gtk.main_quit)
79 self.window.connect("key-press-event", self.on_key_press)
80 self.window.connect("window-state-event", self.on_window_state_change)
81 self.window_in_fullscreen = False
85 menu = hildon.AppMenu()
86 self.window.set_app_menu(menu)
87 about_menu = gtk.Button("About")
88 about_menu.connect("clicked", self.on_about)
91 self.window.set_menu(menu)
92 about_menu = gtk.MenuItem("About")
93 about_menu.set_size_request(-1, 55)
94 about_menu.connect("activate", self.on_about)
96 menu.append(about_menu)
99 #TODO: create a gtk.menubar
105 self.toolbar = gtk.HBox()
106 self.toolbar.set_property("no-show-all", True)
108 self.toolbar.set_homogeneous(True)
109 self.toolbar.set_size_request(-1, 55)
111 self.markets_btn = gtk.Button('Markets')
112 self.markets_btn.connect("clicked", self.create_markets_view)
113 self.markets_btn.set_property("can_focus", False)
115 self.components_btn = gtk.Button('Instruments')
116 self.components_btn.connect("clicked", self.show_components_view)
117 self.components_btn.set_property("can_focus", False)
119 self.graph_btn = gtk.Button('Graph')
120 self.graph_btn.connect("clicked", self.create_graphs_view)
121 self.graph_btn.set_property("can_focus", False)
123 self.refresh_btn = gtk.Button('Refresh')
124 self.refresh_btn.connect("clicked", self.refresh_stock_data)
125 self.refresh_btn.set_property("can_focus", False)
127 self.quotes_btn = gtk.Button('Quote')
128 self.quotes_btn.connect("clicked", self.show_quotes_view)
129 self.quotes_btn.set_property("can_focus", False)
131 self.toolbar.pack_start(self.markets_btn)
132 self.toolbar.pack_start(self.components_btn)
133 self.toolbar.pack_start(self.graph_btn)
134 self.toolbar.pack_start(self.quotes_btn)
135 self.toolbar.pack_start(self.refresh_btn)
137 self.mainbox = gtk.VBox()
141 self.swin = hildon.PannableArea()
143 self.swin = gtk.ScrolledWindow()
145 hildon.hildon_helper_set_thumb_scrollbar(self.swin, True)
146 self.swin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
147 self.swin.add_with_viewport(self.mainbox)
149 vbox.pack_start(self.swin, True, True, 0)
150 vbox.pack_start(gtk.HSeparator(), False, False, 5)
151 vbox.pack_start(self.toolbar, False, False, 0)
153 self.create_markets_view(self.mainbox)
154 self.window.add(vbox)
156 self.window.show_all()
158 def create_markets_view(self, widget):
163 actual_view = self.mainbox.get_children()
164 if len(actual_view) > 0:
165 for a_widget in actual_view:
168 self.marketsbox = gtk.VBox()
171 for i in range(lnames):
172 button = gtk.Button(names[i])
173 button.connect("clicked", self.create_components_view, ids[i])
174 button.set_size_request(-1, 65)
175 button.set_property("can_focus", False)
176 self.marketsbox.pack_start(button, True, True, 2)
178 self.mainbox.pack_start(self.marketsbox, True, True, 2)
179 self.mainbox.show_all()
181 def show_components_view(self, widget):
182 kind = self.market_id
183 self.create_components_view(widget, kind)
185 def create_components_view(self, widget, kind):
186 actual_view = self.mainbox.get_children()
187 for i in actual_view:
190 self.market_id = kind
192 self.components_btn.hide()
193 self.markets_btn.show()
194 self.refresh_btn.hide()
195 self.graph_btn.hide()
196 self.quotes_btn.hide()
198 names = localmarkets[idmarket.index(kind)]
199 ids = localids[idmarket.index(kind)]
201 self.compbox = gtk.VBox()
203 self.components_trv = gtk.TreeView()
204 self.components_trv.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_HORIZONTAL)
207 selection = self.components_trv.get_selection()
208 selection.connect("changed", self.changed_selection, ids)
210 self.components_trv.connect("row-activated", self.select_component, ids)
212 self.components_trv.set_rubber_banding(True)
213 self.components_trv.set_headers_visible(False)
214 self.components_model = self.__create_components_model()
215 self.components_trv.set_model(self.components_model)
216 self._components_trv_columns(self.components_trv)
217 self.add_initial_components(names, ids)
219 self.compbox.pack_start(self.components_trv, True, True, 0)
221 self.mainbox.pack_start(self.compbox, True, True, 0)
222 self.mainbox.show_all()
224 def select_component(self, widget, path, column, ids):
225 self.create_quotes_view(widget,self.components_model[path][1] )
227 def changed_selection(self, widget, ids):
228 n, i, m = self.get_selected_from_treeview(self.components_trv, self.components_model, 1)
230 self.create_quotes_view(widget, n)
232 def __create_components_model(self):
233 lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
236 def _components_trv_columns(self, treeview):
237 renderer = gtk.CellRendererText()
238 renderer.set_property('scale', 1.3)
239 #renderer.set_property("background", 'lightgray')
240 renderer.set_property("xpad", 15)
241 column = gtk.TreeViewColumn('Name', renderer, text=0)
242 column.set_expand(True)
243 treeview.append_column(column)
245 renderer = gtk.CellRendererText()
246 column = gtk.TreeViewColumn('IDS', renderer, text=1)
247 column.set_visible(False)
248 treeview.append_column(column)
250 def add_initial_components(self, kind, ids):
251 for i in range(len(kind)):
252 niter = self.components_model.append()
253 self.components_model.set(niter, 0, kind[i], 1, ids[i])
255 def get_selected_from_treeview(self, treeview, model, setting):
256 selection = treeview.get_selection()
257 selected_model, selected_iter = selection.get_selected()
259 selected_name = model.get_value(selected_iter, setting)
262 return selected_name, selected_iter, selected_model
264 def show_quotes_view(self, widget):
265 kind = self.stocks_id
266 self.create_quotes_view(widget, kind)
268 def create_quotes_view(self, widget, kind):
269 self.stocks_id = kind
271 self.components_btn.show()
272 self.markets_btn.show()
273 self.refresh_btn.show()
274 self.graph_btn.show()
275 self.quotes_btn.hide()
277 #actual_view = self.mainbox.get_children()
278 #actual_view[0].destroy()
281 self.graphbox.destroy()
285 for i in range(len(localids)):
286 if kind in localids[i]:
287 ind1, ind2 = i, localids[i].index(kind)
289 self.quotesbox = gtk.VBox()
291 self.titlelbl = gtk.Label('')
292 self.titlelbl.set_markup('<b><big>'+localmarkets[ind1][ind2].replace('&', '')+'</big></b>')
293 color = gtk.gdk.color_parse("#03A5FF")
294 self.titlelbl.modify_fg(gtk.STATE_NORMAL, color)
296 self.databox = gtk.VBox()
298 self.imagebox = gtk.VBox()
299 self.dataimg = gtk.Image()
300 self.imagebox.pack_start(self.dataimg)
306 label2 = gtk.Label('')
307 label2.set_markup('<b><big>Price:</big></b>')
308 self.lprice = gtk.Label('')
310 hbox1.pack_start(label2, False, False, 50)
311 hbox1.pack_start(self.lprice, False, False, 185)
315 label4 = gtk.Label('')
316 label4.set_markup('<b><big>Change:</big></b>')
317 self.lchange = gtk.Label('')
318 self.lpercent = gtk.Label('')
320 hbox2.pack_start(label4, False, False, 50)
321 hbox2.pack_start(self.lchange , False, False, 145)
322 hbox2.pack_start(self.lpercent, False, False, 0)
326 label7 = gtk.Label('')
327 label7.set_markup('<b><big>Volume:</big></b>')
328 self.lvolume = gtk.Label('')
330 hbox3.pack_start(label7, False, False, 50)
331 hbox3.pack_start(self.lvolume , False, False, 145)
335 label9 = gtk.Label('')
336 label9.set_markup('<b><big>52 week high:</big></b>')
337 self.l52whigh = gtk.Label('')
339 hbox4.pack_start(label9, False, False, 50)
340 hbox4.pack_start(self.l52whigh , False, False, 55)
344 label11 = gtk.Label('')
345 label11.set_markup('<b><big>52 week low:</big></b>')
346 self.l52wlow = gtk.Label('')
348 hbox5.pack_start(label11, False, False, 50)
349 hbox5.pack_start(self.l52wlow , False, False, 70)
351 self.databox.pack_start(hbox1, True, True, 0)
352 self.databox.pack_start(hbox2, True, True, 0)
353 self.databox.pack_start(hbox3, True, True, 0)
354 self.databox.pack_start(hbox4, True, True, 0)
355 self.databox.pack_start(hbox5, True, True, 0)
357 self.quotesbox.pack_start(self.titlelbl, False, False, 0)
358 self.quotesbox.pack_start(gtk.HSeparator(), False, False, 0)
359 self.quotesbox.pack_start(self.databox, True, True, 0)
360 self.quotesbox.pack_start(self.imagebox, True, True, 0)
362 self.mainbox.pack_start(self.quotesbox, True, True, 0)
363 self.mainbox.show_all()
367 def show_data(self, kind):
369 self.dataimg.set_from_file(loading_img)
372 thread.start_new_thread(self.get_data, (kind,))
374 def get_data(self, kind):
375 self.graph_btn.show()
376 self.refresh_btn.show()
377 self.quotes_btn.hide()
379 from ystockquote import ystockquote as yt
381 data = yt.get_all(kind)
383 print 'Failed to get internet data'
384 data = {'price': 'N/A', 'change': 'N/A', 'volume':'N/A',
385 '52_week_high': 'N/A', '52_week_low': 'N/A'}
386 self.titlelbl.set_markup('<b><big>Failed to get data</big></b>')
389 ch_percent = 100.0 * float(data['change'])/(float(data['price'])-float(data['change']))
393 self.lprice.set_label(data['price'])
394 self.lchange.set_label(data['change'])
395 self.lpercent.set_label('%6.2f %%' % ch_percent)
397 if '-' in data['change']:
398 color = gtk.gdk.color_parse("#FF0000")
400 color = gtk.gdk.color_parse("#16EB78")
402 self.lpercent.modify_fg(gtk.STATE_NORMAL, color)
403 self.lchange.modify_fg(gtk.STATE_NORMAL, color)
405 self.lvolume.set_label(data['volume'])
406 self.l52whigh.set_label(data['52_week_high'])
407 self.l52wlow.set_label(data['52_week_low'])
409 self.databox.show_all()
412 def refresh_stock_data(self, widget):
413 self.show_data(self.stocks_id)
415 def create_graphs_view(self, widget):
416 self.graph_btn.hide()
417 self.refresh_btn.hide()
418 self.quotes_btn.show()
420 self.graph = gtk.Image()
422 kind = self.stocks_id
424 self.show_graph(None, '1d', kind)
426 for i in range(len(localids)):
427 if kind in localids[i]:
428 ind1, ind2 = i, localids[i].index(kind)
430 #self.mainbox.destroy()
431 #self.mainbox = gtk.VBox()
432 #self.swin.add_with_viewport(self.mainbox)
434 actual_view = self.mainbox.get_children()
435 for a_widget in actual_view:
438 self.graphbox = gtk.VBox()
440 self.graphs_title = gtk.Label(localmarkets[ind1][ind2])
441 color = gtk.gdk.color_parse("#03A5FF")
442 self.graphs_title.modify_fg(gtk.STATE_NORMAL, color)
445 hbox1.set_size_request(-1, 55)
446 hbox1.set_homogeneous(True)
448 self.btn1d = gtk.Button('1d')
449 self.btn1d.set_property("can_focus", False)
450 self.btn1d.connect("clicked", self.show_graph, '1d', kind)
451 self.btn5d = gtk.Button('5d')
452 self.btn5d.set_property("can_focus", False)
453 self.btn5d.connect("clicked", self.show_graph, '5d', kind)
454 self.btn3m = gtk.Button('3m')
455 self.btn3m.set_property("can_focus", False)
456 self.btn3m.connect("clicked", self.show_graph, '3m', kind)
457 self.btn6m = gtk.Button('6m')
458 self.btn6m.set_property("can_focus", False)
459 self.btn6m.connect("clicked", self.show_graph, '6m', kind)
460 self.btn1y = gtk.Button('1y')
461 self.btn1y.set_property("can_focus", False)
462 self.btn1y.connect("clicked", self.show_graph, '1y', kind)
463 self.btn2y = gtk.Button('2y')
464 self.btn2y.set_property("can_focus", False)
465 self.btn2y.connect("clicked", self.show_graph, '2y', kind)
466 self.btn5y = gtk.Button('5y')
467 self.btn5y.set_property("can_focus", False)
468 self.btn5y.connect("clicked", self.show_graph, '5y', kind)
469 self.btnmax = gtk.Button('max')
470 self.btnmax.set_property("can_focus", False)
471 self.btnmax.connect("clicked", self.show_graph, 'max', kind)
473 hbox1.pack_start(self.btn1d)
474 hbox1.pack_start(self.btn5d)
475 hbox1.pack_start(self.btn3m)
476 hbox1.pack_start(self.btn6m)
477 hbox1.pack_start(self.btn1y)
478 hbox1.pack_start(self.btn2y)
479 hbox1.pack_start(self.btn5y)
480 hbox1.pack_start(self.btnmax)
482 self.graphbox.pack_start(self.graphs_title, False, False, 2)
483 self.graphbox.pack_start(hbox1, False, False, 0)
484 self.graphbox.pack_start(self.graph, True, True, 5)
486 self.mainbox.pack_start(self.graphbox, False, False, 2)
487 self.mainbox.show_all()
489 def show_graph(self, widget, option, kind):
491 self.graph.set_from_file(loading_img)
492 thread.start_new_thread(self.get_graph_data, (option, kind))
494 def get_graph_data(self, option, kind):
496 url = 'http://uk.ichart.yahoo.com/b?s=%s' % kind
498 url = 'http://uk.ichart.yahoo.com/w?s=%s' % kind
500 url = 'http://chart.finance.yahoo.com/c/3m/s/%s' % kind.lower()
502 url = 'http://chart.finance.yahoo.com/c/6m/s/%s' % kind.lower()
504 url = 'http://chart.finance.yahoo.com/c/1y/s/%s' % kind.lower()
506 url = 'http://chart.finance.yahoo.com/c/2y/s/%s' % kind.lower()
508 url = 'http://chart.finance.yahoo.com/c/5y/s/%s' % kind.lower()
509 elif option == 'max':
510 url = 'http://chart.finance.yahoo.com/c/my/s/%s' % kind.lower()
513 myimg = urllib2.urlopen(url)
516 pbl = gtk.gdk.PixbufLoader()
519 pbuf = pbl.get_pixbuf()
521 self.graph.set_from_pixbuf(pbuf)
523 print 'no internet data'
524 self.graphs_title.set_label('Failed to get data')
528 #Functions for fullscreen
529 def on_window_state_change(self, widget, event, *args):
530 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
531 self.window_in_fullscreen = True
533 self.window_in_fullscreen = False
535 #F6 fullscreen, F7 bigger font, F8 smaller font
536 def on_key_press(self, widget, event, *args):
537 if event.keyval == gtk.keysyms.F6:
538 if self.window_in_fullscreen:
539 self.window.unfullscreen ()
541 self.window.fullscreen ()
543 def on_about(self, widget):
544 dialog = gtk.AboutDialog()
545 dialog.set_name("StockThis")
546 dialog.set_version("0.2")
547 dialog.set_copyright("Copyright © 2009")
548 dialog.set_website("http://stockthis.garage.maemo.org")
549 dialog.set_authors(["Daniel Martin Yerga <dyerga@gmail.com>"])
550 logo = gtk.gdk.pixbuf_new_from_file(imgdir + "stockthis.png")
551 dialog.set_logo(logo)
552 dialog.set_license("This program is released under the GNU\nGeneral Public License. Please visit \nhttp://www.gnu.org/copyleft/gpl.html\nfor details.")
553 dialog.set_artists(["Logo by Daniel Martin Yerga"])
557 if __name__ == "__main__":
558 stockspy = StocksPy()
559 gtk.gdk.threads_enter()
561 gtk.gdk.threads_leave()