diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/icons.c | 243 | ||||
-rw-r--r-- | src/icons.h | 21 | ||||
-rw-r--r-- | src/torrent-cell-renderer.c | 958 | ||||
-rw-r--r-- | src/torrent-cell-renderer.h | 51 | ||||
-rw-r--r-- | src/trg-torrent-model.c | 12 | ||||
-rw-r--r-- | src/trg-torrent-model.h | 4 | ||||
-rw-r--r-- | src/trg-torrent-tree-view.c | 41 | ||||
-rw-r--r-- | src/trg-tree-view.c | 5 | ||||
-rw-r--r-- | src/util.c | 11 | ||||
-rw-r--r-- | src/util.h | 2 |
11 files changed, 1338 insertions, 12 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 26cd0df..fe20953 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,6 +57,7 @@ transmission_remote_gtk_SOURCES = \ trg-cell-renderer-file-icon.c \ trg-cell-renderer-epoch.c \ trg-cell-renderer-numgteqthan.c \ + torrent-cell-renderer.c \ trg-remote-prefs-dialog.c \ trg-torrent-props-dialog.c \ trg-torrent-add-url-dialog.c \ @@ -70,6 +71,7 @@ transmission_remote_gtk_SOURCES = \ trg-general-panel.c \ trg-torrent-graph.c \ trg-icons.c \ + icons.c \ trg-toolbar.c \ trg-menu-bar.c \ trg-status-bar.c \ diff --git a/src/icons.c b/src/icons.c new file mode 100644 index 0000000..0c0e07e --- /dev/null +++ b/src/icons.c @@ -0,0 +1,243 @@ +/* + * icons.[ch] written by Paolo Bacchilega, who writes: + * "There is no problem for me, you can license my code + * under whatever licence you wish :)" + * + * $Id: icons.c 12639 2011-08-07 18:41:13Z jordan $ + */ + +#include <string.h> /* strcmp */ +#include <glib.h> +#include <gtk/gtk.h> +#include <gio/gio.h> +#include "icons.h" + +#define VOID_PIXBUF_KEY "void-pixbuf" + +static const char * +get_static_string( const char *s ) +{ + static GStringChunk * static_strings = NULL; + + if( s == NULL ) + return NULL; + + if( static_strings == NULL ) + static_strings = g_string_chunk_new( 1024 ); + + return g_string_chunk_insert_const( static_strings, s ); +} + +typedef struct { + GtkIconTheme * icon_theme; + int icon_size; + GHashTable * cache; +} IconCache; + + +static IconCache *icon_cache[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + + +static GdkPixbuf* +create_void_pixbuf (int width, + int height) +{ + GdkPixbuf *p; + + p = gdk_pixbuf_new( GDK_COLORSPACE_RGB, + TRUE, + 8, + width, + height); + gdk_pixbuf_fill( p, 0xFFFFFF00 ); + + return p; +} + + +static int +get_size_in_pixels( GtkWidget * widget, + GtkIconSize icon_size ) +{ + int width, height; + + gtk_icon_size_lookup_for_settings( gtk_widget_get_settings( widget ), + icon_size, + &width, + &height ); + return MAX( width, height ); +} + + +static IconCache * +icon_cache_new (GtkWidget * for_widget, int icon_size) +{ + IconCache * icon_cache; + + g_return_val_if_fail( for_widget != NULL, NULL ); + + icon_cache = g_new0( IconCache, 1 ); + icon_cache->icon_theme = gtk_icon_theme_get_for_screen( gtk_widget_get_screen( for_widget )); + icon_cache->icon_size = get_size_in_pixels( for_widget, icon_size ); + icon_cache->cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + g_hash_table_insert( icon_cache->cache, (void*)VOID_PIXBUF_KEY, create_void_pixbuf( icon_cache->icon_size, icon_cache->icon_size )); + + return icon_cache; +} + +static const char * +_icon_cache_get_icon_key( GIcon * icon ) +{ + const char * key = NULL; + + if ( G_IS_THEMED_ICON( icon )) { + char ** icon_names; + char * name; + + g_object_get( icon, "names", &icon_names, NULL ); + name = g_strjoinv( ",", icon_names ); + + key = get_static_string( name ); + + g_free( name ); + g_strfreev( icon_names ); + } + else if ( G_IS_FILE_ICON( icon )) { + GFile * file; + char * filename; + + file = g_file_icon_get_file( G_FILE_ICON( icon )); + filename = g_file_get_path( file ); + + key = get_static_string( filename ); + + g_free( filename ); + g_object_unref( file ); + } + + return key; +} + + +static GdkPixbuf * +get_themed_icon_pixbuf( GThemedIcon * icon, + int size, + GtkIconTheme * icon_theme ) +{ + char ** icon_names = NULL; + GtkIconInfo * icon_info; + GdkPixbuf * pixbuf; + GError * error = NULL; + + g_object_get( icon, "names", &icon_names, NULL ); + + icon_info = gtk_icon_theme_choose_icon( icon_theme, (const char **)icon_names, size, 0 ); + if ( icon_info == NULL ) + icon_info = gtk_icon_theme_lookup_icon( icon_theme, "text-x-generic", size, GTK_ICON_LOOKUP_USE_BUILTIN ); + + pixbuf = gtk_icon_info_load_icon( icon_info, &error ); + if ( pixbuf == NULL ) { + if( error && error->message ) + g_warning( "could not load icon pixbuf: %s\n", error->message ); + g_clear_error( &error ); + } + + gtk_icon_info_free( icon_info ); + g_strfreev( icon_names ); + + return pixbuf; +} + + +static GdkPixbuf * +get_file_icon_pixbuf( GFileIcon * icon, int size ) +{ + GFile * file; + char * filename; + GdkPixbuf * pixbuf; + + file = g_file_icon_get_file( icon ); + filename = g_file_get_path( file ); + pixbuf = gdk_pixbuf_new_from_file_at_size( filename, size, -1, NULL ); + g_free( filename ); + g_object_unref( file ); + + return pixbuf; +} + + +static GdkPixbuf * +_get_icon_pixbuf( GIcon * icon, int size, GtkIconTheme * theme ) +{ + if ( icon == NULL ) + return NULL; + if ( G_IS_THEMED_ICON (icon) ) + return get_themed_icon_pixbuf( G_THEMED_ICON( icon ), size, theme ); + if ( G_IS_FILE_ICON (icon) ) + return get_file_icon_pixbuf( G_FILE_ICON( icon ), size ); + return NULL; +} + + +static GdkPixbuf * +icon_cache_get_mime_type_icon( IconCache * icon_cache, const char * mime_type ) +{ + GIcon * icon; + const char * key = NULL; + GdkPixbuf * pixbuf; + + icon = g_content_type_get_icon( mime_type ); + key = _icon_cache_get_icon_key( icon ); + + if (key == NULL) + key = VOID_PIXBUF_KEY; + + pixbuf = g_hash_table_lookup( icon_cache->cache, key ); + if (pixbuf != NULL) { + g_object_ref( pixbuf ); + g_object_unref( G_OBJECT( icon ) ); + return pixbuf; + } + + pixbuf = _get_icon_pixbuf( icon, icon_cache->icon_size, icon_cache->icon_theme ); + if( pixbuf != NULL ) + g_hash_table_insert( icon_cache->cache, (gpointer) key, g_object_ref( pixbuf ) ); + + g_object_unref( G_OBJECT( icon ) ); + + return pixbuf; +} + +GdkPixbuf * +gtr_get_mime_type_icon( const char * mime_type, + GtkIconSize icon_size, + GtkWidget * for_widget ) +{ + int n; + + switch ( icon_size ) { + case GTK_ICON_SIZE_MENU: n = 1; break; + case GTK_ICON_SIZE_SMALL_TOOLBAR: n = 2; break; + case GTK_ICON_SIZE_LARGE_TOOLBAR: n = 3; break; + case GTK_ICON_SIZE_BUTTON: n = 4; break; + case GTK_ICON_SIZE_DND: n = 5; break; + case GTK_ICON_SIZE_DIALOG: n = 6; break; + default /*GTK_ICON_SIZE_INVALID*/: n = 0; break; + } + + if( icon_cache[n] == NULL ) + icon_cache[n] = icon_cache_new( for_widget, icon_size ); + + return icon_cache_get_mime_type_icon( icon_cache[n], mime_type ); +} + + +const char * +gtr_get_mime_type_from_filename( const char * file G_GNUC_UNUSED ) +{ + char * tmp = g_content_type_guess( file, NULL, 0, NULL ); + const char * ret = get_static_string( tmp ); + g_free( tmp ); + return ret; +} diff --git a/src/icons.h b/src/icons.h new file mode 100644 index 0000000..db19d92 --- /dev/null +++ b/src/icons.h @@ -0,0 +1,21 @@ +/* + * icons.[ch] written by Paolo Bacchilega, who writes: + * "There is no problem for me, you can license + * my code under whatever licence you wish :)" + * + * $Id: icons.h 11709 2011-01-19 13:48:47Z jordan $ + */ + +#ifndef GTR_ICONS_H +#define GTR_ICONS_H + +#define DIRECTORY_MIME_TYPE "folder" +#define UNKNOWN_MIME_TYPE "unknown" + +const char * gtr_get_mime_type_from_filename( const char *file ); + +GdkPixbuf * gtr_get_mime_type_icon( const char * mime_type, + GtkIconSize icon_size, + GtkWidget * for_widget ); + +#endif diff --git a/src/torrent-cell-renderer.c b/src/torrent-cell-renderer.c new file mode 100644 index 0000000..d49de36 --- /dev/null +++ b/src/torrent-cell-renderer.c @@ -0,0 +1,958 @@ +/* + * This file Copyright (C) Mnemosyne LLC + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id: torrent-cell-renderer.c 13388 2012-07-14 19:26:55Z jordan $ + */ + +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <glib/gi18n.h> + +#include "hig.h" +#include "icons.h" +#include "torrent-cell-renderer.h" +#include "torrent.h" +#include "util.h" + +/* #define TEST_RTL */ + + /*"status", TORRENT_COLUMN_FLAGS, + "ratio", TORRENT_COLUMN_RATIO, + "downloaded", TORRENT_COLUMN_DOWNLOADED, + "name", TORRENT_COLUMN_NAME, + "sizeWhenDone", TORRENT_COLUMN_SIZE, + "uploaded", TORRENT_COLUMN_UPLOADED, + "percentComplete", TORRENT_COLUMN_DONE, + "upSpeed", TORRENT_COLUMN_UPSPEED, + "downSpeed", TORRENT_COLUMN_DOWNSPEED, + "leechers", TORRENT_COLUMN_LEECHERS, + "seeds", TORRENT_COLUMN_SEEDS, + "eta", TORRENT_COLUMN_ETA, + "json", TORRENT_COLUMN_JSON, + "connected", TORRENT_COLUMN_PEERS_CONNECTED,*/ + +enum +{ + P_STATUS = 1, + P_RATIO, + P_DOWNLOADED, + P_NAME, + P_SIZEWHENDONE, + P_UPLOADED, + P_PERCENTCOMPLETE, + P_UPSPEED, + P_DOWNSPEED, + P_LEECHERS, + P_SEEDS, + P_ETA, + P_JSON, + P_CONNECTED, + P_BAR_HEIGHT, + P_COMPACT +}; + +#define DEFAULT_BAR_HEIGHT 12 +#define SMALL_SCALE 0.9 +#define COMPACT_ICON_SIZE GTK_ICON_SIZE_MENU +#define FULL_ICON_SIZE GTK_ICON_SIZE_DND + +typedef cairo_t GtrDrawable; +typedef GdkRGBA GtrColor; + +/*** +**** +***/ + +static void +render_compact( TorrentCellRenderer * cell, + GtrDrawable * window, + GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags ); + +static void +render_full( TorrentCellRenderer * cell, + GtrDrawable * window, + GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags ); + +/*** +**** +***/ + +struct TorrentCellRendererPrivate +{ + GtkCellRenderer * text_renderer; + GtkCellRenderer * progress_renderer; + GtkCellRenderer * icon_renderer; + GString * gstr1; + GString * gstr2; + int bar_height; + + gint64 uploadedEver; + gint64 sizeWhenDone; + gint64 downloaded; + gint64 upSpeed; + gint64 downSpeed; + gpointer json; + gdouble done; + gdouble ratio; + guint flags; + const gchar *name; + gint64 peersFromUs; + gint64 peersToUs; + gint64 connected; + gint64 eta; + + gboolean compact; +}; + +static void +getProgressString( GString * gstr, + TorrentCellRenderer * r) +{ + struct TorrentCellRendererPrivate *priv = r->priv; + + //const int isSeed = st->haveValid >= info->totalSize; + char buf1[32], buf2[32], buf3[32], buf4[32], buf5[32], buf6[32]; + //double seedRatio; + //const gboolean hasSeedRatio = tr_torrentGetSeedRatio( tor, &seedRatio ); + + //TODO : use seed ratios + + if( priv->flags & TORRENT_FLAG_DOWNLOADING ) /* downloading */ + { + g_string_append_printf( gstr, + /* %1$s is how much we've got, + %2$s is how much we'll have when done, + %3$s%% is a percentage of the two */ + _( "%1$s of %2$s (%3$s%%)" ), + tr_strlsize( buf1, priv->downloaded, sizeof( buf1 ) ), + tr_strlsize( buf2, priv->sizeWhenDone, sizeof( buf2 ) ), + tr_strlpercent( buf3, priv->done, sizeof( buf3 ) ) ); + } + /*else if( isSeed ) + { + if( hasSeedRatio ) + { + g_string_append_printf( gstr, + _( "%1$s of %2$s (%3$s%%), uploaded %4$s (Ratio: %5$s Goal: %6$s)" ), + tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ), + tr_strlsize( buf2, info->totalSize, sizeof( buf2 ) ), + tr_strlpercent( buf3, st->percentComplete * 100.0, sizeof( buf3 ) ), + tr_strlsize( buf4, st->uploadedEver, sizeof( buf4 ) ), + tr_strlratio( buf5, st->ratio, sizeof( buf5 ) ), + tr_strlratio( buf6, seedRatio, sizeof( buf6 ) ) ); + } + else + { + g_string_append_printf( gstr, + _( "%1$s of %2$s (%3$s%%), uploaded %4$s (Ratio: %5$s)" ), + tr_strlsize( buf1, priv->downloaded, sizeof( buf1 ) ), + tr_strlsize( buf2, priv->sizeWhenDone, sizeof( buf2 ) ), + tr_strlpercent( buf3, priv->done, sizeof( buf3 ) ), + tr_strlsize( buf4, priv->uploadedEver, sizeof( buf4 ) ), + tr_strlratio( buf5, priv->ratio, sizeof( buf5 ) ) ); + } + }*/ + else /* seeding */ + { + /*if( hasSeedRatio ) + { + g_string_append_printf( gstr, + _( "%1$s, uploaded %2$s (Ratio: %3$s Goal: %4$s)" ), + tr_strlsize( buf1, info->totalSize, sizeof( buf1 ) ), + tr_strlsize( buf2, st->uploadedEver, sizeof( buf2 ) ), + tr_strlratio( buf3, st->ratio, sizeof( buf3 ) ), + tr_strlratio( buf4, seedRatio, sizeof( buf4 ) ) ); + } + else + { */ + g_string_append_printf( gstr, + /* %1$s is the torrent's total size, + %2$s is how much we've uploaded, + %3$s is our upload-to-download ratio */ + _( "%1$s, uploaded %2$s (Ratio: %3$s)" ), + tr_strlsize( buf1, priv->sizeWhenDone, sizeof( buf1 ) ), + tr_strlsize( buf2, priv->uploadedEver, sizeof( buf2 ) ), + tr_strlratio( buf3, priv->ratio, sizeof( buf3 ) ) ); + //} + } + + /* add time when downloading */ + if( ( priv->flags & TORRENT_FLAG_DOWNLOADING ) ) + //|| ( hasSeedRatio && ( st->activity == TR_STATUS_SEED ) ) ) + { + gint64 eta = priv->eta; + g_string_append( gstr, " - " ); + if( eta < 0 ) + g_string_append( gstr, _( "Remaining time unknown" ) ); + else + { + char timestr[128]; + tr_strltime_long( timestr, eta, sizeof( timestr ) ); + /* time remaining */ + g_string_append_printf( gstr, _( "%s remaining" ), timestr ); + } + } +} + +static char* +getShortTransferString( TorrentCellRenderer * r, + char * buf, + size_t buflen ) +{ + struct TorrentCellRendererPrivate *priv = r->priv; + + char downStr[32], upStr[32]; + //const int haveMeta = tr_torrentHasMetadata( tor ); + //const int haveUp = haveMeta && st->peersGettingFromUs > 0; + //const int haveDown = haveMeta && ( ( st->peersSendingToUs > 0 ) || ( st->webseedsSendingToUs > 0 ) ); + const int haveUp = priv->peersFromUs > 0; + const int haveDown = priv->peersToUs > 0; + + if( haveDown ) + tr_formatter_speed_KBps( downStr, priv->downSpeed, sizeof( downStr ) ); + if( haveUp ) + tr_formatter_speed_KBps( upStr, priv->upSpeed, sizeof( upStr ) ); + + if( haveDown && haveUp ) + /* 1==down arrow, 2==down speed, 3==up arrow, 4==down speed */ + g_snprintf( buf, buflen, _( "%1$s %2$s, %3$s %4$s" ), + GTR_UNICODE_DOWN, downStr, + GTR_UNICODE_UP, upStr ); + else if( haveDown ) + /* bandwidth speed + unicode arrow */ + g_snprintf( buf, buflen, _( "%1$s %2$s" ), + GTR_UNICODE_DOWN, downStr ); + else if( haveUp ) + /* bandwidth speed + unicode arrow */ + g_snprintf( buf, buflen, _( "%1$s %2$s" ), + GTR_UNICODE_UP, upStr ); + /*else if( st->isStalled ) + g_strlcpy( buf, _( "Stalled" ), buflen ); + else if( haveMeta ) + g_strlcpy( buf, _( "Idle" ), buflen );*/ + else + *buf = '\0'; + + return buf; +} + +static void +getShortStatusString( GString * gstr, + TorrentCellRenderer * r ) +{ + struct TorrentCellRendererPrivate *priv = r->priv; + guint flags = priv->flags; + + if (flags & TORRENT_FLAG_PAUSED) { + g_string_append( gstr, (flags & TORRENT_FLAG_COMPLETE) ? _( "Finished" ) : _( "Paused" ) ); + } else if (flags & TORRENT_FLAG_WAITING_CHECK) { + g_string_append( gstr, _( "Queued for verification" ) ); + } else if (flags & TORRENT_FLAG_DOWNLOADING_WAIT) { + g_string_append( gstr, _( "Queued for download" ) ); + } else if (flags & TORRENT_FLAG_SEEDING_WAIT) { + g_string_append( gstr, _( "Queued for seeding" ) ); + } else if (flags & TORRENT_FLAG_CHECKING) { + g_string_append_printf( gstr, _( "Verifying data (%.1f%% tested)" ), + tr_truncd( priv->done * 100.0, 1 ) ); + } else if ((flags & TORRENT_FLAG_DOWNLOADING) || (flags & TORRENT_FLAG_SEEDING)) { + char buf[512]; + if( flags & ~TORRENT_FLAG_DOWNLOADING ) + { + tr_strlratio( buf, priv->ratio, sizeof( buf ) ); + g_string_append_printf( gstr, _( "Ratio %s" ), buf ); + g_string_append( gstr, ", " ); + } + getShortTransferString( r, buf, sizeof( buf ) ); + g_string_append( gstr, buf ); + } +} + +static void +getStatusString( GString * gstr, + TorrentCellRenderer * r ) +{ + struct TorrentCellRendererPrivate *priv = r->priv; + + //TODO: handle metadata for downloading + //TODO: handle errors + + if (priv->flags & TORRENT_FLAG_DOWNLOADING) { + g_string_append_printf( gstr, + ngettext( "Downloading from %1$'d of %2$'d connected peer", + "Downloading from %1$'d of %2$'d connected peers", + priv->peersToUs ), + priv->peersToUs, + priv->connected ); + } else if (priv->flags & TORRENT_FLAG_SEEDING) { + g_string_append_printf( gstr, + ngettext( "Seeding to %1$'d of %2$'d connected peer", + "Seeding to %1$'d of %2$'d connected peers", + priv->connected ), + priv->peersFromUs, + priv->connected ); + } + + if( ( priv->flags & ~TORRENT_FLAG_WAITING_CHECK ) && + ( priv->flags & ~TORRENT_FLAG_CHECKING ) && + ( priv->flags & ~TORRENT_FLAG_DOWNLOADING_WAIT ) && + ( priv->flags & ~TORRENT_FLAG_SEEDING_WAIT ) && + ( priv->flags & ~TORRENT_FLAG_PAUSED ) ) + { + char buf[256]; + getShortTransferString( r, buf, sizeof( buf ) ); + if( *buf ) + g_string_append_printf( gstr, " - %s", buf ); + } +} + +/*** +**** +***/ + +static GdkPixbuf* +get_icon( TorrentCellRenderer *r, GtkIconSize icon_size, GtkWidget * for_widget ) +{ + const char * mime_type; + /*const tr_info * info = tr_torrentInfo( tor ); + + if( info->fileCount == 0 ) + mime_type = UNKNOWN_MIME_TYPE; + else if( info->fileCount > 1 ) + mime_type = DIRECTORY_MIME_TYPE; + else if( strchr( info->files[0].name, '/' ) != NULL ) + mime_type = DIRECTORY_MIME_TYPE; + else + mime_type = gtr_get_mime_type_from_filename( info->files[0].name );*/ + + mime_type = DIRECTORY_MIME_TYPE; + + //return NULL; + return gtr_get_mime_type_icon( mime_type, icon_size, for_widget ); +} + +/*** +**** +***/ + +static void +gtr_cell_renderer_get_preferred_size( GtkCellRenderer * renderer, + GtkWidget * widget, + GtkRequisition * minimum_size, + GtkRequisition * natural_size ) +{ + gtk_cell_renderer_get_preferred_size( renderer, widget, minimum_size, natural_size ); +} + +static void +get_size_compact( TorrentCellRenderer * cell, + GtkWidget * widget, + gint * width, + gint * height ) +{ + int xpad, ypad; + GtkRequisition icon_size; + GtkRequisition name_size; + GtkRequisition stat_size; + GdkPixbuf * icon; + + struct TorrentCellRendererPrivate * p = cell->priv; + GString * gstr_stat = p->gstr1; + + icon = get_icon( cell, COMPACT_ICON_SIZE, widget ); + g_string_truncate( gstr_stat, 0 ); + getShortStatusString( gstr_stat, cell ); + gtk_cell_renderer_get_padding( GTK_CELL_RENDERER( cell ), &xpad, &ypad ); + + /* get the idealized cell dimensions */ + g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); + gtr_cell_renderer_get_preferred_size( p->icon_renderer, widget, NULL, &icon_size ); + g_object_set( p->text_renderer, "text", torrent_get_name(p->json), "ellipsize", PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &name_size ); + g_object_set( p->text_renderer, "text", gstr_stat->str, "scale", SMALL_SCALE, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &stat_size ); + + /** + *** LAYOUT + **/ + +#define BAR_WIDTH 50 + if( width != NULL ) + *width = xpad * 2 + icon_size.width + GUI_PAD + name_size.width + GUI_PAD + BAR_WIDTH + GUI_PAD + stat_size.width; + if( height != NULL ) + *height = ypad * 2 + MAX( name_size.height, p->bar_height ); + + /* cleanup */ + g_object_unref( icon ); +} + +#define MAX3(a,b,c) MAX(a,MAX(b,c)) + +static void +get_size_full( TorrentCellRenderer * cell, + GtkWidget * widget, + gint * width, + gint * height ) +{ + int xpad, ypad; + GtkRequisition icon_size; + GtkRequisition name_size; + GtkRequisition stat_size; + GtkRequisition prog_size; + GdkPixbuf * icon; + + struct TorrentCellRendererPrivate * p = cell->priv; + /*const tr_torrent * tor = p->tor; + const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor ); + const tr_info * inf = tr_torrentInfo( tor );*/ + GString * gstr_prog = p->gstr1; + GString * gstr_stat = p->gstr2; + + icon = get_icon( cell, FULL_ICON_SIZE, widget ); + + g_string_truncate( gstr_stat, 0 ); + getStatusString( gstr_stat, cell ); + g_string_truncate( gstr_prog, 0 ); + getProgressString( gstr_prog, cell ); + gtk_cell_renderer_get_padding( GTK_CELL_RENDERER( cell ), &xpad, &ypad ); + + /* get the idealized cell dimensions */ + g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); + gtr_cell_renderer_get_preferred_size( p->icon_renderer, widget, NULL, &icon_size ); + g_object_set( p->text_renderer, "text", torrent_get_name(p->json), "weight", PANGO_WEIGHT_BOLD, "scale", 1.0, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &name_size ); + g_object_set( p->text_renderer, "text", gstr_prog->str, "weight", PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &prog_size ); + g_object_set( p->text_renderer, "text", gstr_stat->str, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &stat_size ); + + /** + *** LAYOUT + **/ + + if( width != NULL ) + *width = xpad * 2 + icon_size.width + GUI_PAD + MAX3( name_size.width, prog_size.width, stat_size.width ); + if( height != NULL ) + *height = ypad * 2 + name_size.height + prog_size.height + GUI_PAD_SMALL + p->bar_height + GUI_PAD_SMALL + stat_size.height; + + /* cleanup */ + g_object_unref( icon ); +} + + +static void +torrent_cell_renderer_get_size( GtkCellRenderer * cell, + GtkWidget * widget, + const GdkRectangle * cell_area, + gint * x_offset, + gint * y_offset, + gint * width, + gint * height ) +{ + TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell ); + + if( self ) + { + int w, h; + struct TorrentCellRendererPrivate * p = self->priv; + + if( p->compact ) + get_size_compact( TORRENT_CELL_RENDERER( cell ), widget, &w, &h ); + else + get_size_full( TORRENT_CELL_RENDERER( cell ), widget, &w, &h ); + + if( width ) + *width = w; + + if( height ) + *height = h; + + if( x_offset ) + *x_offset = cell_area ? cell_area->x : 0; + + if( y_offset ) { + int xpad, ypad; + gtk_cell_renderer_get_padding( cell, &xpad, &ypad ); + *y_offset = cell_area ? (int)((cell_area->height - (ypad*2 +h)) / 2.0) : 0; + } + } +} + + +#define FOREGROUND_COLOR_KEY "foreground-rgba" + +static void +get_text_color( GtkWidget * w, TorrentCellRenderer *r, GtrColor * setme ) +{ + /*static const GdkRGBA red = { 1.0, 0, 0, 0 }; + if( st->error ) + *setme = red; + else */if( r->priv->flags & TORRENT_FLAG_PAUSED ) + gtk_style_context_get_color( gtk_widget_get_style_context( w ), GTK_STATE_FLAG_INSENSITIVE, setme ); + else + gtk_style_context_get_color( gtk_widget_get_style_context( w ), GTK_STATE_FLAG_NORMAL, setme ); +} + +/*static double +get_percent_done( TorrentCellRenderer *r, gboolean * seed ) +{ + struct TorrentCellRendererPrivate *priv = r->priv; + double d; + + //TODO: handle seed ratios + + if( ( priv->flags & TORRENT_FLAG_SEEDING ) && tr_torrentGetSeedRatio( tor, &d ) ) + { + *seed = true; + d = MAX( 0.0, st->seedRatioPercentDone ); + } + else + { + *seed = FALSE; + d = MAX( 0.0, priv->done ); + } + + return d; +}*/ + +static void +gtr_cell_renderer_render( GtkCellRenderer * renderer, + GtrDrawable * drawable, + GtkWidget * widget, + const GdkRectangle * area, + GtkCellRendererState flags) +{ + gtk_cell_renderer_render( renderer, drawable, widget, area, area, flags ); +} + + +static void +torrent_cell_renderer_render( GtkCellRenderer * cell, + GtrDrawable * window, + GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags ) +{ + TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell ); + + if( self ) + { + struct TorrentCellRendererPrivate * p = self->priv; + if( p->compact ) + render_compact( self, window, widget, background_area, cell_area, flags ); + else + render_full( self, window, widget, background_area, cell_area, flags ); + } +} + +static void +torrent_cell_renderer_set_property( GObject * object, + guint property_id, + const GValue * v, + GParamSpec * pspec ) +{ + TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object ); + struct TorrentCellRendererPrivate * p = self->priv; + + switch( property_id ) + { + case P_JSON: p->json = g_value_get_pointer( v ); break; + case P_STATUS: p->flags = g_value_get_uint( v ); break; + case P_SIZEWHENDONE: p->sizeWhenDone = g_value_get_int64( v ); break; + case P_DOWNLOADED: p->downloaded = g_value_get_int64( v ); break; + case P_UPLOADED: p->uploadedEver = g_value_get_int64( v ); break; + case P_UPSPEED: p->upSpeed = g_value_get_int64( v ); break; + case P_DOWNSPEED: p->downSpeed = g_value_get_int64( v ); break; + case P_LEECHERS: p->peersFromUs = g_value_get_int64( v ); break; + case P_CONNECTED: p->connected = g_value_get_int64( v ); break; + case P_ETA: p->eta = g_value_get_int64( v ); break; + case P_SEEDS: p->peersToUs = g_value_get_int64( v ); break; + case P_NAME: p->name = g_value_get_string( v ); break; + case P_RATIO: p->ratio = g_value_get_double( v ); break; + case P_PERCENTCOMPLETE: p->done = g_value_get_double( v ); break; + case P_BAR_HEIGHT: p->bar_height = g_value_get_int( v ); break; + case P_COMPACT: p->compact = g_value_get_boolean( v ); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec ); break; + } +} + +static void +torrent_cell_renderer_get_property( GObject * object, + guint property_id, + GValue * v, + GParamSpec * pspec ) +{ + /*const TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object ); + struct TorrentCellRendererPrivate * p = self->priv; + + switch( property_id ) + { + case P_TORRENT: g_value_set_pointer( v, p->tor ); break; + case P_UPLOAD_SPEED: g_value_set_double( v, p->upload_speed_KBps ); break; + case P_DOWNLOAD_SPEED: g_value_set_double( v, p->download_speed_KBps ); break; + case P_BAR_HEIGHT: g_value_set_int( v, p->bar_height ); break; + case P_COMPACT: g_value_set_boolean( v, p->compact ); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec ); break; + }*/ +} + +G_DEFINE_TYPE (TorrentCellRenderer, torrent_cell_renderer, GTK_TYPE_CELL_RENDERER) + +static void +torrent_cell_renderer_dispose( GObject * o ) +{ + TorrentCellRenderer * r = TORRENT_CELL_RENDERER( o ); + + if( r && r->priv ) + { + g_string_free( r->priv->gstr1, TRUE ); + g_string_free( r->priv->gstr2, TRUE ); + g_object_unref( G_OBJECT( r->priv->text_renderer ) ); + g_object_unref( G_OBJECT( r->priv->progress_renderer ) ); + g_object_unref( G_OBJECT( r->priv->icon_renderer ) ); + r->priv = NULL; + } + + G_OBJECT_CLASS( torrent_cell_renderer_parent_class )->dispose( o ); +} + +static void +torrent_cell_renderer_class_init( TorrentCellRendererClass * klass ) +{ + GObjectClass * gobject_class = G_OBJECT_CLASS( klass ); + GtkCellRendererClass * cell_class = GTK_CELL_RENDERER_CLASS( klass ); + + g_type_class_add_private( klass, + sizeof( struct TorrentCellRendererPrivate ) ); + + cell_class->render = torrent_cell_renderer_render; + cell_class->get_size = torrent_cell_renderer_get_size; + gobject_class->set_property = torrent_cell_renderer_set_property; + gobject_class->get_property = torrent_cell_renderer_get_property; + gobject_class->dispose = torrent_cell_renderer_dispose; + + g_object_class_install_property( gobject_class, P_NAME, + g_param_spec_string( "name", NULL, + "name", + "", + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_JSON, + g_param_spec_pointer( "json", NULL, + "json", + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_RATIO, + g_param_spec_double( "ratio", NULL, + "ratio", + 0, G_MAXDOUBLE, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_PERCENTCOMPLETE, + g_param_spec_double( "percentComplete", NULL, + "percentComplete", + 0, 100.00, 0, + G_PARAM_READWRITE ) ); + + + g_object_class_install_property( gobject_class, P_SIZEWHENDONE, + g_param_spec_int64( "sizeWhenDone", NULL, + "sizeWhenDone", + 0, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_STATUS, + g_param_spec_uint( "status", NULL, + "status", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_UPSPEED, + g_param_spec_int64( "upSpeed", NULL, + "upSpeed", + 0, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_DOWNSPEED, + g_param_spec_int64( "downSpeed", NULL, + "downSpeed", + 0, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_DOWNLOADED, + g_param_spec_int64( "downloaded", NULL, + "downloaded", + 0, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_UPLOADED, + g_param_spec_int64( "uploaded", NULL, + "uploaded", + 0, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_LEECHERS, + g_param_spec_int64( "leechers", NULL, + "leechers", + -1, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_SEEDS, + g_param_spec_int64( "seeds", NULL, + "seeds", + -1, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_ETA, + g_param_spec_int64( "eta", NULL, + "eta", + -1, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_CONNECTED, + g_param_spec_int64( "connected", NULL, + "connected", + 0, G_MAXINT64, 0, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_BAR_HEIGHT, + g_param_spec_int( "bar-height", NULL, + "Bar Height", + 1, INT_MAX, + DEFAULT_BAR_HEIGHT, + G_PARAM_READWRITE ) ); + + g_object_class_install_property( gobject_class, P_COMPACT, + g_param_spec_boolean( "compact", NULL, + "Compact Mode", + FALSE, + G_PARAM_READWRITE ) ); +} + +static void +torrent_cell_renderer_init( TorrentCellRenderer * self ) +{ + struct TorrentCellRendererPrivate * p; + + p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE( + self, + TORRENT_CELL_RENDERER_TYPE, + struct + TorrentCellRendererPrivate ); + + p->gstr1 = g_string_new( NULL ); + p->gstr2 = g_string_new( NULL ); + p->text_renderer = gtk_cell_renderer_text_new( ); + g_object_set( p->text_renderer, "xpad", 0, "ypad", 0, NULL ); + p->progress_renderer = gtk_cell_renderer_progress_new( ); + p->icon_renderer = gtk_cell_renderer_pixbuf_new( ); + g_object_ref_sink( p->text_renderer ); + g_object_ref_sink( p->progress_renderer ); + g_object_ref_sink( p->icon_renderer ); + + p->bar_height = DEFAULT_BAR_HEIGHT; +} + + +GtkCellRenderer * +torrent_cell_renderer_new( void ) +{ + return (GtkCellRenderer *) g_object_new( TORRENT_CELL_RENDERER_TYPE, + NULL ); +} + +static void +render_compact( TorrentCellRenderer * cell, + GtrDrawable * window, + GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags ) +{ + int xpad, ypad; + GtkRequisition size; + GdkRectangle icon_area; + GdkRectangle name_area; + GdkRectangle stat_area; + GdkRectangle prog_area; + GdkRectangle fill_area; + GdkPixbuf * icon; + GtrColor text_color; + gboolean seed; + + //TODO: Handle errors + + struct TorrentCellRendererPrivate * p = cell->priv; + //const tr_torrent * tor = p->tor; + //const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor ); + const gboolean active = ( p->flags & ~TORRENT_FLAG_PAUSED ) && ( p->flags & ~TORRENT_FLAG_DOWNLOADING_WAIT ) && ( p->flags & ~TORRENT_FLAG_SEEDING_WAIT ); + + const gboolean sensitive = active;// || st->error; + GString * gstr_stat = p->gstr1; + + icon = get_icon( cell, COMPACT_ICON_SIZE, widget ); + + g_string_truncate( gstr_stat, 0 ); + getShortStatusString( gstr_stat, cell ); + gtk_cell_renderer_get_padding( GTK_CELL_RENDERER( cell ), &xpad, &ypad ); + get_text_color( widget, cell, &text_color ); + + fill_area = *background_area; + fill_area.x += xpad; + fill_area.y += ypad; + fill_area.width -= xpad * 2; + fill_area.height -= ypad * 2; + icon_area = name_area = stat_area = prog_area = fill_area; + + g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); + gtr_cell_renderer_get_preferred_size( p->icon_renderer, widget, NULL, &size ); + icon_area.width = size.width; + g_object_set( p->text_renderer, "text", torrent_get_name(p->json), "ellipsize", PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &size ); + name_area.width = size.width; + g_object_set( p->text_renderer, "text", gstr_stat->str, "scale", SMALL_SCALE, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &size ); + stat_area.width = size.width; + + icon_area.x = fill_area.x; + prog_area.x = fill_area.x + fill_area.width - BAR_WIDTH; + prog_area.width = BAR_WIDTH; + stat_area.x = prog_area.x - GUI_PAD - stat_area.width; + name_area.x = icon_area.x + icon_area.width + GUI_PAD; + name_area.y = fill_area.y; + name_area.width = stat_area.x - GUI_PAD - name_area.x; + + /** + *** RENDER + **/ + + g_object_set( p->icon_renderer, "pixbuf", icon, "sensitive", sensitive, NULL ); + gtr_cell_renderer_render( p->icon_renderer, window, widget, &icon_area, flags ); + g_object_set( p->progress_renderer, "value", (gint)p->done, "text", NULL, "sensitive", sensitive, NULL ); + gtr_cell_renderer_render( p->progress_renderer, window, widget, &prog_area, flags ); + g_object_set( p->text_renderer, "text", gstr_stat->str, "scale", SMALL_SCALE, "ellipsize", PANGO_ELLIPSIZE_END, FOREGROUND_COLOR_KEY, &text_color, NULL ); + gtr_cell_renderer_render( p->text_renderer, window, widget, &stat_area, flags ); + g_object_set( p->text_renderer, "text", torrent_get_name(p->json), "scale", 1.0, FOREGROUND_COLOR_KEY, &text_color, NULL ); + gtr_cell_renderer_render( p->text_renderer, window, widget, &name_area, flags ); + + /* cleanup */ + g_object_unref( icon ); +} + +static void +render_full( TorrentCellRenderer * cell, + GtrDrawable * window, + GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags ) +{ + int xpad, ypad; + GtkRequisition size; + GdkRectangle fill_area; + GdkRectangle icon_area; + GdkRectangle name_area; + GdkRectangle stat_area; + GdkRectangle prog_area; + GdkRectangle prct_area; + GdkPixbuf * icon; + GtrColor text_color; + //gboolean seed; + + struct TorrentCellRendererPrivate * p = cell->priv; + const gboolean active = ( p->flags & ~TORRENT_FLAG_PAUSED ) && ( p->flags & ~TORRENT_FLAG_DOWNLOADING_WAIT ) && ( p->flags & ~TORRENT_FLAG_SEEDING_WAIT ); + const gboolean sensitive = active;// || st->error; + GString * gstr_prog = p->gstr1; + GString * gstr_stat = p->gstr2; + + icon = get_icon( cell, FULL_ICON_SIZE, widget ); + g_string_truncate( gstr_prog, 0 ); + getProgressString( gstr_prog, cell ); + g_string_truncate( gstr_stat, 0 ); + getStatusString( gstr_stat, cell ); + gtk_cell_renderer_get_padding( GTK_CELL_RENDERER( cell ), &xpad, &ypad ); + get_text_color( widget, cell, &text_color ); + + /* get the idealized cell dimensions */ + g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); + gtr_cell_renderer_get_preferred_size( p->icon_renderer, widget, NULL, &size ); + icon_area.width = size.width; + icon_area.height = size.height; + g_object_set( p->text_renderer, "text", torrent_get_name(p->json), "weight", PANGO_WEIGHT_BOLD, "ellipsize", PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &size ); + name_area.width = size.width; + name_area.height = size.height; + g_object_set( p->text_renderer, "text", gstr_prog->str, "weight", PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &size ); + prog_area.width = size.width; + prog_area.height = size.height; + g_object_set( p->text_renderer, "text", gstr_stat->str, NULL ); + gtr_cell_renderer_get_preferred_size( p->text_renderer, widget, NULL, &size ); + stat_area.width = size.width; + stat_area.height = size.height; + + /** + *** LAYOUT + **/ + + fill_area = *background_area; + fill_area.x += xpad; + fill_area.y += ypad; + fill_area.width -= xpad * 2; + fill_area.height -= ypad * 2; + + /* icon */ + icon_area.x = fill_area.x; + icon_area.y = fill_area.y + ( fill_area.height - icon_area.height ) / 2; + + /* name */ + name_area.x = icon_area.x + icon_area.width + GUI_PAD; + name_area.y = fill_area.y; + name_area.width = fill_area.width - GUI_PAD - icon_area.width - GUI_PAD_SMALL; + + /* prog */ + prog_area.x = name_area.x; + prog_area.y = name_area.y + name_area.height; + prog_area.width = name_area.width; + + /* progressbar */ + prct_area.x = prog_area.x; + prct_area.y = prog_area.y + prog_area.height + GUI_PAD_SMALL; + prct_area.width = prog_area.width; + prct_area.height = p->bar_height; + + /* status */ + stat_area.x = prct_area.x; + stat_area.y = prct_area.y + prct_area.height + GUI_PAD_SMALL; + stat_area.width = prct_area.width; + + /** + *** RENDER + **/ + + g_object_set( p->icon_renderer, "pixbuf", icon, "sensitive", sensitive, NULL ); + gtr_cell_renderer_render( p->icon_renderer, window, widget, &icon_area, flags ); + g_object_set( p->text_renderer, "text", torrent_get_name(p->json), "scale", 1.0, FOREGROUND_COLOR_KEY, &text_color, "ellipsize", PANGO_ELLIPSIZE_END, "weight", PANGO_WEIGHT_BOLD, NULL ); + gtr_cell_renderer_render( p->text_renderer, window, widget, &name_area, flags ); + g_object_set( p->text_renderer, "text", gstr_prog->str, "scale", SMALL_SCALE, "weight", PANGO_WEIGHT_NORMAL, NULL ); + gtr_cell_renderer_render( p->text_renderer, window, widget, &prog_area, flags ); + g_object_set( p->progress_renderer, "value", (gint)p->done, /*"text", "",*/ "sensitive", sensitive, NULL ); + gtr_cell_renderer_render( p->progress_renderer, window, widget, &prct_area, flags ); + g_object_set( p->text_renderer, "text", gstr_stat->str, FOREGROUND_COLOR_KEY, &text_color, NULL ); + gtr_cell_renderer_render( p->text_renderer, window, widget, &stat_area, flags ); + + /* cleanup */ + g_object_unref( icon ); +} diff --git a/src/torrent-cell-renderer.h b/src/torrent-cell-renderer.h new file mode 100644 index 0000000..7e59483 --- /dev/null +++ b/src/torrent-cell-renderer.h @@ -0,0 +1,51 @@ +/* + * This file Copyright (C) Mnemosyne LLC + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id: torrent-cell-renderer.h 12658 2011-08-09 05:47:24Z jordan $ + */ + +#ifndef GTR_TORRENT_CELL_RENDERER_H +#define GTR_TORRENT_CELL_RENDERER_H + +#include <gtk/gtk.h> + +#define GTR_UNICODE_UP "\xE2\x86\x91" +#define GTR_UNICODE_DOWN "\xE2\x86\x93" +#define DIRECTORY_MIME_TYPE "folder" +#define UNKNOWN_MIME_TYPE "unknown" + +#define TORRENT_CELL_RENDERER_TYPE ( torrent_cell_renderer_get_type( ) ) + +#define TORRENT_CELL_RENDERER( o ) \ + ( G_TYPE_CHECK_INSTANCE_CAST( ( o ), \ + TORRENT_CELL_RENDERER_TYPE, \ + TorrentCellRenderer ) ) + +typedef struct TorrentCellRenderer TorrentCellRenderer; + +typedef struct TorrentCellRendererClass TorrentCellRendererClass; + +struct TorrentCellRenderer +{ + GtkCellRenderer parent; + + /*< private >*/ + struct TorrentCellRendererPrivate * priv; +}; + +struct TorrentCellRendererClass +{ + GtkCellRendererClass parent; +}; + +GType torrent_cell_renderer_get_type( void ) G_GNUC_CONST; + +GtkCellRenderer * torrent_cell_renderer_new( void ); + +#endif /* GTR_TORRENT_CELL_RENDERER_H */ diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c index cf490c3..2df9603 100644 --- a/src/trg-torrent-model.c +++ b/src/trg-torrent-model.c @@ -199,8 +199,8 @@ static void trg_torrent_model_init(TrgTorrentModel * self) column_types[TORRENT_COLUMN_ICON] = G_TYPE_STRING; column_types[TORRENT_COLUMN_NAME] = G_TYPE_STRING; - column_types[TORRENT_COLUMN_SIZE] = G_TYPE_INT64; - column_types[TORRENT_COLUMN_DONE] = G_TYPE_DOUBLE; + column_types[TORRENT_COLUMN_SIZEWHENDONE] = G_TYPE_INT64; + column_types[TORRENT_COLUMN_PERCENTDONE] = G_TYPE_DOUBLE; column_types[TORRENT_COLUMN_STATUS] = G_TYPE_STRING; column_types[TORRENT_COLUMN_SEEDS] = G_TYPE_INT64; column_types[TORRENT_COLUMN_LEECHERS] = G_TYPE_INT64; @@ -475,9 +475,9 @@ update_torrent_iter(TrgTorrentModel * model, gtk_list_store_set(ls, iter, TORRENT_COLUMN_NAME, torrent_get_name(t), -1); gtk_list_store_set(ls, iter, - TORRENT_COLUMN_SIZE, torrent_get_size(t), -1); + TORRENT_COLUMN_SIZEWHENDONE, torrent_get_size(t), -1); gtk_list_store_set(ls, iter, - TORRENT_COLUMN_DONE, + TORRENT_COLUMN_PERCENTDONE, (newFlags & TORRENT_FLAG_CHECKING) ? torrent_get_recheck_progress(t) : torrent_get_percent_done(t), -1); @@ -540,8 +540,8 @@ update_torrent_iter(TrgTorrentModel * model, TORRENT_COLUMN_ADDED, torrent_get_added_date(t), TORRENT_COLUMN_DONE_DATE, torrent_get_done_date(t), TORRENT_COLUMN_NAME, torrent_get_name(t), - TORRENT_COLUMN_SIZE, torrent_get_size(t), - TORRENT_COLUMN_DONE, + TORRENT_COLUMN_SIZEWHENDONE, torrent_get_size(t), + TORRENT_COLUMN_PERCENTDONE, (newFlags & TORRENT_FLAG_CHECKING) ? torrent_get_recheck_progress(t) : torrent_get_percent_done(t), diff --git a/src/trg-torrent-model.h b/src/trg-torrent-model.h index 9711fda..ddc5e98 100644 --- a/src/trg-torrent-model.h +++ b/src/trg-torrent-model.h @@ -104,8 +104,8 @@ void trg_torrent_model_reload_dir_aliases(TrgClient * tc, enum { TORRENT_COLUMN_ICON, TORRENT_COLUMN_NAME, - TORRENT_COLUMN_SIZE, - TORRENT_COLUMN_DONE, + TORRENT_COLUMN_SIZEWHENDONE, + TORRENT_COLUMN_PERCENTDONE, TORRENT_COLUMN_STATUS, TORRENT_COLUMN_SEEDS, TORRENT_COLUMN_LEECHERS, diff --git a/src/trg-torrent-tree-view.c b/src/trg-torrent-tree-view.c index c60f306..87208a2 100644 --- a/src/trg-torrent-tree-view.c +++ b/src/trg-torrent-tree-view.c @@ -23,6 +23,7 @@ #include "trg-prefs.h" #include "trg-tree-view.h" #include "trg-torrent-model.h" +#include "torrent-cell-renderer.h" #include "trg-torrent-tree-view.h" G_DEFINE_TYPE(TrgTorrentTreeView, trg_torrent_tree_view, @@ -43,9 +44,9 @@ static void trg_torrent_tree_view_init(TrgTorrentTreeView * tttv) 0); desc->model_column_extra = TORRENT_COLUMN_ICON; - trg_tree_view_reg_column(ttv, TRG_COLTYPE_SIZE, TORRENT_COLUMN_SIZE, + trg_tree_view_reg_column(ttv, TRG_COLTYPE_SIZE, TORRENT_COLUMN_SIZEWHENDONE, _("Size"), "size", 0); - trg_tree_view_reg_column(ttv, TRG_COLTYPE_PROG, TORRENT_COLUMN_DONE, + trg_tree_view_reg_column(ttv, TRG_COLTYPE_PROG, TORRENT_COLUMN_PERCENTDONE, _("Done"), "done", 0); trg_tree_view_reg_column(ttv, TRG_COLTYPE_TEXT, TORRENT_COLUMN_STATUS, _("Status"), "status", 0); @@ -131,7 +132,6 @@ static void trg_torrent_tree_view_init(TrgTorrentTreeView * tttv) TORRENT_COLUMN_LASTACTIVE, _("Last Active"), "last-active", TRG_COLUMN_EXTRA); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(tttv), TORRENT_COLUMN_NAME); } @@ -163,6 +163,38 @@ JsonArray *build_json_id_array(TrgTorrentTreeView * tv) return ids; } +static void setup_classic_layout(TrgTorrentTreeView *tv) +{ + GtkCellRenderer *renderer = torrent_cell_renderer_new(); + GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("", + renderer, + "status", TORRENT_COLUMN_FLAGS, + "ratio", TORRENT_COLUMN_RATIO, + "downloaded", TORRENT_COLUMN_DOWNLOADED, + "sizeWhenDone", TORRENT_COLUMN_SIZEWHENDONE, + "uploaded", TORRENT_COLUMN_UPLOADED, + "percentComplete", TORRENT_COLUMN_PERCENTDONE, + "upSpeed", TORRENT_COLUMN_UPSPEED, + "downSpeed", TORRENT_COLUMN_DOWNSPEED, + "peersToUs", TORRENT_COLUMN_PEERS_TO_US, + "peersGettingFromUs", TORRENT_COLUMN_PEERS_FROM_US, + "eta", TORRENT_COLUMN_ETA, + "json", TORRENT_COLUMN_JSON, + "connected", TORRENT_COLUMN_PEERS_CONNECTED, + NULL); + + //gtk_tree_view_column_set_min_width(column, 0); + gtk_tree_view_column_set_resizable(column, FALSE); + gtk_tree_view_column_set_reorderable(column, FALSE); + gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(tv), FALSE); + gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tv), FALSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tv), FALSE); + + gtk_tree_view_column_set_sort_column_id(column, TORRENT_COLUMN_NAME); + + gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); +} + TrgTorrentTreeView *trg_torrent_tree_view_new(TrgPrefs * prefs, GtkTreeModel * model) { @@ -170,7 +202,8 @@ TrgTorrentTreeView *trg_torrent_tree_view_new(TrgPrefs * prefs, trg_tree_view_set_prefs(TRG_TREE_VIEW(obj), prefs); gtk_tree_view_set_model(GTK_TREE_VIEW(obj), model); - trg_tree_view_setup_columns(TRG_TREE_VIEW(obj)); + //trg_tree_view_setup_columns(TRG_TREE_VIEW(obj)); + setup_classic_layout(TRG_TORRENT_TREE_VIEW(obj)); trg_tree_view_restore_sort(TRG_TREE_VIEW(obj), TRUE); diff --git a/src/trg-tree-view.c b/src/trg-tree-view.c index 2e3e78e..47ffabd 100644 --- a/src/trg-tree-view.c +++ b/src/trg-tree-view.c @@ -464,6 +464,11 @@ void trg_tree_view_persist(TrgTreeView * tv, gboolean parentIsSortable) GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tv)); GList *cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(tv)); + if (cols && g_object_get_data(G_OBJECT(cols->data), "column-desc") == NULL) { + g_list_free(cols); + return; + } + GList *li; gint sort_column_id; GtkSortType sort_type; @@ -573,6 +573,17 @@ evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap) #endif } +char* +tr_strlsize( char * buf, guint64 bytes, size_t buflen ) +{ + if( !bytes ) + g_strlcpy( buf, Q_( "None" ), buflen ); + else + tr_formatter_size_B( buf, bytes, buflen ); + + return buf; +} + gboolean is_minimised_arg(const gchar * arg) { return !g_strcmp0(arg, "-m") @@ -85,6 +85,8 @@ size_t tr_strlcpy(char *dst, const void *src, size_t siz); double tr_truncd(double x, int decimal_places); int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap); +char* +tr_strlsize( char * buf, guint64 bytes, size_t buflen ); void rm_trailing_slashes(gchar * str); void trg_widget_set_visible(GtkWidget * w, gboolean visible); gchar *trg_base64encode(const gchar * filename); |