--- /dev/null
+/*
+ * Simple stock widget
+ * Jon Parr
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <string.h>
+#include <hildon/hildon.h>
+#include "lib-stock-home-widget.h"
+#include "lib-stock-settings.h"
+
+HD_DEFINE_PLUGIN_MODULE (StockPlugin, stock_plugin, HD_TYPE_HOME_PLUGIN_ITEM)
+
+static void
+OnClickRefresh(GtkWidget *widget, StockPluginContext *psContext)
+{
+ DebugOut(("OnClickRefresh"));
+
+ /* Disable button while getting latest stocks */
+ gtk_widget_set_sensitive(GTK_WIDGET(psContext->psButton),FALSE);
+ {
+ float fPrice;
+ float fChange;
+ char szBuffer[1024];
+
+ if(RetrieveStockPrice(psContext->hSG,psContext->psSettings->ppszTickers[0],&fPrice,NULL,&fChange) == SG_OK)
+ {
+ char szTime[80];
+ time_t rawtime;
+ struct tm *timeinfo;
+
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+ strftime(szTime,80,"(%I:%M%p)",timeinfo);
+
+ /* Update to latest price */
+ sprintf(szBuffer,"%s %.2f %.2f%% %s",psContext->psSettings->ppszTickers[0],fPrice,fChange,szTime);
+
+ hildon_button_set_title(HILDON_BUTTON(psContext->psButton),szBuffer);
+ gtk_widget_queue_draw(GTK_WIDGET(psContext->psBox));
+ }
+ /*
+ If it fails, leave the old price as the user can see the timestamp
+ and know it's not up-to-date. So just notify them of the failure.
+ */
+ else
+ {
+ hildon_banner_show_information(GTK_WIDGET(widget),NULL,"Failed to retrieve stock information, check ticker symbol and try again.");
+ }
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(psContext->psButton),TRUE);
+}
+
+static gboolean
+UpdateStockOnTimeout(gpointer data)
+{
+ StockPluginContext *psContext = (StockPluginContext*)data;
+
+ DebugOut(("UpdateStockOnTimeout"));
+
+ if(!psContext)
+ return FALSE;
+
+ /* If no longer a timeout, don't do anything and stop */
+ if(!psContext->psSettings->uiUpdateTime)
+ return FALSE;
+
+ /* Update stock price */
+ OnClickRefresh(GTK_WIDGET(psContext->psButton),psContext);
+ return TRUE;
+}
+
+static void
+stock_show_settings_dialog(GtkWidget* widget, gpointer data)
+{
+ StockPluginContext *psContext = (StockPluginContext*)data;
+ GtkWidget *dialog;
+ GtkWidget *content;
+ GtkSizeGroup *group;
+ GtkWidget *addselector;
+ GtkWidget *addbutton;
+ GtkWidget *timeselector;
+ GtkWidget *timebutton;
+
+ DebugOut(("stock_show_settings_dialog"));
+
+ /* Stop timer while settings are one */
+ if(psContext->nTimerID != -1)
+ {
+ g_source_remove(psContext->nTimerID);
+ psContext->nTimerID = -1;
+ }
+
+ dialog = gtk_dialog_new_with_buttons("Settings",NULL,0,"Save",GTK_RESPONSE_ACCEPT,NULL);
+ content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ group = GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL));
+
+ /* Add new stock symbol */
+ {
+ int i;
+
+ addbutton = hildon_picker_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
+ HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
+
+ addselector = hildon_touch_selector_entry_new_text();
+
+ for(i=0; i < psContext->psSettings->uiNumTickers; i++)
+ {
+ hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(addselector),psContext->psSettings->ppszTickers[i]);
+ }
+
+ /* First ticker in ppszTickers is the chosen one */
+ hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(addselector), 0, 0);
+
+ hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (addbutton), HILDON_TOUCH_SELECTOR (addselector));
+
+ hildon_button_set_title(HILDON_BUTTON(addbutton), "Select Ticker");
+ }
+
+ /* Set auto update time */
+ {
+ int i;
+ int sel = 0;
+
+ char *aszUpdateTimes[] =
+ {
+ "No update",
+ "1 minute",
+ "15 minutes",
+ "30 minutes",
+ "1 hour"
+ };
+
+ timebutton = hildon_picker_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
+ HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
+
+ timeselector = hildon_touch_selector_new_text();
+
+ for(i=0; i < sizeof(aszUpdateTimes)/sizeof(aszUpdateTimes[0]); i++)
+ {
+ hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(timeselector),aszUpdateTimes[i]);
+ }
+
+ switch(psContext->psSettings->uiUpdateTime)
+ {
+ case 0: sel = 0; break;
+ case 1: sel = 1; break;
+ case 15: sel = 2; break;
+ case 30: sel = 3; break;
+ case 60: sel = 4; break;
+ }
+
+ hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(timeselector), 0, sel);
+ hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (timebutton), HILDON_TOUCH_SELECTOR (timeselector));
+ hildon_button_set_title(HILDON_BUTTON(timebutton), "Automatic Update Period");
+ }
+
+ gtk_container_add(GTK_CONTAINER(content),addbutton);
+ gtk_container_add(GTK_CONTAINER(content),timebutton);
+ gtk_widget_show_all(dialog);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+ {
+ const char *pszNewTicker;
+ char aszOldTicker[255]={0};
+ guint uiUpdateSelection = 0;
+
+ /* Only perform ops if they actually changed the ticker */
+ if(strcmp(aszOldTicker,psContext->psSettings->ppszTickers[0]))
+ {
+ /* Save off old ticker */
+ strcpy(aszOldTicker,psContext->psSettings->ppszTickers[0]);
+
+ /* Get new ticker */
+ pszNewTicker = hildon_button_get_value(HILDON_BUTTON(addbutton));
+
+ /* Check if ticker already exists */
+ {
+ int i;
+ gboolean bFound = FALSE;
+
+ /* Check it doesn't exist already */
+ for(i=0; i < psContext->psSettings->uiNumTickers; i++)
+ {
+ if(!strcmp(pszNewTicker,psContext->psSettings->ppszTickers[i]))
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ /* If they just chose another one, just swap the pointers so new one is at the top:
+ */
+ if(bFound)
+ {
+ /* Swapped ith and 0th element */
+ char *psTmp = psContext->psSettings->ppszTickers[i];
+ psContext->psSettings->ppszTickers[i] = psContext->psSettings->ppszTickers[0];
+ psContext->psSettings->ppszTickers[0] = psTmp;
+
+ DebugOut(("Swapped ticker %d (%s) with 0 (%s)",
+ i,
+ psContext->psSettings->ppszTickers[i],
+ psContext->psSettings->ppszTickers[0]));
+ }
+ /* If it doesn't add it to the list, placing chosen one at the front */
+ else
+ {
+ gchar **ppszTickers = g_malloc0(sizeof(char*) * (psContext->psSettings->uiNumTickers+2));
+
+ /* Place the selected one first */
+ ppszTickers[0] = g_strdup(pszNewTicker);
+
+ /* Copy across old tickers */
+ for(i=0; i < psContext->psSettings->uiNumTickers; i++)
+ {
+ /* offset by one as the selected one is first */
+ ppszTickers[i+1] = g_strdup(psContext->psSettings->ppszTickers[i]);
+ }
+
+ /* Free current array */
+ g_strfreev(psContext->psSettings->ppszTickers);
+
+ /* Assign new array */
+ psContext->psSettings->ppszTickers = ppszTickers;
+
+ /* Update count */
+ psContext->psSettings->uiNumTickers++;
+ }
+ }
+
+ /* Force a refresh as the ticker changed */
+ OnClickRefresh(GTK_WIDGET(psContext->psButton),psContext);
+ }
+
+ uiUpdateSelection = hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(timeselector),0);
+
+ switch(uiUpdateSelection)
+ {
+ /* No update */
+ case 0: psContext->psSettings->uiUpdateTime = 0; break;
+ case 1: psContext->psSettings->uiUpdateTime = 1; break;
+ case 2: psContext->psSettings->uiUpdateTime = 15; break;
+ case 3: psContext->psSettings->uiUpdateTime = 30; break;
+ case 4: psContext->psSettings->uiUpdateTime = 60; break;
+ }
+
+ if(psContext->psSettings->uiUpdateTime != 0)
+ {
+ /* Remove previous timeout if there was one */
+ if(psContext->nTimerID != -1)
+ {
+ g_source_remove(psContext->nTimerID);
+ }
+
+ /* Add timer (in seconds) */
+ psContext->nTimerID = g_timeout_add_seconds(psContext->psSettings->uiUpdateTime * 60,
+ UpdateStockOnTimeout,
+ psContext);
+ }
+
+ /* Save Settings */
+ stock_save_settings(psContext->psSettings);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static GtkWidget *stock_create_gui(gchar *pszStockLabel,
+ StockPluginContext *psContext)
+{
+ HildonButton *psButton = NULL;
+
+ DebugOut(("stock_create_gui"));
+
+ psButton = (HildonButton*)hildon_button_new_with_text (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
+ HILDON_BUTTON_ARRANGEMENT_VERTICAL,
+ pszStockLabel,
+ NULL);
+
+ psContext->psButton = psButton;
+
+ /* Setup button click signal for refreshing stocks */
+ gtk_signal_connect (GTK_OBJECT(psButton),"clicked",GTK_SIGNAL_FUNC(OnClickRefresh),(gpointer)psContext);
+
+ /* Display */
+ gtk_widget_show_all(GTK_WIDGET(psButton));
+
+ return GTK_WIDGET(psButton);
+}
+
+static void
+stock_plugin_finalize (GObject *object)
+{
+ StockPluginContext *psContext = ((StockPlugin*)object)->context;
+
+ DebugOut(("stock_plugin_finalize"));
+
+ if(psContext)
+ {
+ if(psContext->psSettings)
+ {
+ if(psContext->psSettings)
+ g_free(psContext->psSettings->iD);
+
+ stock_free_settings(psContext->psSettings);
+ g_free(psContext->psSettings);
+ }
+
+ if(psContext->nTimerID != -1)
+ {
+ g_source_remove(psContext->nTimerID);
+ psContext->nTimerID = -1;
+ }
+
+ if(psContext->hSG)
+ FreeStockGetter(psContext->hSG);
+
+ g_free(psContext);
+ }
+}
+
+static void
+stock_plugin_init (StockPlugin *desktop_plugin)
+{
+ StockPluginContext *psContext;
+ SGHandle hSG;
+
+ DebugOut(("stock_plugin_init"));
+
+ hSG = InitStockGetter();
+
+ if(!hSG)
+ {
+ return;
+ }
+
+ /* Create plugin context */
+ psContext = g_new0(StockPluginContext,1);
+
+ /* Always create a settings */
+ psContext->psSettings = g_new0(StockPluginSettings,1);
+ psContext->psSettings->iD = g_strdup(STOCK_PLUGIN_APPLET_ID);
+
+ /* Attempt to load settings (defaulted if not present) */
+ stock_read_settings(psContext->psSettings);
+
+ /* Create GUI widget interface (and sets links in context) */
+ psContext->psBox = stock_create_gui("Click to Update",psContext);
+
+ gtk_container_add (GTK_CONTAINER (desktop_plugin), psContext->psBox);
+
+ psContext->hSG = hSG;
+ psContext->nTimerID = -1;
+
+ /* Assign private data to plugin */
+ desktop_plugin->context = psContext;
+
+ /* Remove previous timeout if there was one */
+ if(psContext->nTimerID != -1)
+ {
+ g_source_remove(psContext->nTimerID);
+ }
+
+ /* Setup new one if required */
+ if(psContext->psSettings->uiUpdateTime > 0)
+ {
+ psContext->nTimerID = g_timeout_add_seconds(psContext->psSettings->uiUpdateTime * 60,
+ UpdateStockOnTimeout,
+ psContext);
+ }
+
+ /* Show a settings button */
+ hd_home_plugin_item_set_settings (HD_HOME_PLUGIN_ITEM (desktop_plugin), TRUE);
+
+ /* Connect to the settings button */
+ g_signal_connect(desktop_plugin, "show-settings", G_CALLBACK(stock_show_settings_dialog), psContext);
+}
+
+static void
+stock_plugin_class_init (StockPluginClass *klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = stock_plugin_finalize;
+}
+
+static void
+stock_plugin_class_finalize (StockPluginClass *klass)
+{
+}