9 #include <hildon/hildon.h>
10 #include "lib-stock-home-widget.h"
11 #include "lib-stock-settings.h"
13 HD_DEFINE_PLUGIN_MODULE (StockPlugin, stock_plugin, HD_TYPE_HOME_PLUGIN_ITEM)
16 OnClickRefresh(GtkWidget *widget, GdkEventButton *event, StockPluginContext *psContext)
18 DebugOut(("OnClickRefresh"));
20 /* Disable button while getting latest stocks */
26 if(RetrieveStockPrice(psContext->hSG,psContext->psSettings->ppszTickers[0],&fPrice,NULL,&fChange) == SG_OK)
29 char *pszColour = NULL;
34 timeinfo = localtime(&rawtime);
35 strftime(szTime,80,"(%I:%M%p)",timeinfo);
37 /* Highlight the change in price */
43 /* Update to latest price */
45 "%s %.2f <span foreground=\"%s\">%.2f%%</span> <span foreground=\"grey\">%s</span>",
46 psContext->psSettings->ppszTickers[0],fPrice,pszColour,fChange,szTime);
48 gtk_label_set_markup(GTK_LABEL(psContext->psLabel),szBuffer);
49 gtk_widget_queue_draw(GTK_WIDGET(psContext->psParent));
52 If it fails, leave the old price as the user can see the timestamp
53 and know it's not up-to-date. So just notify them of the failure.
57 hildon_banner_show_information(GTK_WIDGET(widget),NULL,"Failed to retrieve stock information, check ticker symbol and try again.");
63 UpdateStockOnTimeout(gpointer data)
65 StockPluginContext *psContext = (StockPluginContext*)data;
67 DebugOut(("UpdateStockOnTimeout"));
72 /* If no longer a timeout, don't do anything and stop */
73 if(!psContext->psSettings->uiUpdateTime)
76 /* Update stock price */
77 OnClickRefresh(GTK_WIDGET(psContext->psLabel),NULL,psContext);
82 stock_show_settings_dialog(GtkWidget* widget, gpointer data)
84 StockPluginContext *psContext = (StockPluginContext*)data;
88 GtkWidget *addselector;
90 GtkWidget *timeselector;
91 GtkWidget *timebutton;
93 DebugOut(("stock_show_settings_dialog"));
95 /* Stop timer while settings are one */
96 if(psContext->nTimerID != -1)
98 g_source_remove(psContext->nTimerID);
99 psContext->nTimerID = -1;
102 dialog = gtk_dialog_new_with_buttons("Settings",NULL,0,"Save",GTK_RESPONSE_ACCEPT,NULL);
103 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
104 group = GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL));
106 /* Add new stock symbol */
110 addbutton = hildon_picker_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
111 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
113 addselector = hildon_touch_selector_entry_new_text();
115 for(i=0; i < psContext->psSettings->uiNumTickers; i++)
117 hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(addselector),psContext->psSettings->ppszTickers[i]);
120 /* First ticker in ppszTickers is the chosen one */
121 hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(addselector), 0, 0);
123 hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (addbutton), HILDON_TOUCH_SELECTOR (addselector));
125 hildon_button_set_title(HILDON_BUTTON(addbutton), "Select Ticker");
128 /* Set auto update time */
133 char *aszUpdateTimes[] =
142 timebutton = hildon_picker_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
143 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
145 timeselector = hildon_touch_selector_new_text();
147 for(i=0; i < sizeof(aszUpdateTimes)/sizeof(aszUpdateTimes[0]); i++)
149 hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(timeselector),aszUpdateTimes[i]);
152 switch(psContext->psSettings->uiUpdateTime)
154 case 0: sel = 0; break;
155 case 1: sel = 1; break;
156 case 15: sel = 2; break;
157 case 30: sel = 3; break;
158 case 60: sel = 4; break;
161 hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(timeselector), 0, sel);
162 hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (timebutton), HILDON_TOUCH_SELECTOR (timeselector));
163 hildon_button_set_title(HILDON_BUTTON(timebutton), "Automatic Update Period");
166 gtk_container_add(GTK_CONTAINER(content),addbutton);
167 gtk_container_add(GTK_CONTAINER(content),timebutton);
168 gtk_widget_show_all(dialog);
170 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
172 const char *pszNewTicker;
173 char aszOldTicker[255]={0};
174 guint uiUpdateSelection = 0;
176 /* Only perform ops if they actually changed the ticker */
177 if(strcmp(aszOldTicker,psContext->psSettings->ppszTickers[0]))
179 /* Save off old ticker */
180 strcpy(aszOldTicker,psContext->psSettings->ppszTickers[0]);
183 pszNewTicker = hildon_button_get_value(HILDON_BUTTON(addbutton));
185 /* Check if ticker already exists */
188 gboolean bFound = FALSE;
190 /* Check it doesn't exist already */
191 for(i=0; i < psContext->psSettings->uiNumTickers; i++)
193 if(!strcmp(pszNewTicker,psContext->psSettings->ppszTickers[i]))
200 /* If they just chose another one, just swap the pointers so new one is at the top:
204 /* Swapped ith and 0th element */
205 char *psTmp = psContext->psSettings->ppszTickers[i];
206 psContext->psSettings->ppszTickers[i] = psContext->psSettings->ppszTickers[0];
207 psContext->psSettings->ppszTickers[0] = psTmp;
209 DebugOut(("Swapped ticker %d (%s) with 0 (%s)",
211 psContext->psSettings->ppszTickers[i],
212 psContext->psSettings->ppszTickers[0]));
214 /* If it doesn't add it to the list, placing chosen one at the front */
217 gchar **ppszTickers = g_malloc0(sizeof(char*) * (psContext->psSettings->uiNumTickers+2));
219 /* Place the selected one first */
220 ppszTickers[0] = g_strdup(pszNewTicker);
222 /* Copy across old tickers */
223 for(i=0; i < psContext->psSettings->uiNumTickers; i++)
225 /* offset by one as the selected one is first */
226 ppszTickers[i+1] = g_strdup(psContext->psSettings->ppszTickers[i]);
229 /* Free current array */
230 g_strfreev(psContext->psSettings->ppszTickers);
232 /* Assign new array */
233 psContext->psSettings->ppszTickers = ppszTickers;
236 psContext->psSettings->uiNumTickers++;
240 /* Force a refresh as the ticker changed */
241 OnClickRefresh(GTK_WIDGET(psContext->psLabel),NULL,psContext);
244 uiUpdateSelection = hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(timeselector),0);
246 switch(uiUpdateSelection)
249 case 0: psContext->psSettings->uiUpdateTime = 0; break;
250 case 1: psContext->psSettings->uiUpdateTime = 1; break;
251 case 2: psContext->psSettings->uiUpdateTime = 15; break;
252 case 3: psContext->psSettings->uiUpdateTime = 30; break;
253 case 4: psContext->psSettings->uiUpdateTime = 60; break;
256 if(psContext->psSettings->uiUpdateTime != 0)
258 /* Remove previous timeout if there was one */
259 if(psContext->nTimerID != -1)
261 g_source_remove(psContext->nTimerID);
264 /* Add timer (in seconds) */
265 psContext->nTimerID = g_timeout_add_seconds(psContext->psSettings->uiUpdateTime * 60,
266 UpdateStockOnTimeout,
271 stock_save_settings(psContext->psSettings);
274 gtk_widget_destroy (dialog);
277 static GtkWidget *stock_create_gui(gchar *pszStockLabel,
278 StockPluginContext *psContext)
283 DebugOut(("stock_create_gui"));
285 label = gtk_label_new(pszStockLabel);
286 eventbox = gtk_event_box_new();
288 gtk_event_box_set_visible_window(GTK_EVENT_BOX(eventbox),FALSE);
289 gtk_container_set_border_width(GTK_CONTAINER(eventbox),10);
291 gtk_container_add(GTK_CONTAINER(eventbox),label);
293 g_signal_connect(GTK_CONTAINER(eventbox),"button-press-event",G_CALLBACK(OnClickRefresh),(gpointer)psContext);
296 gtk_widget_show_all(GTK_WIDGET(eventbox));
298 psContext->psLabel = label;
299 psContext->psEventBox = eventbox;
305 stock_plugin_finalize (GObject *object)
307 StockPluginContext *psContext = ((StockPlugin*)object)->context;
309 DebugOut(("stock_plugin_finalize"));
313 if(psContext->psSettings)
315 if(psContext->psSettings)
316 g_free(psContext->psSettings->iD);
318 stock_free_settings(psContext->psSettings);
319 g_free(psContext->psSettings);
322 if(psContext->nTimerID != -1)
324 g_source_remove(psContext->nTimerID);
325 psContext->nTimerID = -1;
329 FreeStockGetter(psContext->hSG);
336 stock_plugin_init (StockPlugin *desktop_plugin)
338 StockPluginContext *psContext;
341 DebugOut(("stock_plugin_init"));
343 hSG = InitStockGetter();
350 /* Create plugin context */
351 psContext = g_new0(StockPluginContext,1);
353 /* Always create a settings */
354 psContext->psSettings = g_new0(StockPluginSettings,1);
355 psContext->psSettings->iD = g_strdup(STOCK_PLUGIN_APPLET_ID);
357 /* Attempt to load settings (defaulted if not present) */
358 stock_read_settings(psContext->psSettings);
360 /* Create GUI widget interface (and sets links in context) */
361 stock_create_gui("Click to Update",psContext);
363 gtk_container_add(GTK_CONTAINER(desktop_plugin), psContext->psEventBox);
365 psContext->hSG = hSG;
366 psContext->nTimerID = -1;
367 psContext->psParent = GTK_WIDGET(desktop_plugin);
369 /* Assign private data to plugin */
370 desktop_plugin->context = psContext;
372 /* Remove previous timeout if there was one */
373 if(psContext->nTimerID != -1)
375 g_source_remove(psContext->nTimerID);
378 /* Setup new one if required */
379 if(psContext->psSettings->uiUpdateTime > 0)
381 psContext->nTimerID = g_timeout_add_seconds(psContext->psSettings->uiUpdateTime * 60,
382 UpdateStockOnTimeout,
386 /* Show a settings button */
387 hd_home_plugin_item_set_settings (HD_HOME_PLUGIN_ITEM (desktop_plugin), TRUE);
389 /* Connect to the settings button */
390 g_signal_connect(desktop_plugin, "show-settings", G_CALLBACK(stock_show_settings_dialog), psContext);
394 stock_plugin_realize(GtkWidget* widget)
396 GdkScreen *screen = gtk_widget_get_screen(widget);
397 gtk_widget_set_colormap(widget, gdk_screen_get_rgba_colormap(screen));
398 gtk_widget_set_app_paintable(widget, TRUE);
399 GTK_WIDGET_CLASS(stock_plugin_parent_class)->realize(widget);
403 cairo_rounded_rectangle(cairo_t *cr,
411 double corner_radius = height / corner_div;
412 double radius = corner_radius / aspect;
413 double degrees = 3.14159265 / 180.0;
415 cairo_new_sub_path (cr);
416 cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
417 cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
418 cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
419 cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
420 cairo_close_path (cr);
422 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.25);
423 cairo_fill_preserve (cr);
424 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
425 cairo_set_line_width (cr, 1.0);
430 stock_plugin_expose(GtkWidget* widget, GdkEventExpose *event)
435 GdkRectangle *psRect;
437 cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
439 psRect = &event->area;
441 width = psRect->width;
442 height = psRect->height;
444 DebugOut(("X: %d Y: %d Width: %d Height %d",psRect->x,psRect->y,psRect->width,psRect->height));
446 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.5);
448 cairo_rounded_rectangle(cr, 0, 0, width, height, 10.0);
450 cairo_rectangle(cr, 0, 0, width, height);
455 return GTK_WIDGET_CLASS(stock_plugin_parent_class)->expose_event(widget, event);
459 stock_plugin_class_init (StockPluginClass *klass)
461 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
462 widget_class->realize = stock_plugin_realize;
463 widget_class->expose_event = stock_plugin_expose;
464 G_OBJECT_CLASS(klass)->finalize = stock_plugin_finalize;
468 stock_plugin_class_finalize (StockPluginClass *klass)