source: trunk/gtk/util.c @ 5220

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

(gtk) r5212 tr_strltime() cleanup

  • Property svn:keywords set to Date Rev Author Id
File size: 11.0 KB
Line 
1/******************************************************************************
2 * $Id: util.c 5220 2008-03-07 19:27:46Z 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    if( !size )
73        g_strlcpy( buf, _( "None" ), buflen );
74#if GLIB_CHECK_VERSION(2,16,0)
75    else{ 
76        char * tmp = g_format_size_for_display( s );
77        g_strlcpy( buf, tmp, buflen );
78        g_free( tmp );
79    }
80#else
81    else if( size < (guint64)KILOBYTE_FACTOR )
82        g_snprintf( buf, buflen, ngettext("%u byte", "%u bytes", (guint)size), (guint)size );
83    else {
84        gdouble displayed_size;
85        if (size < (guint64)MEGABYTE_FACTOR) {
86            displayed_size = (gdouble) size / KILOBYTE_FACTOR;
87            g_snprintf( buf, buflen, _("%.1f KB"), displayed_size );
88        } else if (size < (guint64)GIGABYTE_FACTOR) {
89            displayed_size = (gdouble) size / MEGABYTE_FACTOR;
90            g_snprintf( buf, buflen, _("%.1f MB"), displayed_size );
91        } else {
92            displayed_size = (gdouble) size / GIGABYTE_FACTOR;
93            g_snprintf( buf, buflen, _("%.1f GB"), displayed_size );
94        }
95    }
96#endif
97    return buf;
98}
99
100char*
101tr_strlspeed( char * buf, double KiBps, size_t buflen )
102{
103    const double speed = KiBps;
104
105    if ( speed < 1000.0 ) /* 0.0 KB to 999.9 KB */
106        g_snprintf( buf, buflen, _( "%.1f KB/s" ), speed );
107    else if( speed < 102400.0 ) /* 0.98 MB to 99.99 MB */
108        g_snprintf( buf, buflen, _( "%.2f MB/s" ), (speed/1024) );
109    else if( speed < 1024000.0 ) /* 100.0 MB to 999.9 MB */
110        g_snprintf( buf, buflen, _( "%.1f MB/s" ), (speed/1024) );
111    else /* insane speeds */
112        g_snprintf( buf, buflen, _( "%.2f GB/s" ), (speed/1048576) );
113
114    return buf;
115}
116
117char*
118tr_strltime( char * buf, int seconds, size_t buflen )
119{
120    int hours;
121
122    if( seconds < 0 )
123        seconds = 0;
124
125    if( seconds < 60 )
126    {
127        g_snprintf( buf, buflen, ngettext( "%'d second", "%'d seconds", (int)seconds ), (int) seconds );
128        return buf;
129    }
130
131    if( seconds < ( 60 * 60 ) )
132    {
133        const int minutes = ( seconds + 30 ) / 60;
134        g_snprintf( buf, buflen, ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
135        return buf;
136    }
137
138    hours = seconds / ( 60 *60 );
139
140    if( seconds < ( 60 * 60 * 4 ) )
141    {
142        char h[64];
143        char m[64];
144
145        const int minutes = ( seconds - hours * 60 * 60 + 30 ) / 60;
146
147        g_snprintf( h, sizeof(h), ngettext( "%'d hour", "%'d hours", hours ), hours );
148        g_snprintf( m, sizeof(m), ngettext( "%'d minute", "%'d minutes", minutes ), minutes );
149        g_snprintf( buf, buflen, "%s, %s", h, m );
150        return buf;
151    }
152
153    g_snprintf( buf, buflen, ngettext( "%'d hour", "%'d hours", hours ), hours );
154    return buf;
155}
156
157
158char *
159rfc822date (guint64 epoch_msec)
160{
161    const time_t secs = epoch_msec / 1000;
162    const struct tm tm = *localtime (&secs);
163    char buf[128];
164    strftime( buf, sizeof(buf), "%a, %d %b %Y %T %Z", &tm );
165    return g_locale_to_utf8( buf, -1, NULL, NULL, NULL );
166}
167
168gboolean
169mkdir_p( const char * path, mode_t mode )
170{
171#if GLIB_CHECK_VERSION( 2, 8, 0)
172    return !g_mkdir_with_parents( path, mode );
173#else
174    return !tr_mkdirp( path, mode );
175#endif
176}
177
178GList *
179dupstrlist( GList * l )
180{
181    GList * ret = NULL;
182    for( ; l!=NULL; l=l->next )
183        ret = g_list_prepend( ret, g_strdup( l->data ) );
184    return g_list_reverse( ret );
185}
186
187char *
188joinstrlist(GList *list, char *sep)
189{
190  GList *l;
191  GString *gstr = g_string_new (NULL);
192  for (l=list; l!=NULL; l=l->next) {
193    g_string_append (gstr, (char*)l->data);
194    if (l->next != NULL)
195      g_string_append (gstr, (sep));
196  }
197  return g_string_free (gstr, FALSE);
198}
199
200void
201freestrlist(GList *list)
202{
203  g_list_foreach (list, (GFunc)g_free, NULL);
204  g_list_free (list);
205}
206
207char *
208decode_uri( const char * uri )
209{
210    char * filename = evhttp_decode_uri( uri );
211    char * ret = g_strdup( filename );
212    free( filename );
213    return ret;
214}
215
216GList *
217checkfilenames( int argc, char **argv )
218{
219    int i;
220    GList * ret = NULL;
221    char * pwd = g_get_current_dir( );
222
223    for( i=0; i<argc; ++i )
224    {
225        char * filename = g_path_is_absolute( argv[i] )
226            ? g_strdup ( argv[i] )
227            : g_build_filename( pwd, argv[i], NULL );
228
229        if( g_file_test( filename, G_FILE_TEST_EXISTS ) )
230            ret = g_list_append( ret, filename );
231        else
232            g_free( filename );
233    }
234
235    g_free( pwd );
236    return ret;
237}
238
239char *
240getdownloaddir( void )
241{
242    static char * wd = NULL;
243    char * dir = pref_string_get( PREF_KEY_DIR_DEFAULT );
244    if ( dir == NULL ) {
245        if( wd == NULL )
246            wd = g_get_current_dir();
247        dir = g_strdup( wd );
248    }
249    return dir;
250}
251
252/**
253 * don't use more than 50% the height of the screen, nor 80% the width.
254 * but don't be too small, either -- set the minimums to 500 x 300
255 */
256void
257sizingmagic( GtkWindow         * wind,
258             GtkScrolledWindow * scroll,
259             GtkPolicyType       hscroll,
260             GtkPolicyType       vscroll )
261{
262    int width;
263    int height;
264    GtkRequisition req;
265
266    GdkScreen * screen = gtk_widget_get_screen( GTK_WIDGET( wind ) );
267
268    gtk_scrolled_window_set_policy( scroll, GTK_POLICY_NEVER,
269                                            GTK_POLICY_NEVER );
270
271    gtk_widget_size_request( GTK_WIDGET( wind ), &req );
272    req.height = MAX( req.height, 300 );
273    height = MIN( req.height, gdk_screen_get_height( screen ) / 5 * 4 );
274
275    gtk_scrolled_window_set_policy( scroll, GTK_POLICY_NEVER, vscroll );
276    gtk_widget_size_request( GTK_WIDGET( wind ), &req );
277    req.width = MAX( req.width, 500 );
278    width = MIN( req.width, gdk_screen_get_width( screen ) / 2 );
279
280    gtk_window_set_default_size( wind, width, height );
281    gtk_scrolled_window_set_policy( scroll, hscroll, vscroll );
282}
283
284static void
285errcb(GtkWidget *widget, int resp UNUSED, gpointer data) {
286  GList *funcdata;
287  callbackfunc_t func;
288
289  if(NULL != data) {
290    funcdata = g_list_first(data);
291    func = (callbackfunc_t) funcdata->data;
292    data = funcdata->next->data;
293    func(data);
294    g_list_free(funcdata);
295  }
296
297  gtk_widget_destroy(widget);
298}
299
300static GtkWidget *
301verrmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
302              const char * format, va_list ap )
303{
304  GtkWidget *dialog;
305  char *msg;
306  GList *funcdata;
307
308  msg = g_strdup_vprintf(format, ap);
309
310  if(NULL == wind)
311    dialog = gtk_message_dialog_new(
312      NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
313  else
314    dialog = gtk_message_dialog_new(wind,
315      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
316      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
317
318  if(NULL == func)
319    funcdata = NULL;
320  else
321      funcdata = g_list_append(g_list_append(NULL, (void *) func), data);
322  g_signal_connect(dialog, "response", G_CALLBACK(errcb), funcdata);
323  g_free(msg);
324
325  return dialog;
326}
327
328void
329errmsg( GtkWindow * wind, const char * format, ... )
330{
331    GtkWidget * dialog;
332    va_list     ap;
333
334    va_start( ap, format );
335    dialog = verrmsg_full( wind, NULL, NULL, format, ap );
336    va_end( ap );
337
338    if( NULL != wind && !GTK_WIDGET_MAPPED( GTK_WIDGET( wind ) ) )
339    {
340        g_signal_connect_swapped( wind, "map",
341                                  G_CALLBACK( gtk_widget_show ), dialog );
342    }
343    else
344    {
345        gtk_widget_show( dialog );
346    }
347}
348
349GtkWidget *
350errmsg_full( GtkWindow * wind, callbackfunc_t func, void * data,
351             const char * format, ... )
352{
353    GtkWidget * dialog;
354    va_list     ap;
355
356    va_start( ap, format );
357    dialog = verrmsg_full( wind, func, data, format, ap );
358    va_end( ap );
359
360    return dialog;
361}
362
363typedef void (PopupFunc)(GtkWidget*, GdkEventButton*); 
364
365/* pop up the context menu if a user right-clicks.
366   if the row they right-click on isn't selected, select it. */
367
368gboolean
369on_tree_view_button_pressed (GtkWidget       * view,
370                             GdkEventButton  * event,
371                             gpointer          func)
372{
373  GtkTreeView * tv = GTK_TREE_VIEW( view );
374
375  if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3)
376  {
377    GtkTreeSelection * selection = gtk_tree_view_get_selection(tv);
378    GtkTreePath *path;
379    if (gtk_tree_view_get_path_at_pos (tv,
380                                       (gint) event->x,
381                                       (gint) event->y,
382                                       &path, NULL, NULL, NULL))
383    {
384      if (!gtk_tree_selection_path_is_selected (selection, path))
385      {
386        gtk_tree_selection_unselect_all (selection);
387        gtk_tree_selection_select_path (selection, path);
388      }
389      gtk_tree_path_free(path);
390    }
391   
392    ((PopupFunc*)func)(view, event);
393
394    return TRUE;
395  }
396
397  return FALSE;
398}
399
400gpointer
401tr_object_ref_sink( gpointer object )
402{
403#if GLIB_CHECK_VERSION(2,10,0)
404    g_object_ref_sink( object );
405#else
406    g_object_ref( object );
407    gtk_object_sink( GTK_OBJECT( object ) );
408#endif
409    return object;
410}
Note: See TracBrowser for help on using the repository browser.