source: trunk/gtk/util.c @ 5212

Last change on this file since 5212 was 5212, checked in by charles, 14 years ago

(gtk) use g_format_size_for_display() for file size, and behave like nautilus for displaying ETA

  • Property svn:keywords set to Date Rev Author Id
File size: 10.9 KB
Line 
1/******************************************************************************
2 * $Id: util.c 5212 2008-03-07 15:16:25Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <stdarg.h>
26#include <stdlib.h> /* free() */
27#include <string.h> /* strcmp() */
28
29#include <gtk/gtk.h>
30#include <glib/gi18n.h>
31
32#include <libevent/evhttp.h>
33
34#include <libtransmission/transmission.h> /* TR_RATIO_NA, TR_RATIO_INF */
35
36#include "conf.h"
37#include "tr-prefs.h"
38#include "util.h"
39
40int
41tr_strcmp( const char * a, const char * b )
42{
43    if( a && b ) return strcmp( a, b );
44    if( a ) return 1;
45    if( b ) return -1;
46    return 0;
47}
48
49char*
50tr_strlratio( char * buf, double ratio, size_t buflen )
51{
52    if( (int)ratio == TR_RATIO_NA )
53        g_strlcpy( buf, _( "None" ), buflen );
54    else if( (int)ratio == TR_RATIO_INF )
55        g_strlcpy( buf, "\xE2\x88\x9E", buflen );
56    else if( ratio < 10.0 )
57        g_snprintf( buf, buflen, "%.2f", ratio );
58    else if( ratio < 100.0 )
59        g_snprintf( buf, buflen, "%.1f", ratio );
60    else
61        g_snprintf( buf, buflen, "%.0f", ratio );
62    return buf;
63}
64
65#define KILOBYTE_FACTOR 1024.0
66#define MEGABYTE_FACTOR (1024.0 * 1024.0)
67#define GIGABYTE_FACTOR (1024.0 * 1024.0 * 1024.0)
68
69char*
70tr_strlsize( char * buf, guint64 size, size_t buflen )
71{
72    const goffset s = (goffset)size;
73#if GLIB_CHECK_VERSION(2,16,0)
74    char * tmp = g_format_size_for_display( s );
75    g_strlcpy( buf, tmp, buflen );
76    g_free( tmp );
77#else
78    if ( s < (goffset)KILOBYTE_FACTOR )
79        g_snprintf( buf, buflen, ngettext("%u byte", "%u bytes", (guint)s), (guint)s );
80    else {
81        gdouble displayed_size;
82        if (size < (goffset) MEGABYTE_FACTOR) {
83            displayed_size = (gdouble) size / KILOBYTE_FACTOR;
84            g_snprintf( buf, buflen, _("%.1f KB"), displayed_size );
85        } else if (size < (goffset) GIGABYTE_FACTOR) {
86            displayed_size = (gdouble) size / MEGABYTE_FACTOR;
87            g_snprintf( buf, buflen, _("%.1f MB"), displayed_size );
88        } else {
89            displayed_size = (gdouble) size / GIGABYTE_FACTOR;
90            g_snprintf( buf, buflen, _("%.1f GB"), displayed_size );
91        }
92    }
93#endif
94    return buf;
95}
96
97char*
98tr_strlspeed( char * buf, double KiBps, size_t buflen )
99{
100    const double speed = KiBps;
101
102    if ( speed < 1000.0 ) /* 0.0 KB to 999.9 KB */
103        g_snprintf( buf, buflen, _( "%.1f KB/s" ), speed );
104    else if( speed < 102400.0 ) /* 0.98 MB to 99.99 MB */
105        g_snprintf( buf, buflen, _( "%.2f MB/s" ), (speed/1024) );
106    else if( speed < 1024000.0 ) /* 100.0 MB to 999.9 MB */
107        g_snprintf( buf, buflen, _( "%.1f MB/s" ), (speed/1024) );
108    else /* insane speeds */
109        g_snprintf( buf, buflen, _( "%.2f GB/s" ), (speed/1048576) );
110
111    return buf;
112}
113
114char*
115tr_strltime( char * buf, int seconds, size_t buflen )
116{
117    int hours;
118
119    if( seconds < 0 )
120        seconds = 0;
121
122    if( seconds < 60 )
123    {
124        g_snprintf( buf, sizeof( buf ), ngettext( "%'d second", "%'d seconds", (int)seconds ), (int) seconds );
125        return buf;
126    }
127
128    if( seconds < ( 60 * 60 ) )
129    {
130        const int minutes = ( seconds + 30 ) / 60;
131        g_snprintf( buf, sizeof( buf ), ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
132        return buf;
133    }
134
135    hours = seconds / ( 60 *60 );
136
137    if( seconds < ( 60 * 60 * 4 ) )
138    {
139        char h[64];
140        char m[64];
141
142        const int minutes = ( seconds - hours * 60 * 60 + 30 ) / 60;
143
144        g_snprintf( h, sizeof(h), ngettext( "%'d hour", "%'d hours", hours ), hours );
145        g_snprintf( m, sizeof(m), ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
146        g_snprintf( buf, buflen, "%s, %s", h, m );
147        return buf;
148    }
149
150    g_snprintf( buf, sizeof( buf ), ngettext( "%'d hour", "%'d hours", hours ), hours );
151    return buf;
152}
153
154
155char *
156rfc822date (guint64 epoch_msec)
157{
158    const time_t secs = epoch_msec / 1000;
159    const struct tm tm = *localtime (&secs);
160    char buf[128];
161    strftime( buf, sizeof(buf), "%a, %d %b %Y %T %Z", &tm );
162    return g_locale_to_utf8( buf, -1, NULL, NULL, NULL );
163}
164
165gboolean
166mkdir_p( const char * path, mode_t mode )
167{
168#if GLIB_CHECK_VERSION( 2, 8, 0)
169    return !g_mkdir_with_parents( path, mode );
170#else
171    return !tr_mkdirp( path, mode );
172#endif
173}
174
175GList *
176dupstrlist( GList * l )
177{
178    GList * ret = NULL;
179    for( ; l!=NULL; l=l->next )
180        ret = g_list_prepend( ret, g_strdup( l->data ) );
181    return g_list_reverse( ret );
182}
183
184char *
185joinstrlist(GList *list, char *sep)
186{
187  GList *l;
188  GString *gstr = g_string_new (NULL);
189  for (l=list; l!=NULL; l=l->next) {
190    g_string_append (gstr, (char*)l->data);
191    if (l->next != NULL)
192      g_string_append (gstr, (sep));
193  }
194  return g_string_free (gstr, FALSE);
195}
196
197void
198freestrlist(GList *list)
199{
200  g_list_foreach (list, (GFunc)g_free, NULL);
201  g_list_free (list);
202}
203
204char *
205decode_uri( const char * uri )
206{
207    char * filename = evhttp_decode_uri( uri );
208    char * ret = g_strdup( filename );
209    free( filename );
210    return ret;
211}
212
213GList *
214checkfilenames( int argc, char **argv )
215{
216    int i;
217    GList * ret = NULL;
218    char * pwd = g_get_current_dir( );
219
220    for( i=0; i<argc; ++i )
221    {
222        char * filename = g_path_is_absolute( argv[i] )
223            ? g_strdup ( argv[i] )
224            : g_build_filename( pwd, argv[i], NULL );
225
226        if( g_file_test( filename, G_FILE_TEST_EXISTS ) )
227            ret = g_list_append( ret, filename );
228        else
229            g_free( filename );
230    }
231
232    g_free( pwd );
233    return ret;
234}
235
236char *
237getdownloaddir( void )
238{
239    static char * wd = NULL;
240    char * dir = pref_string_get( PREF_KEY_DIR_DEFAULT );
241    if ( dir == NULL ) {
242        if( wd == NULL )
243            wd = g_get_current_dir();
244        dir = g_strdup( wd );
245    }
246    return dir;
247}
248
249/**
250 * don't use more than 50% the height of the screen, nor 80% the width.
251 * but don't be too small, either -- set the minimums to 500 x 300
252 */
253void
254sizingmagic( GtkWindow         * wind,
255             GtkScrolledWindow * scroll,
256             GtkPolicyType       hscroll,
257             GtkPolicyType       vscroll )
258{
259    int width;
260    int height;
261    GtkRequisition req;
262
263    GdkScreen * screen = gtk_widget_get_screen( GTK_WIDGET( wind ) );
264
265    gtk_scrolled_window_set_policy( scroll, GTK_POLICY_NEVER,
266                                            GTK_POLICY_NEVER );
267
268    gtk_widget_size_request( GTK_WIDGET( wind ), &req );
269    req.height = MAX( req.height, 300 );
270    height = MIN( req.height, gdk_screen_get_height( screen ) / 5 * 4 );
271
272    gtk_scrolled_window_set_policy( scroll, GTK_POLICY_NEVER, vscroll );
273    gtk_widget_size_request( GTK_WIDGET( wind ), &req );
274    req.width = MAX( req.width, 500 );
275    width = MIN( req.width, gdk_screen_get_width( screen ) / 2 );
276
277    gtk_window_set_default_size( wind, width, height );
278    gtk_scrolled_window_set_policy( scroll, hscroll, vscroll );
279}
280
281static void
282errcb(GtkWidget *widget, int resp UNUSED, gpointer data) {
283  GList *funcdata;
284  callbackfunc_t func;
285
286  if(NULL != data) {
287    funcdata = g_list_first(data);
288    func = (callbackfunc_t) funcdata->data;
289    data = funcdata->next->data;
290    func(data);
291    g_list_free(funcdata);
292  }
293
294  gtk_widget_destroy(widget);
295}
296
297static GtkWidget *
298verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
299              const char * format, va_list ap )
300{
301  GtkWidget *dialog;
302  char *msg;
303  GList *funcdata;
304
305  msg = g_strdup_vprintf(format, ap);
306
307  if(NULL == wind)
308    dialog = gtk_message_dialog_new(
309      NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
310  else
311    dialog = gtk_message_dialog_new(wind,
312      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
313      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
314
315  if(NULL == func)
316    funcdata = NULL;
317  else
318      funcdata = g_list_append(g_list_append(NULL, (void *) func), data);
319  g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
320  g_free(msg);
321
322  return dialog;
323}
324
325void
326errmsg( GtkWindow * wind, const char * format, ... )
327{
328    GtkWidget * dialog;
329    va_list     ap;
330
331    va_start( ap, format );
332    dialog = verrmsg_full( wind, NULL, NULL, format, ap );
333    va_end( ap );
334
335    if( NULL != wind && !GTK_WIDGET_MAPPED( GTK_WIDGET( wind ) ) )
336    {
337        g_signal_connect_swapped( wind, "map",
338                                  G_CALLBACK( gtk_widget_show ), dialog );
339    }
340    else
341    {
342        gtk_widget_show( dialog );
343    }
344}
345
346GtkWidget *
347errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
348             const char * format, ... )
349{
350    GtkWidget * dialog;
351    va_list     ap;
352
353    va_start( ap, format );
354    dialog = verrmsg_full( wind, func, data, format, ap );
355    va_end( ap );
356
357    return dialog;
358}
359
360typedef void (PopupFunc)(GtkWidget*, GdkEventButton*); 
361
362/* pop up the context menu if a user right-clicks.
363   if the row they right-click on isn't selected, select it. */
364
365gboolean
366on_tree_view_button_pressed (GtkWidget       * view,
367                             GdkEventButton  * event,
368                             gpointer          func)
369{
370  GtkTreeView * tv = GTK_TREE_VIEW( view );
371
372  if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3)
373  {
374    GtkTreeSelection * selection = gtk_tree_view_get_selection(tv);
375    GtkTreePath *path;
376    if (gtk_tree_view_get_path_at_pos (tv,
377                                       (gint) event->x,
378                                       (gint) event->y,
379                                       &path, NULL, NULL, NULL))
380    {
381      if (!gtk_tree_selection_path_is_selected (selection, path))
382      {
383        gtk_tree_selection_unselect_all (selection);
384        gtk_tree_selection_select_path (selection, path);
385      }
386      gtk_tree_path_free(path);
387    }
388   
389    ((PopupFunc*)func)(view, event);
390
391    return TRUE;
392  }
393
394  return FALSE;
395}
396
397gpointer
398tr_object_ref_sink( gpointer object )
399{
400#if GLIB_CHECK_VERSION(2,10,0)
401    g_object_ref_sink( object );
402#else
403    g_object_ref( object );
404    gtk_object_sink( GTK_OBJECT( object ) );
405#endif
406    return object;
407}
Note: See TracBrowser for help on using the repository browser.