/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
* GData Client
* Copyright (C) Joe Cortes 2010 <escozzia@gmail.com>
*
* GData Client is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* GData Client 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This is an extremely simple example program to query youtube videos
* and picasa pictures and add them to a grid.
* It was coded as part of the 2010 Google Code-In.
* Click on Properties to change the window's title, or authenticate
* yourself (it's assumed that your google and picasa ids are the same)
* It's also possible to upload files to picasa.
* Since this is only an example, intended to serve as documentation,
* it's probably full of bugs and a couple of awful programming practices.
* The program itself is of no practical use, but it does what it is
* meant to do and doesn't segfault randomly (I hope so :p).
*/
#include "scrapbook.h"
static void
open_in_web_browser (GtkWidget *widget, gchar *uri) /* quicky wrapper for gtk_show_uri */
{
gtk_show_uri_on_window (GTK_WINDOW (gtk_widget_get_toplevel (widget)), uri, GDK_CURRENT_TIME, NULL);
}
static void
picture_selected (GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, ScrapPicSearch *self)
{
GtkTreeModel *model;
GtkTreeIter iter;
GDataEntry *pic;
GdkPixbuf *thumbnail;
GtkWidget *button;
GtkWidget *image;
pic = g_slice_new (GDataEntry);
model = gtk_tree_view_get_model (tree);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, COL_PIXBUF, &(thumbnail), P_COL_PIC, &(pic), -1);
gtk_widget_destroy (self->search_data->window);
gtk_list_store_append (self->main_data->lStore, &iter);
gtk_list_store_set (self->main_data->lStore, &iter,
ORIG_COL_PIXBUF, thumbnail,
ORIG_COL_TITLE, gdata_entry_get_title (pic),
ORIG_COL_ENTRY, pic, -1);
if (self->main_data->currentRow[self->main_data->currentCol] > self->main_data->max_rows) {
self->main_data->currentCol++;
self->main_data->currentRow[self->main_data->currentCol] = 0;
}
image = gtk_image_new_from_pixbuf (thumbnail);
button = gtk_button_new ();
self->file = GDATA_PICASAWEB_FILE (pic);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
/*g_signal_connect (button, "clicked", G_CALLBACK (open_in_web_browser), gdata_entry_get_id (pic));
* commented out, I can't seem to find anything that will give me a picture's URI */
gtk_grid_attach (GTK_GRID (self->main_data->grid), button,
self->main_data->currentCol,
self->main_data->currentRow[self->main_data->currentCol],
1, 1);
gtk_widget_show (button);
self->main_data->currentRow[self->main_data->currentCol]++;
}
static void
video_selected (GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *column, ScrapYTSearch *self)
{
GtkTreeModel *model;
GtkTreeIter iter;
GDataEntry *video;
GdkPixbuf *thumbnail;
GtkWidget *button;
GtkWidget *image;
video = g_slice_new (GDataEntry);
model = gtk_tree_view_get_model (tree);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, COL_PIXBUF, &(thumbnail), COL_VIDEO, &(video), -1);
gtk_widget_destroy (self->window);
gtk_list_store_append (self->main_data->lStore, &iter);
gtk_list_store_set (self->main_data->lStore, &iter,
ORIG_COL_PIXBUF, thumbnail,
ORIG_COL_TITLE, gdata_entry_get_title (video),
ORIG_COL_ENTRY, video, -1);
if (self->main_data->currentRow[self->main_data->currentCol] > self->main_data->max_rows) {
self->main_data->currentCol++;
self->main_data->currentRow[self->main_data->currentCol] = 0;
}
image = gtk_image_new_from_pixbuf (thumbnail);
button = gtk_button_new ();
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
g_signal_connect (button, "clicked", G_CALLBACK (open_in_web_browser),
(gpointer) gdata_youtube_video_get_player_uri (GDATA_YOUTUBE_VIDEO (video)));
gtk_grid_attach (GTK_GRID (self->main_data->grid), button,
self->main_data->currentCol,
self->main_data->currentRow[self->main_data->currentCol],
1, 1);
gtk_widget_show (button);
self->main_data->currentRow[self->main_data->currentCol]++;
}
static void
p_display_tree (ScrapPicSearch *self)
{
GtkCellRenderer *renderer;
GtkWidget *scrollWin;
scrollWin = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrollWin), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->tView), -1,
"", renderer, "pixbuf",
P_COL_PIXBUF, NULL);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->tView), -1,
"", renderer, "text",
P_COL_USER, NULL);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->tView), -1,
"", renderer, "text",
P_COL_TITLE, NULL);
gtk_tree_view_set_model (GTK_TREE_VIEW (self->tView), GTK_TREE_MODEL (self->lStore));
gtk_container_add (GTK_CONTAINER (scrollWin), self->tView);
g_signal_connect (self->tView, "row-activated", G_CALLBACK (picture_selected), self);
gtk_widget_show (self->tView);
gtk_widget_show (scrollWin);
gtk_box_pack_start (GTK_BOX(self->search_data->box1), scrollWin, TRUE, TRUE, 2);
}
static void
yt_display_tree (ScrapYTSearch *self)
{
GtkCellRenderer *renderer;
GtkWidget *scrollWin;
scrollWin = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrollWin), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->tView), -1,
"", renderer, "pixbuf",
COL_PIXBUF, NULL);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->tView), -1,
"", renderer, "text",
COL_TITLE, NULL);
gtk_tree_view_set_model (GTK_TREE_VIEW (self->tView), GTK_TREE_MODEL (self->lStore));
gtk_container_add (GTK_CONTAINER (scrollWin), self->tView);
g_signal_connect (self->tView, "row-activated", G_CALLBACK (video_selected), self);
gtk_widget_show (self->tView);
gtk_widget_show (scrollWin);
gtk_box_pack_start (GTK_BOX(self->box1), scrollWin, TRUE, TRUE, 2);
}
GDataMediaThumbnail *
choose_best_thumbnail (GList *thumbnails, gint ideal_size)
{
gint delta = G_MININT;
GDataMediaThumbnail *thumbnail = NULL;
for (; thumbnails != NULL; thumbnails = thumbnails->next) {
gint new_delta;
GDataMediaThumbnail *current = (GDataMediaThumbnail *) thumbnails->data;
new_delta = gdata_media_thumbnail_get_width (current) - ideal_size;
if (delta == 0) {
break;
} else if ((delta == G_MININT)
|| (delta < 0 && new_delta > delta)
|| (delta > 0 && new_delta < delta)) {
delta = new_delta;
thumbnail = current;
}
}
return thumbnail;
}
static void
find_pictures (GDataEntry *entry, guint entry_key, guint entry_count, ScrapPicSearch *self)
{
GtkTreeIter iter;
GList *thumbnails;
GDataMediaThumbnail *thumbnail;
GFileInputStream *input_stream;
gtk_list_store_append (self->lStore, &iter);
gtk_list_store_set (self->lStore, &iter,
P_COL_PIXBUF, NULL,
P_COL_TITLE, self->title,
P_COL_USER, self->user,
P_COL_PIC, entry, -1);
thumbnails = gdata_picasaweb_file_get_thumbnails (GDATA_PICASAWEB_FILE (entry));
thumbnail = choose_best_thumbnail (thumbnails, THUMBNAIL_WIDTH);
if (thumbnail != NULL) {
GFile *thumbnail_file;
thumbnail_file = g_file_new_for_uri (gdata_media_thumbnail_get_uri (thumbnail));
input_stream = g_file_read (thumbnail_file, NULL, NULL);
self->thumbnail = gdk_pixbuf_new_from_stream_at_scale (G_INPUT_STREAM (input_stream), THUMBNAIL_WIDTH, -1,
TRUE, NULL, NULL);
gtk_list_store_set (self->lStore, &iter, P_COL_PIXBUF, self->thumbnail, -1); /* we can now set the thumbnail ;) */
g_object_unref (thumbnail_file);
}
gdata_query_set_q (self->query, NULL);
}
static void
p_query_element (GDataEntry *entry, guint entry_key, guint entry_count, ScrapPSearch *self)
{
GError *error=NULL;
ScrapPicSearch *picture;
GDataFeed *feed;
picture = self->pic;
picture->title = gdata_entry_get_title (entry);
picture->query = picture->search_data->query;
picture->user = self->user;
gdata_query_set_q (picture->query, picture->title);
feed = gdata_picasaweb_service_query_files (self->main_data->picasaweb_service, GDATA_PICASAWEB_ALBUM (entry), picture->query, NULL,
(GDataQueryProgressCallback) find_pictures, picture, &error);
if (error != NULL) {
g_print ("whoops, somebody raised an error!\n%s", error->message);
g_error_free (error);
}
if (feed != NULL) {
g_object_unref (feed);
}
}
static void
p_text_callback (GtkWidget *widget, ScrapPSearch *self)
{
GError *error = NULL;
GDataFeed *feed;
self->user = gtk_entry_get_text (GTK_ENTRY (self->user_entry));
self->pic->tView = gtk_tree_view_new ();
feed = gdata_picasaweb_service_query_all_albums (self->main_data->picasaweb_service, self->query, self->user, NULL,
(GDataQueryProgressCallback) p_query_element, self, &error);
if (error != NULL) {
g_print ("someone raised an error\n%s\n",error->message);
g_error_free (error);
}
if (feed != NULL) {
g_object_unref (feed);
}
p_display_tree (self->pic);
}
/* ran as a callback for each individual element queried
* it takes the video found, a unique entry_key and entry_count and the data structure as arguments
* parts of this function were inspired (or simply taken) from the totem youtube plugin */
static void
yt_query_element (GDataEntry *entry, guint entry_key, guint entry_count, ScrapYTSearch *self)
{
GtkTreeIter iter;
GList *thumbnails;
GDataMediaThumbnail *thumbnail;
const gchar *title; /* the video's title */
const gchar *uri; /* the video's URI */
GFileInputStream *input_stream; /* this will be used to make a pixbuf to store the thumbnail */
title = gdata_entry_get_title (entry); /* self-explanatory, I hope */
uri = gdata_youtube_video_get_player_uri (GDATA_YOUTUBE_VIDEO (entry)); /* ditto */
g_print ("%s %s", title, uri);
gtk_list_store_append (self->lStore, &iter); /* make a new entry for this vid */
gtk_list_store_set (self->lStore, &iter,
COL_PIXBUF, NULL, /* this will be set in a few moments */
COL_TITLE, title,
COL_VIDEO, entry,
-1);
/* get a GList of thumbnails for the vid */
thumbnails = gdata_youtube_video_get_thumbnails (GDATA_YOUTUBE_VIDEO (entry));
thumbnail = choose_best_thumbnail (thumbnails, THUMBNAIL_WIDTH);
if (thumbnail != NULL) {
GFile *thumbnail_file;
thumbnail_file = g_file_new_for_uri (gdata_media_thumbnail_get_uri (thumbnail));
input_stream = g_file_read (thumbnail_file, NULL, NULL);
self->thumbnail = gdk_pixbuf_new_from_stream_at_scale (G_INPUT_STREAM (input_stream), THUMBNAIL_WIDTH, -1,
TRUE, NULL, NULL);
gtk_list_store_set (self->lStore, &iter, COL_PIXBUF, self->thumbnail, -1); /* we can now set the thumbnail ;) */
g_object_unref (thumbnail_file);
}
}
static void
yt_text_callback (GtkWidget *widget, ScrapYTSearch *self)
{
GDataFeed *feed;
self->txt = gtk_entry_get_text (GTK_ENTRY (self->txt_entry));
gdata_query_set_q (self->query, self->txt); /* set the string we'll be searching for in youtube */
/* do the actual query, running yt_query_element for each object found */
feed = gdata_youtube_service_query_videos (self->main_data->youtube_service, self->query, NULL, (GDataQueryProgressCallback) yt_query_element,
self, NULL);
if (feed != NULL) {
g_object_unref (feed);
}
yt_display_tree (self); /* run yt_display_tree to show the results */
}
static void
start_new_picasa_search (GtkWidget *widget, ScrapData *first)
{
ScrapPSearch *self;
ScrapPicSearch *picture;
GtkWidget *button, *box2;
self = first->p_search;
picture = first->pic_search;
picture->search_data = self;
picture->search_data->pic = picture;
picture->main_data = self->main_data;
g_assert (GDATA_IS_PICASAWEB_SERVICE (first->picasaweb_service));
gtk_list_store_clear (self->pic->lStore);
self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_resize (GTK_WINDOW (self->window), 400, 400);
g_signal_connect (self->window, "destroy", G_CALLBACK (gtk_widget_destroy), NULL);
g_signal_connect_swapped (self->window, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
/* our two boxes */
self->box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); /* this box contains everything in our window */
gtk_container_add (GTK_CONTAINER (self->window), self->box1);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
/* search bar */
self->user_entry = gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY (self->user_entry), "User to search for");
g_signal_connect (self->user_entry, "activate", (GCallback) p_text_callback, self);
gtk_box_pack_start (GTK_BOX(box2), self->user_entry, TRUE, TRUE, 0);
gtk_widget_show (self->user_entry);
/* Search button */
button = gtk_button_new_with_mnemonic ("_Search");
g_signal_connect (button, "clicked", (GCallback) p_text_callback, self);
gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 0);
gtk_widget_show (button);
gtk_box_pack_end (GTK_BOX (self->box1), box2, FALSE, FALSE, 0); /* pack the box with the button and search bar */
gtk_widget_show (box2);
gtk_widget_show (self->box1);
gtk_widget_show (self->window);
}
static void
start_new_youtube_search (GtkWidget *widget, ScrapData *first) /* *first is a pointer we use to talk to the main window */
{
ScrapYTSearch *self; /* this struct will be used for all the data in the search, if there's time I'll make it into a GObject */
GtkWidget *button, *box2;
self = first->yt_search;
gtk_list_store_clear (self->lStore); /* clear it out */
self->tView = gtk_tree_view_new ();
/* window stuff */
self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_resize (GTK_WINDOW (self->window), 400, 400);
g_signal_connect (self->window, "destroy", G_CALLBACK (gtk_widget_destroy), NULL);
g_signal_connect_swapped (self->window, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
/* our two boxes */
self->box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); /* this box contains everything in our window */
gtk_container_add (GTK_CONTAINER (self->window), self->box1);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
/* search bar */
self->txt_entry = gtk_entry_new ();
g_signal_connect (self->txt_entry, "activate", G_CALLBACK (yt_text_callback), self);
gtk_box_pack_start (GTK_BOX (box2), self->txt_entry, TRUE, TRUE, 0);
gtk_widget_show (self->txt_entry);
/* Search button */
button = gtk_button_new_with_mnemonic ("_Search");
g_signal_connect (button, "clicked", (GCallback) yt_text_callback, self);
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
gtk_box_pack_end (GTK_BOX (self->box1), box2, FALSE, FALSE, 0); /* pack the box with the button and search bar */
gtk_widget_show (box2);
gtk_widget_show (self->box1);
gtk_widget_show (self->window);
/* everything else is implemented somewhere else */
}
static void
properties_set (GtkWidget *widget, ScrapProps *self)
{
GDataClientLoginAuthorizer *authorizer;
GList *domains = NULL; /* list of GDataAuthorizationDomains */
GError *error = NULL;
/* Get the username and password to use */
self->main_data->username = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->username_entry)));
self->main_data->password = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->password_entry)));
/* Domains we need to be authorised for */
domains = g_list_prepend (domains, gdata_youtube_service_get_primary_authorization_domain ());
domains = g_list_prepend (domains, gdata_picasaweb_service_get_primary_authorization_domain ());
/* Authenticate */
authorizer = gdata_client_login_authorizer_new_for_authorization_domains (CLIENT_ID, domains);
gdata_client_login_authorizer_authenticate (authorizer, self->main_data->username, self->main_data->password, NULL, &error);
if (error != NULL) { /* we show this to the user in case they mistyped their password */
GtkWidget *label;
label = gtk_label_new (error->message);
gtk_widget_show (label);
gtk_box_pack_end (GTK_BOX (self->box1), label, FALSE, FALSE, 0);
g_print ("error\n%s\n", error->message);
g_error_free (error);
}
gdata_service_set_authorizer (GDATA_SERVICE (self->main_data->youtube_service), GDATA_AUTHORIZER (authorizer));
gdata_service_set_authorizer (GDATA_SERVICE (self->main_data->picasaweb_service), GDATA_AUTHORIZER (authorizer));
gtk_widget_destroy (self->window);
g_object_unref (authorizer);
}
static void
properties_show (GtkWidget *widget, ScrapData *first)
{
ScrapProps *self;
GtkWidget *label, *button, *box2;
self = g_slice_new (struct _ScrapProps);
self->main_data = first;
self->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (self->window, "destroy", G_CALLBACK (gtk_widget_destroy), NULL);
g_signal_connect (self->window, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
self->box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
/* Username/Password labels box */
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
label = gtk_label_new ("Username");
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (box2), label, TRUE, TRUE, 0);
label = gtk_label_new ("Password");
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (box2), label, TRUE, TRUE, 0);
gtk_widget_show (box2);
gtk_box_pack_start (GTK_BOX (self->box1), box2, FALSE, FALSE, 0);
/* Username/Password entries box */
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
self->username_entry = gtk_entry_new ();
if (self->main_data->username != NULL)
gtk_entry_set_text (GTK_ENTRY(self->username_entry), self->main_data->username);
gtk_widget_show (self->username_entry);
gtk_box_pack_start (GTK_BOX (box2), self->username_entry, TRUE, TRUE, 0);
self->password_entry = gtk_entry_new ();
gtk_entry_set_visibility (GTK_ENTRY (self->password_entry), FALSE);
if (self->main_data->password != NULL)
gtk_entry_set_text (GTK_ENTRY(self->password_entry), self->main_data->password);
gtk_widget_show (self->password_entry);
gtk_box_pack_start (GTK_BOX (box2), self->password_entry, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (self->box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* OK button */
button = gtk_button_new_with_label ("_OK");
g_signal_connect (button, "clicked", (GCallback) properties_set, self);
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (self->box1), button, FALSE, FALSE, 0);
gtk_widget_show (self->box1);
gtk_container_add (GTK_CONTAINER (self->window), self->box1);
gtk_widget_show (self->window);
}
static void
select_file (ScrapPUpload *self, GtkFileChooser *file_chooser)
{
GFile *file;
GError *error = NULL;
GFileInfo *file_info;
GDataUploadStream *upload_stream;
GFileInputStream *file_stream;
file = gtk_file_chooser_get_file (file_chooser);
file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
G_FILE_QUERY_INFO_NONE, NULL, NULL);
/* upload our file, using the service we've set up, and metadata
* set up in upload ()
* no album is specified, but that should be easy to add */
upload_stream = gdata_picasaweb_service_upload_file (self->main_data->picasaweb_service, NULL /* for now uploading to drop box */,
self->file, g_file_info_get_display_name (file_info),
g_file_info_get_content_type (file_info), NULL, &error);
g_object_unref (file_info);
g_object_unref (self->file);
self->file = NULL;
if (error != NULL) {
g_print ("Error: %s\n", error->message);
g_error_free (error);
g_object_unref (file);
return;
}
file_stream = g_file_read (file, NULL, NULL);
g_object_unref (file);
g_output_stream_splice (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (file_stream),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, NULL);
self->file = gdata_picasaweb_service_finish_file_upload (self->main_data->picasaweb_service, upload_stream, NULL);
g_object_unref (file_stream);
g_object_unref (upload_stream);
}
static void
got_name (GtkWidget *widget, ScrapData *scrap_data)
{
ScrapPUpload *self;
GtkWidget *file_dialog;
self = scrap_data->p_upload;
gdata_entry_set_title (GDATA_ENTRY (self->file),
gtk_entry_get_text (GTK_ENTRY (self->name)));
gdata_entry_set_summary (GDATA_ENTRY (self->file),
gtk_entry_get_text (GTK_ENTRY (self->description)));
gtk_widget_destroy (self->dialog);
file_dialog = gtk_file_chooser_dialog_new ("Upload Photo", GTK_WINDOW (scrap_data->window), GTK_FILE_CHOOSER_ACTION_SAVE,
"_Cancel", GTK_RESPONSE_CANCEL,
"_Open", GTK_RESPONSE_ACCEPT,
NULL);
if (gtk_dialog_run (GTK_DIALOG (file_dialog)) == GTK_RESPONSE_ACCEPT) {
select_file (self, GTK_FILE_CHOOSER (file_dialog));
}
/* since the upload blocks, it's safe to assume the widget won't
* be destroyed until we're done */
gtk_widget_destroy (file_dialog);
}
static void
upload (GtkWidget *widget, ScrapData *first)
{
ScrapPUpload *self;
GtkWidget *label, *content_area;
label = gtk_label_new ("Enter photo name and description");
self = first->p_upload;
/* we make a new file, without an id (it will be assigned automatically later on) */
self->file = gdata_picasaweb_file_new (NULL);
/* dialog to get the file's name and description */
self->dialog = gtk_dialog_new();
content_area = gtk_dialog_get_content_area (GTK_DIALOG (self->dialog));
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (content_area), label, FALSE, FALSE, 0);
self->name = gtk_entry_new ();
g_signal_connect (self->name, "activate", G_CALLBACK (got_name), self);
gtk_widget_show (self->name);
gtk_box_pack_start (GTK_BOX (content_area), self->name, TRUE, TRUE, 0);
self->description = gtk_entry_new ();
g_signal_connect (self->description, "activate", G_CALLBACK (got_name), first);
gtk_widget_show (self->description);
gtk_box_pack_start (GTK_BOX (content_area), self->description, TRUE, TRUE, 0);
gtk_widget_show (self->dialog);
}
int
main(int argc, char **argv)
{
ScrapData *scrapbook;
ScrapPSearch *picasaSearch;
ScrapYTSearch *youtubeSearch;
ScrapPicSearch *photoSearch;
ScrapPUpload *fUpload;
GtkWidget *button;
GtkWidget *vbox;
scrapbook = g_slice_new (struct _ScrapData);
scrapbook->max_rows = 5;
gtk_init (&argc, &argv);
scrapbook->currentCol = 0;
scrapbook->currentRow[scrapbook->currentCol] = 0;
scrapbook->lStore = gtk_list_store_new (ORIG_N_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDATA_TYPE_ENTRY);
scrapbook->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (scrapbook->window), "Scrapbook");
g_signal_connect (scrapbook->window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (scrapbook->window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
youtubeSearch = g_slice_new (struct _ScrapYTSearch); /* get some memory for the structure */
youtubeSearch->txt = NULL;
scrapbook->yt_search = youtubeSearch;
youtubeSearch->main_data = scrapbook;
/* create a new query, without any search text, starting at 0, and search only MAX_RESULTS results */
youtubeSearch->query = gdata_query_new_with_limits (NULL, 0, MAX_RESULTS);
/* create a new youtube service, giving it our developer key; google no longer uses client ids so we send in an empty string (NULL gives an error) */
scrapbook->youtube_service = gdata_youtube_service_new (DEVELOPER_KEY, NULL);
/* create a new list store and tree to show the user the results
* it has three columns (two of which are displayed): a pixbuf for the thumbnail, the title, and the video data itself (as a gdata generic entry) */
youtubeSearch->lStore = gtk_list_store_new (N_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDATA_TYPE_ENTRY);
picasaSearch = g_slice_new (struct _ScrapPSearch);
scrapbook->p_search = picasaSearch;
picasaSearch->main_data = scrapbook;
picasaSearch->query = gdata_query_new_with_limits (NULL, 0, MAX_RESULTS);
scrapbook->picasaweb_service = gdata_picasaweb_service_new (NULL);
photoSearch = g_slice_new (struct _ScrapPicSearch);
scrapbook->p_search->pic = photoSearch;
scrapbook->pic_search = photoSearch;
photoSearch->lStore = gtk_list_store_new (P_N_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, GDATA_TYPE_ENTRY);
fUpload = g_slice_new (struct _ScrapPUpload);
scrapbook->p_upload = fUpload;
fUpload->main_data = scrapbook;
scrapbook->box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
scrapbook->grid = gtk_grid_new ();
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
/* Add buttons to the main window */
button = gtk_button_new_with_mnemonic ("Add YouTube _Video");
g_signal_connect (button, "clicked", (GCallback) start_new_youtube_search, scrapbook);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
button = gtk_button_new_with_mnemonic ("Add PicasaWeb _Photo");
g_signal_connect (button, "clicked", (GCallback) start_new_picasa_search, scrapbook);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
button = gtk_button_new_with_mnemonic ("P_roperties");
g_signal_connect (button, "clicked", (GCallback) properties_show, scrapbook);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
button = gtk_button_new_with_mnemonic ("_Upload Photo to PicasaWeb");
g_signal_connect (button, "clicked", (GCallback) upload, scrapbook);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
gtk_widget_show (vbox);
gtk_box_pack_start (GTK_BOX (scrapbook->box1), vbox, FALSE, FALSE, 5);
gtk_box_pack_start (GTK_BOX (scrapbook->box1), scrapbook->grid, TRUE, TRUE, 0);
gtk_widget_show (scrapbook->grid);
gtk_widget_show (scrapbook->box1);
gtk_container_add (GTK_CONTAINER (scrapbook->window), scrapbook->box1);
gtk_widget_show (scrapbook->window);
gtk_main ();
return 0;
}