From 973aaa9d9a020e1644ce2fe45fd3613422f6ada9 Mon Sep 17 00:00:00 2001 From: Alan Fitton Date: Thu, 17 Feb 2011 09:45:23 +0000 Subject: a bunch of changes needed to facilitate changing trackers (unfinished). also tidy up general details panel a bit, fix a crash if a stats update is received after stats dialog is closed. --- configure.ac | 4 +- redhat/transmission-remote-gtk.spec | 2 +- src/torrent.c | 5 ++ src/torrent.h | 1 + src/trg-client.c | 10 +++ src/trg-client.h | 2 + src/trg-general-panel.c | 58 ++++++++------- src/trg-main-window.c | 18 ++--- src/trg-menu-bar.c | 1 - src/trg-menu-bar.h | 2 + src/trg-model.c | 40 +++++++++++ src/trg-model.h | 5 +- src/trg-peers-model.c | 1 - src/trg-stats-dialog.c | 10 ++- src/trg-status-bar.c | 2 +- src/trg-status-bar.h | 2 +- src/trg-torrent-model.c | 54 ++------------ src/trg-torrent-model.h | 10 +-- src/trg-trackers-model.c | 17 ++++- src/trg-trackers-model.h | 6 +- src/trg-trackers-tree-view.c | 140 +++++++++++++++++++++++++++++++++++- src/trg-trackers-tree-view.h | 4 +- src/trg-tree-view.c | 4 +- src/trg-tree-view.h | 2 +- 24 files changed, 288 insertions(+), 112 deletions(-) diff --git a/configure.ac b/configure.ac index 0dcf36a..e4c01e5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ #AC_PREREQ([2.65]) -AC_INIT(transmission-remote-gtk, 0.1.1, alan@eth0.org.uk) -AM_INIT_AUTOMAKE(transmission-remote-gtk, 0.1.1) +AC_INIT(transmission-remote-gtk, 0.1.2, alan@eth0.org.uk) +AM_INIT_AUTOMAKE(transmission-remote-gtk, 0.1.2) AC_OUTPUT(Makefile src/Makefile) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) diff --git a/redhat/transmission-remote-gtk.spec b/redhat/transmission-remote-gtk.spec index 2e912f7..1c99129 100644 --- a/redhat/transmission-remote-gtk.spec +++ b/redhat/transmission-remote-gtk.spec @@ -1,5 +1,5 @@ Name: transmission-remote-gtk -Version: 0.1.1 +Version: 0.1.2 Release: 1%{?dist:%{dist}} Summary: Remote control client for Transmission BitTorrent diff --git a/src/torrent.c b/src/torrent.c index 9ecb354..d6fcde2 100644 --- a/src/torrent.c +++ b/src/torrent.c @@ -208,6 +208,11 @@ gchar *torrent_get_status_string(gint64 value) } } +gint64 tracker_get_id(JsonObject *t) +{ + return json_object_get_int_member(t, FIELD_ID); +} + gint64 tracker_get_tier(JsonObject * t) { return json_object_get_int_member(t, FIELD_TIER); diff --git a/src/torrent.h b/src/torrent.h index bfac5a6..093759f 100644 --- a/src/torrent.h +++ b/src/torrent.h @@ -51,6 +51,7 @@ JsonArray *torrent_get_wanted(JsonObject * t); JsonArray *torrent_get_priorities(JsonObject * t); gint64 torrent_get_id(JsonObject * t); gint64 tracker_get_tier(JsonObject * t); +gint64 tracker_get_id(JsonObject *t); const gchar *tracker_get_announce(JsonObject * t); const gchar *tracker_get_scrape(JsonObject * t); JsonArray *torrent_get_files(JsonObject * args); diff --git a/src/trg-client.c b/src/trg-client.c index 97462bb..bb8dd68 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -37,6 +37,16 @@ trg_client *trg_init_client() #define check_for_error(error) if (error) { g_error_free(error); return TRG_GCONF_SCHEMA_ERROR; } +void trg_client_set_session(trg_client *tc, JsonObject *session) +{ + if (tc->session != NULL) + json_object_unref(tc->session); + + session_get_version(session, &(tc->version)); + + tc->session = session; +} + int trg_client_populate_with_settings(trg_client * tc, GConfClient * gconf) { gint port; diff --git a/src/trg-client.h b/src/trg-client.h index 2fbcad9..51f3100 100644 --- a/src/trg-client.h +++ b/src/trg-client.h @@ -34,6 +34,7 @@ typedef struct { gint64 updateSerial; JsonObject *session; gboolean ssl; + float version; char *url; char *username; char *password; @@ -45,5 +46,6 @@ typedef struct { trg_client *trg_init_client(); int trg_client_populate_with_settings(trg_client * tc, GConfClient * gconf); +void trg_client_set_session(trg_client *tc, JsonObject *session); #endif /* TRG_CLIENT_H_ */ diff --git a/src/trg-general-panel.c b/src/trg-general-panel.c index 7d6525f..b52347f 100644 --- a/src/trg-general-panel.c +++ b/src/trg-general-panel.c @@ -92,32 +92,31 @@ void trg_general_panel_update(TrgGeneralPanel * panel, JsonObject * t, sizeOfBuf = sizeof(buf); - tr_strlsize(buf, torrent_get_size(t), sizeOfBuf); + trg_strlsize(buf, torrent_get_size(t)); gtk_label_set_text(GTK_LABEL(priv->gen_size_label), buf); - tr_strlspeed(buf, torrent_get_rate_down(t) / KILOBYTE_FACTOR, - sizeOfBuf); + trg_strlspeed(buf, torrent_get_rate_down(t) / KILOBYTE_FACTOR); gtk_label_set_text(GTK_LABEL(priv->gen_down_rate_label), buf); - tr_strlspeed(buf, torrent_get_rate_up(t) / KILOBYTE_FACTOR, sizeOfBuf); + trg_strlspeed(buf, torrent_get_rate_up(t) / KILOBYTE_FACTOR); gtk_label_set_text(GTK_LABEL(priv->gen_up_rate_label), buf); - tr_strlsize(buf, torrent_get_uploaded(t), sizeOfBuf); + trg_strlsize(buf, torrent_get_uploaded(t)); gtk_label_set_text(GTK_LABEL(priv->gen_uploaded_label), buf); - tr_strlsize(buf, torrent_get_downloaded(t), sizeOfBuf); + trg_strlsize(buf, torrent_get_downloaded(t)); gtk_label_set_text(GTK_LABEL(priv->gen_downloaded_label), buf); - tr_strlratio(buf, + trg_strlratio(buf, (double) torrent_get_uploaded(t) / - (double) torrent_get_downloaded(t), sizeOfBuf); + (double) torrent_get_downloaded(t)); gtk_label_set_text(GTK_LABEL(priv->gen_ratio_label), buf); statusString = torrent_get_status_string(torrent_get_status(t)); gtk_label_set_text(GTK_LABEL(priv->gen_status_label), statusString); g_free(statusString); - tr_strlpercent(buf, torrent_get_percent_done(t), sizeOfBuf); + trg_strlpercent(buf, torrent_get_percent_done(t)); gtk_label_set_text(GTK_LABEL(priv->gen_completed_label), buf); gtk_label_set_text(GTK_LABEL(priv->gen_name_label), @@ -153,13 +152,14 @@ static GtkLabel *trg_general_panel_add_label(TrgGeneralPanel * fixed, keyMarkup = g_markup_printf_escaped("%s", key); gtk_label_set_markup(GTK_LABEL(keyLabel), keyMarkup); g_free(keyMarkup); - gtk_fixed_put(GTK_FIXED(fixed), keyLabel, 10 + (col * 300), - 10 + (row * 24)); + gtk_fixed_put(GTK_FIXED(fixed), keyLabel, 10 + (col * 280), + 10 + (row * 22)); value = gtk_label_new(NULL); gtk_label_set_selectable(GTK_LABEL(value), TRUE); - gtk_fixed_put(GTK_FIXED(fixed), value, 140 + (col * 320), - 10 + (row * 24)); + gtk_fixed_put(GTK_FIXED(fixed), value, 140 + (col * 300), + 10 + (row * 22)); + g_object_set_data(G_OBJECT(value), "key-label", keyLabel); return GTK_LABEL(value); } @@ -170,27 +170,31 @@ static void trg_general_panel_init(TrgGeneralPanel * self) priv->gen_name_label = trg_general_panel_add_label(self, "Name:", 0, 0); + priv->gen_size_label = trg_general_panel_add_label(self, "Size:", 0, 1); + priv->gen_eta_label = trg_general_panel_add_label(self, "ETA:", 1, 1); priv->gen_completed_label = - trg_general_panel_add_label(self, "Completed:", 0, 2); + trg_general_panel_add_label(self, "Completed:", 2, 1); + priv->gen_seeders_label = - trg_general_panel_add_label(self, "Seeders:", 0, 3); - priv->gen_leechers_label = - trg_general_panel_add_label(self, "Leechers:", 0, 4); - priv->gen_status_label = - trg_general_panel_add_label(self, "Status:", 0, 5); - priv->gen_eta_label = trg_general_panel_add_label(self, "ETA:", 1, 1); - priv->gen_downloaded_label = - trg_general_panel_add_label(self, "Downloaded:", 1, 2); - priv->gen_uploaded_label = - trg_general_panel_add_label(self, "Uploaded:", 1, 3); + trg_general_panel_add_label(self, "Seeders:", 0, 2); priv->gen_down_rate_label = - trg_general_panel_add_label(self, "Rate Down:", 1, 4); + trg_general_panel_add_label(self, "Rate Down:", 1, 2); + priv->gen_downloaded_label = + trg_general_panel_add_label(self, "Downloaded:", 2, 2); + + priv->gen_leechers_label = + trg_general_panel_add_label(self, "Leechers:", 0, 3); priv->gen_up_rate_label = - trg_general_panel_add_label(self, "Rate Up:", 1, 5); + trg_general_panel_add_label(self, "Rate Up:", 1, 3); + priv->gen_uploaded_label = + trg_general_panel_add_label(self, "Uploaded:", 2, 3); + + priv->gen_status_label = + trg_general_panel_add_label(self, "Status:", 0, 4); priv->gen_ratio_label = - trg_general_panel_add_label(self, "Ratio:", 2, 3); + trg_general_panel_add_label(self, "Ratio:", 1, 4); gtk_widget_set_sensitive(GTK_WIDGET(self), FALSE); } diff --git a/src/trg-main-window.c b/src/trg-main-window.c index 7b73cc2..6ef29c5 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -762,7 +762,7 @@ GtkWidget *trg_main_window_notebook_new(TrgMainWindow * win) GtkWidget *notebook = gtk_notebook_new(); - gtk_widget_set_size_request(notebook, -1, 200); + gtk_widget_set_size_request(notebook, -1, 170); priv->genDetails = trg_general_panel_new(priv->sortedTorrentModel); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), @@ -771,7 +771,7 @@ GtkWidget *trg_main_window_notebook_new(TrgMainWindow * win) priv->trackersModel = trg_trackers_model_new(); priv->trackersTreeView = - trg_trackers_tree_view_new(priv->trackersModel); + trg_trackers_tree_view_new(priv->trackersModel, priv->client); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), my_scrolledwin_new(GTK_WIDGET (priv->trackersTreeView)), @@ -827,16 +827,15 @@ static void on_session_get(JsonObject * response, int status, newSession = get_arguments(response); - if (client->session != NULL) { - json_object_unref(client->session); - } else { + if (client->session == NULL) { trg_status_bar_connect(priv->statusBar, newSession); trg_main_window_conn_changed(win, TRUE); dispatch_async(client, torrent_get(), on_torrent_get_first, data); } - client->session = newSession; + trg_client_set_session(client, newSession); + trg_trackers_tree_view_new_connection(priv->trackersTreeView, client); gdk_threads_leave(); json_object_ref(newSession); @@ -878,10 +877,7 @@ trg_main_window_update_notebook_displays(TrgMainWindow * win, client = priv->client; trg_general_panel_update(priv->genDetails, t, iter); - - if (first == TRUE) - trg_trackers_model_update(priv->trackersModel, t); - + trg_trackers_model_update(priv->trackersModel, client->updateSerial, t, first); trg_files_model_update(priv->filesModel, client->updateSerial, t, first); trg_peers_model_update(priv->peersModel, client->updateSerial, @@ -1021,7 +1017,7 @@ static void on_torrent_get_multipurpose(JsonObject * response, gboolean first, int status, gpointer data) { - TrgTorrentModelClassUpdateStats stats; + trg_torrent_model_update_stats stats; TrgMainWindowPrivate *priv; trg_client *client; diff --git a/src/trg-menu-bar.c b/src/trg-menu-bar.c index ddd2626..e55a2c3 100644 --- a/src/trg-menu-bar.c +++ b/src/trg-menu-bar.c @@ -179,7 +179,6 @@ trg_menu_bar_install_widget_prop(GObjectClass * class, guint propId, G_PARAM_STATIC_BLURB)); } -static GtkWidget *trg_menu_bar_item_new(GtkMenuShell * shell, char *text, char *stock_id, gboolean sensitive) { diff --git a/src/trg-menu-bar.h b/src/trg-menu-bar.h index 8820fec..bb98475 100644 --- a/src/trg-menu-bar.h +++ b/src/trg-menu-bar.h @@ -48,6 +48,8 @@ typedef struct { GType trg_menu_bar_get_type(void); TrgMenuBar *trg_menu_bar_new(TrgMainWindow * win); +GtkWidget *trg_menu_bar_item_new(GtkMenuShell * shell, char *text, + char *stock_id, gboolean sensitive); G_END_DECLS void trg_menu_bar_torrent_actions_sensitive(TrgMenuBar * mb, diff --git a/src/trg-model.c b/src/trg-model.c index b27c981..2d1ff67 100644 --- a/src/trg-model.c +++ b/src/trg-model.c @@ -19,6 +19,7 @@ #include #include +#include struct trg_model_remove_removed_foreachfunc_args { gint64 currentSerial; @@ -63,3 +64,42 @@ trg_model_remove_removed(GtkListStore * model, gint serial_column, g_list_free(args.toRemove); } } + +struct find_existing_item_foreach_args { + gint64 id; + gint search_column; + GtkTreeIter *iter; + gboolean found; +}; + +static gboolean +find_existing_item_foreachfunc(GtkTreeModel * model, + GtkTreePath * path G_GNUC_UNUSED, + GtkTreeIter * iter, gpointer data) +{ + struct find_existing_item_foreach_args *args = (struct find_existing_item_foreach_args *) data; + gint64 currentId; + + gtk_tree_model_get(model, iter, args->search_column, ¤tId, -1); + if (currentId == args->id) { + args->iter = iter; + return args->found = TRUE; + } + + return FALSE; +} + +gboolean +find_existing_model_item(GtkTreeModel * model, gint search_column, gint64 id, + GtkTreeIter * iter) +{ + struct find_existing_item_foreach_args args; + args.id = id; + args.found = FALSE; + args.search_column = search_column; + gtk_tree_model_foreach(model, + find_existing_item_foreachfunc, &args); + if (args.found == TRUE) + *iter = *(args.iter); + return args.found; +} diff --git a/src/trg-model.h b/src/trg-model.h index 427e0bd..e954153 100644 --- a/src/trg-model.h +++ b/src/trg-model.h @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #ifndef TRG_MODEL_H_ #define TRG_MODEL_H_ @@ -26,4 +25,8 @@ void trg_model_remove_removed(GtkListStore * model, gint serial_column, gint64 currentSerial); +gboolean +find_existing_model_item(GtkTreeModel * model, gint search_column, gint64 id, + GtkTreeIter * iter); + #endif /* TRG_MODEL_H_ */ diff --git a/src/trg-peers-model.c b/src/trg-peers-model.c index 26ac636..0fb3721 100644 --- a/src/trg-peers-model.c +++ b/src/trg-peers-model.c @@ -171,7 +171,6 @@ void trg_peers_model_update(TrgPeersModel * model, gint64 updateSerial, isNew = FALSE; } - flagStr = peer_get_flagstr(peer); gtk_list_store_set(GTK_LIST_STORE(model), &peerIter, PEERSCOL_FLAGS, flagStr, diff --git a/src/trg-stats-dialog.c b/src/trg-stats-dialog.c index 4674215..4c1d08c 100644 --- a/src/trg-stats-dialog.c +++ b/src/trg-stats-dialog.c @@ -199,9 +199,17 @@ static void update_time_stat(JsonObject * args, GtkTreeRowReference * rr, static void on_stats_reply(JsonObject * response, int status, gpointer data) { - TrgStatsDialogPrivate *priv = TRG_STATS_DIALOG_GET_PRIVATE(data); + TrgStatsDialogPrivate *priv; JsonObject *args; + if (!TRG_IS_STATS_DIALOG(data)) + { + response_unref(response); + return; + } + + priv = TRG_STATS_DIALOG_GET_PRIVATE(data); + if (status == CURLE_OK) { args = get_arguments(response); diff --git a/src/trg-status-bar.c b/src/trg-status-bar.c index 499c00c..056bae0 100644 --- a/src/trg-status-bar.c +++ b/src/trg-status-bar.c @@ -77,7 +77,7 @@ void trg_status_bar_connect(TrgStatusBar * sb, JsonObject * session) } void trg_status_bar_update(TrgStatusBar * sb, - TrgTorrentModelClassUpdateStats * stats) + trg_torrent_model_update_stats * stats) { TrgStatusBarPrivate *priv; gchar *statusBarUpdate; diff --git a/src/trg-status-bar.h b/src/trg-status-bar.h index 3baf5bc..90e0133 100644 --- a/src/trg-status-bar.h +++ b/src/trg-status-bar.h @@ -52,7 +52,7 @@ TrgStatusBar *trg_status_bar_new(); G_END_DECLS void trg_status_bar_update(TrgStatusBar * sb, - TrgTorrentModelClassUpdateStats * stats); + trg_torrent_model_update_stats * stats); void trg_status_bar_connect(TrgStatusBar * sb, JsonObject * session); void trg_status_bar_push_connection_msg(TrgStatusBar * sb, const gchar * msg); diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c index 3d7d85f..3bfe20c 100644 --- a/src/trg-torrent-model.c +++ b/src/trg-torrent-model.c @@ -41,21 +41,12 @@ static guint signals[TMODEL_SIGNAL_COUNT] = { 0 }; G_DEFINE_TYPE(TrgTorrentModel, trg_torrent_model, GTK_TYPE_LIST_STORE) static guint32 torrent_get_flags(JsonObject * t, gint64 status, - TrgTorrentModelClassUpdateStats * stats); + trg_torrent_model_update_stats * stats); static void update_torrent_iter(gint64 serial, TrgTorrentModel * model, GtkTreeIter * iter, JsonObject * t, - TrgTorrentModelClassUpdateStats * stats); - -static gboolean -find_existing_torrent_item_foreachfunc(GtkTreeModel * model, - GtkTreePath * path, - GtkTreeIter * iter, gpointer data); - -static gboolean -find_existing_torrent_item(TrgTorrentModel * model, JsonObject * t, - GtkTreeIter * iter); + trg_torrent_model_update_stats * stats); static void trg_torrent_model_class_init(TrgTorrentModelClass * klass) { @@ -137,7 +128,7 @@ static void trg_torrent_model_init(TrgTorrentModel * self) } static guint32 torrent_get_flags(JsonObject * t, gint64 status, - TrgTorrentModelClassUpdateStats * stats) + trg_torrent_model_update_stats * stats) { guint32 flags = 0; switch (status) { @@ -176,7 +167,7 @@ static guint32 torrent_get_flags(JsonObject * t, gint64 status, static void update_torrent_iter(gint64 serial, TrgTorrentModel * model, GtkTreeIter * iter, JsonObject * t, - TrgTorrentModelClassUpdateStats * stats) + trg_torrent_model_update_stats * stats) { guint lastFlags, newFlags; gchar *statusString, *statusIcon; @@ -274,42 +265,9 @@ TrgTorrentModel *trg_torrent_model_new(void) return g_object_new(TRG_TYPE_TORRENT_MODEL, NULL); } -static gboolean -find_existing_torrent_item_foreachfunc(GtkTreeModel * model, - GtkTreePath * path G_GNUC_UNUSED, - GtkTreeIter * iter, gpointer data) -{ - struct idAndIter *ii; - gint currentId; - - ii = (struct idAndIter *) data; - - gtk_tree_model_get(model, iter, TORRENT_COLUMN_ID, ¤tId, -1); - if (currentId == ii->id) { - ii->iter = iter; - return ii->found = TRUE; - } - - return FALSE; -} - -static gboolean -find_existing_torrent_item(TrgTorrentModel * model, JsonObject * t, - GtkTreeIter * iter) -{ - struct idAndIter ii; - ii.id = torrent_get_id(t); - ii.found = FALSE; - gtk_tree_model_foreach(GTK_TREE_MODEL(model), - find_existing_torrent_item_foreachfunc, &ii); - if (ii.found == TRUE) - *iter = *(ii.iter); - return ii.found; -} - void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc, JsonObject * response, - TrgTorrentModelClassUpdateStats * stats, + trg_torrent_model_update_stats * stats, gboolean first) { int i; @@ -325,7 +283,7 @@ void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc, t = json_array_get_object_element(newTorrents, i); if (first == TRUE - || find_existing_torrent_item(model, t, &iter) == FALSE) { + || find_existing_model_item(GTK_TREE_MODEL(model), TORRENT_COLUMN_ID, torrent_get_id(t), &iter) == FALSE) { gtk_list_store_append(GTK_LIST_STORE(model), &iter); update_torrent_iter(tc->updateSerial, model, &iter, t, stats); if (!first) diff --git a/src/trg-torrent-model.h b/src/trg-torrent-model.h index 2c11dd0..b486737 100644 --- a/src/trg-torrent-model.h +++ b/src/trg-torrent-model.h @@ -59,7 +59,7 @@ typedef struct { gint down; gint paused; gint count; -} TrgTorrentModelClassUpdateStats; +} trg_torrent_model_update_stats; GType trg_torrent_model_get_type(void); @@ -72,7 +72,7 @@ find_existing_peer_item(GtkListStore * model, JsonObject * p, void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc, JsonObject * response, - TrgTorrentModelClassUpdateStats * stats, + trg_torrent_model_update_stats * stats, gboolean first); enum { @@ -96,10 +96,4 @@ enum { TORRENT_COLUMN_COLUMNS }; -struct idAndIter { - gint id; - GtkTreeIter *iter; - gboolean found; -}; - #endif /* TRG_TORRENT_MODEL_H_ */ diff --git a/src/trg-trackers-model.c b/src/trg-trackers-model.c index e2dc7ab..739efd6 100644 --- a/src/trg-trackers-model.c +++ b/src/trg-trackers-model.c @@ -23,11 +23,12 @@ #include "config.h" #include "torrent.h" +#include "trg-model.h" #include "trg-trackers-model.h" G_DEFINE_TYPE(TrgTrackersModel, trg_trackers_model, GTK_TYPE_LIST_STORE) -void trg_trackers_model_update(TrgTrackersModel * model, JsonObject * t) +void trg_trackers_model_update(TrgTrackersModel * model, gint64 updateSerial, JsonObject * t, gboolean first) { guint j; JsonArray *trackers; @@ -42,11 +43,13 @@ void trg_trackers_model_update(TrgTrackersModel * model, JsonObject * t) GtkTreeIter trackIter; JsonObject *tracker = json_node_get_object(json_array_get_element(trackers, j)); + gint64 trackerId = tracker_get_id(tracker); announce = tracker_get_announce(tracker); scrape = tracker_get_scrape(tracker); - gtk_list_store_append(GTK_LIST_STORE(model), &trackIter); + if (first || find_existing_model_item(GTK_TREE_MODEL(model), TRACKERCOL_ID, trackerId, &trackIter) == FALSE) + gtk_list_store_append(GTK_LIST_STORE(model), &trackIter); #ifdef DEBUG gtk_list_store_set(GTK_LIST_STORE(model), &trackIter, @@ -57,15 +60,23 @@ void trg_trackers_model_update(TrgTrackersModel * model, JsonObject * t) TRACKERCOL_ANNOUNCE, announce, -1); gtk_list_store_set(GTK_LIST_STORE(model), &trackIter, TRACKERCOL_SCRAPE, scrape, -1); + gtk_list_store_set(GTK_LIST_STORE(model), &trackIter, TRACKERCOL_ID, trackerId, -1); + gtk_list_store_set(GTK_LIST_STORE(model), &trackIter, TRACKERCOL_UPDATESERIAL, updateSerial, -1); #else gtk_list_store_set(GTK_LIST_STORE(model), &trackIter, TRACKERCOL_ICON, GTK_STOCK_NETWORK, + TRACKERCOL_ID, trackerId, + TRACKERCOL_UPDATESERIAL, updateSerial, TRACKERCOL_TIER, tracker_get_tier(tracker), TRACKERCOL_ANNOUNCE, announce, TRACKERCOL_SCRAPE, scrape, -1); #endif } + + trg_model_remove_removed(GTK_LIST_STORE(model), + TRACKERCOL_UPDATESERIAL, + updateSerial); } static void @@ -81,6 +92,8 @@ static void trg_trackers_model_init(TrgTrackersModel * self) column_types[TRACKERCOL_TIER] = G_TYPE_INT64; column_types[TRACKERCOL_ANNOUNCE] = G_TYPE_STRING; column_types[TRACKERCOL_SCRAPE] = G_TYPE_STRING; + column_types[TRACKERCOL_ID] = G_TYPE_INT64; + column_types[TRACKERCOL_UPDATESERIAL] = G_TYPE_INT64; gtk_list_store_set_column_types(GTK_LIST_STORE(self), TRACKERCOL_COLUMNS, column_types); diff --git a/src/trg-trackers-model.h b/src/trg-trackers-model.h index 3737371..13e6c56 100644 --- a/src/trg-trackers-model.h +++ b/src/trg-trackers-model.h @@ -48,14 +48,16 @@ GType trg_trackers_model_get_type(void); TrgTrackersModel *trg_trackers_model_new(void); G_END_DECLS - void -trg_trackers_model_update(TrgTrackersModel * model, JsonObject * t); + +void trg_trackers_model_update(TrgTrackersModel * model, gint64 updateSerial, JsonObject * t, gboolean first); enum { TRACKERCOL_ICON, TRACKERCOL_TIER, TRACKERCOL_ANNOUNCE, TRACKERCOL_SCRAPE, + TRACKERCOL_ID, + TRACKERCOL_UPDATESERIAL, TRACKERCOL_COLUMNS }; diff --git a/src/trg-trackers-tree-view.c b/src/trg-trackers-tree-view.c index d29a956..ff08a5e 100644 --- a/src/trg-trackers-tree-view.c +++ b/src/trg-trackers-tree-view.c @@ -21,32 +21,168 @@ #include "trg-trackers-tree-view.h" #include "trg-tree-view.h" +#include "trg-client.h" +#include "trg-menu-bar.h" G_DEFINE_TYPE(TrgTrackersTreeView, trg_trackers_tree_view, TRG_TYPE_TREE_VIEW) +#define TRG_TRACKERS_TREE_VIEW_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_TRACKERS_TREE_VIEW, TrgTrackersTreeViewPrivate)) + +typedef struct _TrgTrackersTreeViewPrivate TrgTrackersTreeViewPrivate; + +struct _TrgTrackersTreeViewPrivate { + trg_client *client; + GtkCellRenderer *announceRenderer; +}; static void trg_trackers_tree_view_class_init(TrgTrackersTreeViewClass * klass G_GNUC_UNUSED) { + g_type_class_add_private(klass, sizeof(TrgTrackersTreeViewPrivate)); +} + +void trg_trackers_tree_view_new_connection(TrgTrackersTreeView *tv, trg_client *tc) +{ + TrgTrackersTreeViewPrivate *priv = TRG_TRACKERS_TREE_VIEW_GET_PRIVATE(tv); + gboolean editable = tc->version >= 2.10; + + g_object_set(priv->announceRenderer, "editable", editable, NULL); + g_object_set(priv->announceRenderer, "mode", editable ? GTK_CELL_RENDERER_MODE_EDITABLE : GTK_CELL_RENDERER_MODE_INERT, NULL); +} + +static void trg_tracker_announce_edited(GtkCellRendererText *renderer, + gchar *path, + gchar *new_text, + gpointer user_data) +{ + GtkTreeView *tv = GTK_TREE_VIEW(user_data); + GtkTreeModel *model = gtk_tree_view_get_model(tv); + GtkTreeIter iter; + + gtk_tree_model_get_iter_from_string(model, &iter, path); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, TRACKERCOL_ANNOUNCE, new_text, -1); } static void trg_trackers_tree_view_init(TrgTrackersTreeView * self) { + TrgTrackersTreeViewPrivate *priv = TRG_TRACKERS_TREE_VIEW_GET_PRIVATE(self); + trg_tree_view_add_pixbuf_text_column(TRG_TREE_VIEW(self), TRACKERCOL_ICON, TRACKERCOL_TIER, "Tier", -1); - trg_tree_view_add_column(TRG_TREE_VIEW(self), "Announce URL", + + priv->announceRenderer = trg_tree_view_add_column(TRG_TREE_VIEW(self), "Announce URL", TRACKERCOL_ANNOUNCE); + g_signal_connect(priv->announceRenderer, "edited", G_CALLBACK(trg_tracker_announce_edited), self); + trg_tree_view_add_column(TRG_TREE_VIEW(self), "Scrape URL", TRACKERCOL_SCRAPE); } -TrgTrackersTreeView *trg_trackers_tree_view_new(TrgTrackersModel * model) +static void add_tracker(GtkWidget *w, gpointer data) +{ + +} + +static void delete_tracker(GtkWidget *w, gpointer data) +{ + +} + +static void +view_popup_menu_add_only(GtkWidget * treeview, GdkEventButton * event, + gpointer data G_GNUC_UNUSED) +{ + GtkWidget *menu, *menuitem; + + menu = gtk_menu_new(); + + menuitem = trg_menu_bar_item_new(GTK_MENU_SHELL(menu), "Add", GTK_STOCK_ADD, TRUE); + g_signal_connect(menuitem, "activate", G_CALLBACK(add_tracker), treeview); + + gtk_widget_show_all(menu); + + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, + (event != NULL) ? event->button : 0, + gdk_event_get_time((GdkEvent *) event)); +} + +static void +view_popup_menu(GtkWidget * treeview, GdkEventButton * event, + gpointer data G_GNUC_UNUSED) +{ + GtkWidget *menu, *menuitem; + + menu = gtk_menu_new(); + + menuitem = trg_menu_bar_item_new(GTK_MENU_SHELL(menu), "Delete", GTK_STOCK_DELETE, TRUE); + g_signal_connect(menuitem, "activate", G_CALLBACK(delete_tracker), treeview); + + menuitem = trg_menu_bar_item_new(GTK_MENU_SHELL(menu), "Add", GTK_STOCK_ADD, TRUE); + g_signal_connect(menuitem, "activate", G_CALLBACK(add_tracker), treeview); + + gtk_widget_show_all(menu); + + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, + (event != NULL) ? event->button : 0, + gdk_event_get_time((GdkEvent *) event)); +} + +static gboolean +view_onButtonPressed(GtkWidget * treeview, GdkEventButton * event, + gpointer userdata) +{ + TrgTrackersTreeViewPrivate *priv = TRG_TRACKERS_TREE_VIEW_GET_PRIVATE(treeview); + GtkTreeSelection *selection; + GtkTreePath *path; + + if (priv->client->version < 2.10) + return FALSE; + + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + + if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), + (gint) event->x, + (gint) event->y, &path, + NULL, NULL, NULL)) { + if (!gtk_tree_selection_path_is_selected(selection, path)) { + gtk_tree_selection_unselect_all(selection); + gtk_tree_selection_select_path(selection, path); + } + gtk_tree_path_free(path); + + view_popup_menu(treeview, event, userdata); + return TRUE; + } else { + view_popup_menu_add_only(treeview, event, userdata); + } + } + + return FALSE; +} + +static gboolean view_onPopupMenu(GtkWidget * treeview, gpointer userdata) +{ + view_popup_menu(treeview, NULL, userdata); + return TRUE; +} + +TrgTrackersTreeView *trg_trackers_tree_view_new(TrgTrackersModel * model, trg_client *client) { GObject *obj = g_object_new(TRG_TYPE_TRACKERS_TREE_VIEW, NULL); + TrgTrackersTreeViewPrivate *priv = TRG_TRACKERS_TREE_VIEW_GET_PRIVATE(obj); + + g_signal_connect(obj, "button-press-event", + G_CALLBACK(view_onButtonPressed), NULL); + g_signal_connect(obj, "popup-menu", G_CALLBACK(view_onPopupMenu), + NULL); + gtk_tree_view_set_model(GTK_TREE_VIEW(obj), GTK_TREE_MODEL(model)); + priv->client = client; return TRG_TRACKERS_TREE_VIEW(obj); } diff --git a/src/trg-trackers-tree-view.h b/src/trg-trackers-tree-view.h index 0728e43..2b58c2a 100644 --- a/src/trg-trackers-tree-view.h +++ b/src/trg-trackers-tree-view.h @@ -25,6 +25,7 @@ #include "trg-trackers-model.h" #include "trg-tree-view.h" +#include "trg-client.h" G_BEGIN_DECLS #define TRG_TYPE_TRACKERS_TREE_VIEW trg_trackers_tree_view_get_type() @@ -48,7 +49,8 @@ typedef struct { GType trg_trackers_tree_view_get_type(void); -TrgTrackersTreeView *trg_trackers_tree_view_new(TrgTrackersModel * model); +TrgTrackersTreeView *trg_trackers_tree_view_new(TrgTrackersModel * model, trg_client *client); +void trg_trackers_tree_view_new_connection(TrgTrackersTreeView *tv, trg_client *tc); G_END_DECLS #endif /* TRG_TRACKERS_TREE_VIEW_H_ */ diff --git a/src/trg-tree-view.c b/src/trg-tree-view.c index ca196cd..e92bdbc 100644 --- a/src/trg-tree-view.c +++ b/src/trg-tree-view.c @@ -133,7 +133,7 @@ void trg_tree_view_add_ratio_column(TrgTreeView * tv, char *title, gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); } -void trg_tree_view_add_column_fixed_width(TrgTreeView * tv, char *title, +GtkCellRenderer *trg_tree_view_add_column_fixed_width(TrgTreeView * tv, char *title, int index, int width) { GtkCellRenderer *renderer; @@ -145,6 +145,8 @@ void trg_tree_view_add_column_fixed_width(TrgTreeView * tv, char *title, trg_tree_view_std_column_setup(column, index, width); gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); + + return renderer; } void diff --git a/src/trg-tree-view.h b/src/trg-tree-view.h index 1abea47..fe225fe 100644 --- a/src/trg-tree-view.h +++ b/src/trg-tree-view.h @@ -48,7 +48,7 @@ GtkWidget *trg_tree_view_new(void); G_END_DECLS #define trg_tree_view_add_column(tv, title, index) trg_tree_view_add_column_fixed_width(tv, title, index, -1) -void trg_tree_view_add_column_fixed_width(TrgTreeView * treeview, +GtkCellRenderer *trg_tree_view_add_column_fixed_width(TrgTreeView * treeview, char *title, int index, int width); -- cgit v1.2.3