Improved the tooltip on the Gnome applet.
[doldaconnect.git] / clients / gnome-trans-applet / dolcon-trans-applet.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2005 Fredrik Tolf <fredrik@dolda2000.com>
4  *  
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *  
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *  
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <string.h>
24 #include <doldaconnect/uilib.h>
25 #include <doldaconnect/utils.h>
26 #include <panel-applet.h>
27 #include <gtk/gtk.h>
28 #include <time.h>
29
30 #include "conduit.h"
31
32 struct appletdata
33 {
34     PanelApplet *applet;
35     GtkLabel *label;
36     GtkProgressBar *pbar;
37     GtkTooltips *tips;
38     gint tiptimeout;
39     struct conduit *conduit;
40     struct transfer *curdisplay;
41 };
42
43 static char *ctxtmenu =
44 "<popup name='button3'>"
45 "    <menuitem name='Preferences' verb='dca_pref' _label='Preferences' pixtype='stock' pixname='gtk-properties' />"
46 "    <menuitem name='Cancel transfer' verb='dca_cancel' _label='Cancel transfer' pixtype='stock' pixname='gtk-cancel' />"
47 "</popup>";
48
49 static void run_pref_dialog(BonoboUIComponent *uic, gpointer data, const char *cname)
50 {
51 }
52
53 static void cancel_transfer(BonoboUIComponent *uic, struct appletdata *data, const char *cname)
54 {
55     if(data->conduit->iface->cancel != NULL)
56         data->conduit->iface->cancel(data->conduit, data->curdisplay);
57 }
58
59 static BonoboUIVerb ctxtmenuverbs[] =
60 {
61     BONOBO_UI_VERB("dca_pref", run_pref_dialog),
62     BONOBO_UI_VERB("dca_cancel", (void (*)(BonoboUIComponent*, gpointer, const char *))cancel_transfer),
63     BONOBO_UI_VERB_END
64 };
65
66 static gint reconncb(struct appletdata *data)
67 {
68     condtryconn(data->conduit);
69     return(FALSE);
70 }
71
72 static gboolean updatetip(struct appletdata *data)
73 {
74     int diff, speed, left;
75     time_t now;
76     char buf[256];
77     
78     if(data->curdisplay == NULL) {
79         gtk_tooltips_set_tip(data->tips, GTK_WIDGET(data->applet), _("No transfer selected"), NULL);
80         return(TRUE);
81     }
82     now = time(NULL);
83     if(data->curdisplay->cmptime == 0)
84     {
85         strcpy(buf, _("Calculating remaining time..."));
86     } else {
87         diff = data->curdisplay->pos - data->curdisplay->cmpsize;
88         speed = diff / (now - data->curdisplay->cmptime);
89         if(speed == 0)
90         {
91             strcpy(buf, _("Time left: Infinite (Transfer is standing still)"));
92         } else {
93             left = (data->curdisplay->size - data->curdisplay->pos) / speed;
94             if(left >= 86400)
95                 sprintf(buf, _("Time left: %id%02ih%02im"), left / 86400, (left / 3600) % 24, (left / 60) % 60);
96             else if(left >= 3600)
97                 sprintf(buf, _("Time left: %ih%02im"), left / 3600, (left / 60) % 60);
98             else
99                 sprintf(buf, _("Time left: %im"), left / 60);
100         }
101     }
102     gtk_tooltips_set_tip(data->tips, GTK_WIDGET(data->applet), buf, NULL);
103     return(TRUE);
104 }
105
106 static void update(struct appletdata *data)
107 {
108     char buf[256];
109     size_t l;
110     
111     switch(data->conduit->state)
112     {
113     case CNDS_IDLE:
114         gtk_progress_bar_set_text(data->pbar, _("Not connected"));
115         gtk_label_set_text(data->label, "");
116         break;
117     case CNDS_SYN:
118         gtk_progress_bar_set_text(data->pbar, _("Connecting..."));
119         gtk_label_set_text(data->label, "");
120         break;
121     case CNDS_EST:
122         if(data->conduit->transfers == NULL)
123         {
124             gtk_progress_bar_set_fraction(data->pbar, 0);
125             gtk_progress_bar_set_text(data->pbar, "");
126             gtk_label_set_text(data->label, _("No transfers to display"));
127         } else if(data->curdisplay == NULL) {
128             gtk_progress_bar_set_fraction(data->pbar, 0);
129             gtk_progress_bar_set_text(data->pbar, "");
130             gtk_label_set_text(data->label, _("No transfer selected"));
131         } else {
132             if((data->curdisplay->pos > 0) && (data->curdisplay->size > 0))
133             {
134                 sprintf(buf, "%'ji/%'ji", (intmax_t)data->curdisplay->pos, (intmax_t)data->curdisplay->size);
135                 gtk_progress_bar_set_fraction(data->pbar, (double)data->curdisplay->pos / (double)data->curdisplay->size);
136                 gtk_progress_bar_set_text(data->pbar, buf);
137             } else {
138                 gtk_progress_bar_set_fraction(data->pbar, 0);
139                 gtk_progress_bar_set_text(data->pbar, _("Initializing"));
140             }
141             if((l = strlen(data->curdisplay->tag)) > 50) {
142                 memcpy(buf, data->curdisplay->tag, 20);
143                 memcpy(buf + 20, "...", 3);
144                 memcpy(buf + 23 , data->curdisplay->tag + l - 20, 20);
145                 buf[43] = 0;
146                 gtk_label_set_text(data->label, buf);
147             } else {
148                 gtk_label_set_text(data->label, data->curdisplay->tag);
149             }
150         }
151         break;
152     }
153 }
154
155 static void trsize(struct transfer *transfer, struct appletdata *data)
156 {
157     update(data);
158 }
159
160 static void trpos(struct transfer *transfer, struct appletdata *data)
161 {
162     update(data);
163 }
164
165 static void trnew(struct transfer *transfer, struct appletdata *data)
166 {
167     if(data->curdisplay == NULL)
168         data->curdisplay = transfer;
169     update(data);
170 }
171
172 static void trfree(struct transfer *transfer, struct appletdata *data)
173 {
174     if(data->curdisplay == transfer)
175         data->curdisplay = data->conduit->transfers;
176     update(data);
177 }
178
179 static void condstate(struct conduit *conduit, struct appletdata *data)
180 {
181     if(conduit->state == CNDS_IDLE)
182         g_timeout_add(10000, (gboolean (*)(gpointer))reconncb, data);
183     update(data);
184 }
185
186 static void initcond(void)
187 {
188     static int inited = 0;
189     
190     if(!inited)
191     {
192         cb_trsize = (void (*)(struct transfer *, void *))trsize;
193         cb_trpos = (void (*)(struct transfer *, void *))trpos;
194         cb_trnew = (void (*)(struct transfer *, void *))trnew;
195         cb_trfree = (void (*)(struct transfer *, void *))trfree;
196         cb_condstate = (void (*)(struct conduit *, void *))condstate;
197         inited = 1;
198     }
199 }
200
201 static gboolean trview_applet_button_press(GtkWidget *widget, GdkEventButton *event, struct appletdata *data)
202 {
203     if(event->button == 1)
204     {
205         if(data->curdisplay == NULL)
206             data->curdisplay = data->conduit->transfers;
207         else if(data->curdisplay->next == NULL)
208             data->curdisplay = data->conduit->transfers;
209         else
210             data->curdisplay = data->curdisplay->next;
211         update(data);
212     }
213     return(FALSE);
214 }
215
216 static gboolean trview_applet_scroll(GtkWidget *widget, GdkEventScroll *event, struct appletdata *data)
217 {
218     struct transfer *tr;
219     
220     if(event->direction == GDK_SCROLL_DOWN)
221     {
222         if(data->curdisplay == NULL)
223             data->curdisplay = data->conduit->transfers;
224         else if(data->curdisplay->next == NULL)
225             data->curdisplay = data->conduit->transfers;
226         else
227             data->curdisplay = data->curdisplay->next;
228         update(data);
229     } else if(event->direction == GDK_SCROLL_UP) {
230         if(data->curdisplay == NULL)
231         {
232             data->curdisplay = data->conduit->transfers;
233         } else if(data->curdisplay->prev == NULL) {
234             for(tr = data->conduit->transfers; tr->next != NULL; tr = tr->next);
235             data->curdisplay = tr;
236         } else {
237             data->curdisplay = data->curdisplay->prev;
238         }
239         update(data);
240     }
241     return(TRUE);
242 }
243
244 static void trview_applet_destroy(GtkWidget *widget, struct appletdata *data)
245 {
246     freeconduit(data->conduit);
247     g_source_remove(data->tiptimeout);
248     g_object_unref(data->applet);
249     g_object_unref(data->tips);
250     free(data);
251 }
252
253 static gboolean trview_applet_fill(PanelApplet *applet, const gchar *iid, gpointer uudata)
254 {
255     GtkWidget *hbox, *pbar, *label;
256     struct appletdata *data;
257     
258     initcond();
259     if(strcmp(iid, "OAFIID:Dolcon_Transferapplet"))
260         return(FALSE);
261     
262     hbox = gtk_hbox_new(FALSE, 0);
263     label = gtk_label_new("");
264     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
265     pbar = gtk_progress_bar_new();
266     gtk_box_pack_start(GTK_BOX(hbox), pbar, TRUE, TRUE, 0);
267     gtk_container_add(GTK_CONTAINER(applet), hbox);
268     gtk_widget_show_all(GTK_WIDGET(applet));
269     
270     data = smalloc(sizeof(*data));
271     memset(data, 0, sizeof(*data));
272     g_object_ref(data->applet = applet);
273     data->conduit = newconduit(conduit_dclib, data);
274     data->pbar = GTK_PROGRESS_BAR(pbar);
275     g_object_ref(data->tips = gtk_tooltips_new());
276     data->tiptimeout = g_timeout_add(500, (gboolean (*)(gpointer))updatetip, data);
277     data->label = GTK_LABEL(label);
278     
279     panel_applet_setup_menu(applet, ctxtmenu, ctxtmenuverbs, data);
280
281     g_signal_connect(applet, "button-press-event", (GCallback)trview_applet_button_press, data);
282     g_signal_connect(applet, "scroll-event", (GCallback)trview_applet_scroll, data);
283     g_signal_connect(applet, "destroy", (GCallback)trview_applet_destroy, data);
284     
285     condtryconn(data->conduit);
286     
287     update(data);
288     
289     return(TRUE);
290 }
291
292 #define GETTEXT_PACKAGE PACKAGE
293 #define GNOMELOCALEDIR LOCALEDIR
294
295 PANEL_APPLET_BONOBO_FACTORY("OAFIID:Dolcon_Transferapplet_Factory",
296                             PANEL_TYPE_APPLET,
297                             "Doldaconnect Transfer Viewer",
298                             "0",
299                             trview_applet_fill,
300                             NULL);