source: trunk/gtk/util.c @ 5169

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

(gtk) make verrmsg_full() private

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