1 /* $Id: smsview.c,v 1.14 2008/02/27 20:02:08 dforsi Exp $ */
2
3 #include <gtk/gtk.h>
4 #include <gdk/gdkkeysyms.h>
5 #include <glade/glade.h>
6 #include <gnokii.h>
7 #include <string.h>
8
9 #include "gnocky.h"
10 #include "utils.h"
11 #include "phonebookview.h"
12
13 extern GtkWidget *window;
14 extern GSList *sms_list;
15 extern GMutex *sms_mutex;
16 extern gboolean sms_updated;
17 extern GSList *phonebook_list;
18 extern GMutex *phonebook_mutex;
19 extern GdkPixbuf *me_pixbuf;
20 extern GdkPixbuf *sm_pixbuf;
21
22 static GladeXML *sms_xml = NULL;
23 static GladeXML *new_sms_xml = NULL;
24 static GtkListStore *store;
25 static GtkTreeIter iter;
26
27 enum {
28 COL_SENDER,
29 COL_DATE,
30 COL_MEMORY,
31 COL_POINTER
32 };
33
34 enum {
35 COL_TYPE,
36 COL_NAME,
37 COL_PB_POINTER
38 };
39
gnocky_sms_create_model()40 static GtkTreeModel *gnocky_sms_create_model()
41 {
42 /* create list store */
43 store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
44
45 return GTK_TREE_MODEL (store);
46 }
47
gnocky_sms_sort_date_column(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)48 static gint gnocky_sms_sort_date_column(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
49 {
50 gn_sms *smsa, *smsb;
51 gint ret;
52
53 gtk_tree_model_get (model, a, COL_POINTER, &smsa, -1);
54 gtk_tree_model_get (model, b, COL_POINTER, &smsb, -1);
55
56 /* this ignores smsc_time.timezone */
57 ret = smsa->smsc_time.year - smsb->smsc_time.year;
58 if (ret) return ret;
59 ret = smsa->smsc_time.month - smsb->smsc_time.month;
60 if (ret) return ret;
61 ret = smsa->smsc_time.day - smsb->smsc_time.day;
62 if (ret) return ret;
63 ret = smsa->smsc_time.hour - smsb->smsc_time.hour;
64 if (ret) return ret;
65 ret = smsa->smsc_time.minute - smsb->smsc_time.minute;
66 if (ret) return ret;
67 ret = smsa->smsc_time.second - smsb->smsc_time.second;
68
69 return ret;
70 }
71
gnocky_sms_add_columns(GtkTreeView * treeview)72 static void gnocky_sms_add_columns(GtkTreeView *treeview)
73 {
74 GtkCellRenderer *renderer;
75 GtkTreeViewColumn *column;
76 GtkTreeModel *model = gtk_tree_view_get_model (treeview);
77
78 renderer = gtk_cell_renderer_text_new ();
79 column = gtk_tree_view_column_new_with_attributes (_("Sender"),
80 renderer,
81 "text",
82 COL_SENDER,
83 NULL);
84 gtk_tree_view_column_set_sort_column_id (column, COL_SENDER);
85 gtk_tree_view_append_column (treeview, column);
86
87 renderer = gtk_cell_renderer_text_new ();
88 column = gtk_tree_view_column_new_with_attributes (_("Date"),
89 renderer,
90 "text",
91 COL_DATE,
92 NULL);
93 gtk_tree_view_column_set_sort_column_id (column, COL_DATE);
94 gtk_tree_view_append_column (treeview, column);
95
96 renderer = gtk_cell_renderer_text_new ();
97 column = gtk_tree_view_column_new_with_attributes (_("Memory"),
98 renderer,
99 "text",
100 COL_MEMORY,
101 NULL);
102 gtk_tree_view_column_set_sort_column_id (column, COL_MEMORY);
103 gtk_tree_view_append_column (treeview, column);
104
105 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(model), COL_DATE, gnocky_sms_sort_date_column, NULL, NULL);
106 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(model), COL_DATE, GTK_SORT_DESCENDING);
107 }
108
gnocky_new_sms_count_characters(GtkWidget * widget,GdkEventKey * event,gpointer user_data)109 gboolean gnocky_new_sms_count_characters(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
110 {
111 GtkTextBuffer *buffer;
112 GtkWidget *w;
113 gint char_count;
114 gchar *tmp;
115
116 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
117 char_count = gtk_text_buffer_get_char_count (buffer);
118
119 if (char_count > GN_SMS_MAX_LENGTH) {
120 GtkTextIter start, end;
121 gchar *text;
122
123 gtk_text_buffer_get_start_iter(buffer, &start);
124 gtk_text_buffer_get_end_iter(buffer, &end);
125
126 text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
127 gtk_text_buffer_set_text(buffer, text, GN_SMS_MAX_LENGTH);
128 g_free(text);
129 char_count = GN_SMS_MAX_LENGTH;
130 }
131 w = glade_xml_get_widget(new_sms_xml, "chars_label");
132 tmp = g_strdup_printf(_("%d left"), GN_SMS_MAX_LENGTH - char_count);
133 gtk_label_set_markup(GTK_LABEL(w), tmp);
134 g_free(tmp);
135
136 return FALSE;
137 }
138
gnocky_sms_phone_search_model()139 static GtkTreeModel *gnocky_sms_phone_search_model()
140 {
141 GtkListStore *store;
142 /* create list store */
143 store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
144
145 return GTK_TREE_MODEL (store);
146 }
147
gnocky_phone_search_add_columns(GtkTreeView * treeview)148 static void gnocky_phone_search_add_columns(GtkTreeView *treeview)
149 {
150 GtkCellRenderer *renderer;
151 GtkTreeViewColumn *column;
152 GtkTreeModel *model = gtk_tree_view_get_model (treeview);
153
154 renderer = gtk_cell_renderer_pixbuf_new ();
155 column = gtk_tree_view_column_new_with_attributes (_("Type"),
156 renderer,
157 "pixbuf",
158 COL_TYPE,
159 NULL);
160 gtk_tree_view_column_set_sort_column_id (column, COL_TYPE);
161 gtk_tree_view_append_column (treeview, column);
162
163 renderer = gtk_cell_renderer_text_new ();
164 column = gtk_tree_view_column_new_with_attributes (_("Name"),
165 renderer,
166 "text",
167 COL_NAME,
168 NULL);
169 gtk_tree_view_column_set_sort_column_id (column, COL_NAME);
170 gtk_tree_view_append_column (treeview, column);
171
172 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(model), COL_NAME, GTK_SORT_ASCENDING);
173 }
174
pbs_clicked(GtkWidget * widget,GdkEventButton * ev,gpointer user_data)175 gboolean pbs_clicked(GtkWidget *widget, GdkEventButton *ev, gpointer user_data)
176 {
177 if (ev->type == GDK_2BUTTON_PRESS && ev->button == 1) {
178 GtkWidget *dialog;
179 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
180 GtkTreeViewColumn *treevc = NULL;
181 GtkTreePath *treepath = NULL;
182 GtkTreeIter iter;
183 gn_phonebook_entry *en;
184
185 if (!gtk_tree_view_get_path_at_pos
186 (GTK_TREE_VIEW(widget), ev->x, ev->y, &treepath, &treevc, NULL, NULL))
187 return FALSE;
188 gtk_tree_model_get_iter(model, &iter, treepath);
189 gtk_tree_path_free(treepath);
190 gtk_tree_model_get(model, &iter, COL_PB_POINTER, &en, -1);
191 if (en) {
192 dialog = gtk_widget_get_ancestor(widget, GTK_TYPE_DIALOG);
193 gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
194 }
195 }
196 return FALSE;
197 }
198
gnocky_sms_phonebook_search_clicked(GtkWidget * widget,gpointer user_data)199 void gnocky_sms_phonebook_search_clicked(GtkWidget *widget, gpointer user_data)
200 {
201 GtkWidget *phone_search;
202 GtkWidget *phone_tree;
203 GtkTreeModel *model;
204 int res;
205 GladeXML *phone_search_xml = create_gladexml("gnocky-phonebook-list-dialog.glade", "phonebook_list_dialog");
206
207 if (!phone_search_xml)
208 g_error("Cannot create phone search view!\n");
209
210 phone_search = glade_xml_get_widget(phone_search_xml, "phonebook_list_dialog");
211 glade_xml_signal_autoconnect(phone_search_xml);
212
213 model = gnocky_sms_phone_search_model();
214 phone_tree = glade_xml_get_widget(phone_search_xml, "phonebook_treeview");
215 gtk_tree_view_set_model(GTK_TREE_VIEW(phone_tree), model);
216
217 gnocky_phone_search_add_columns(GTK_TREE_VIEW(phone_tree));
218
219 if (g_mutex_trylock(phonebook_mutex)) {
220 GSList *tmp = phonebook_list;
221 while (tmp) {
222 gn_phonebook_entry *en = (gn_phonebook_entry *) tmp->data;
223 gchar *number_string = g_strdup("");
224 gchar *name = g_locale_to_utf8(en->name, -1, NULL, NULL, NULL);
225
226 if (en->subentries_count) {
227 gint i;
228 gchar *tmp;
229
230 for (i = 0;i<en->subentries_count;i++) {
231 tmp = g_strdup_printf("%s %s", number_string, en->subentries[i].data.number);
232 g_free(number_string);
233 number_string = tmp;
234 }
235 } else {
236 g_free(number_string);
237 number_string = g_strdup(en->number);
238 }
239
240 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
241 gtk_list_store_set (GTK_LIST_STORE(model), &iter, COL_NAME, name, COL_PB_POINTER, en, -1);
242
243 g_free(name);
244 g_free(number_string);
245
246 switch (en->memory_type) {
247 case GN_MT_ME:
248 gtk_list_store_set (GTK_LIST_STORE(model), &iter, COL_TYPE, me_pixbuf, -1);
249 break;
250 case GN_MT_SM:
251 gtk_list_store_set (GTK_LIST_STORE(model), &iter, COL_TYPE, sm_pixbuf, -1);
252 break;
253 default:
254 break;
255 }
256 tmp = tmp->next;
257 }
258 }
259 g_mutex_unlock(phonebook_mutex);
260
261 gtk_window_set_transient_for (GTK_WINDOW (phone_search), GTK_WINDOW (((GnockyNewSmsInfo *) user_data)->parent));
262 res = gtk_dialog_run(GTK_DIALOG(phone_search));
263 if (res == GTK_RESPONSE_OK) {
264 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(phone_tree));
265 GtkTreeIter iter;
266 GList *rows, *tmp;
267 gn_phonebook_entry *en;
268
269 rows = gtk_tree_selection_get_selected_rows(selection, NULL);
270 tmp = rows;
271 while (tmp) {
272 gtk_tree_model_get_iter(model, &iter, tmp->data);
273 gtk_tree_model_get(model, &iter, COL_PB_POINTER, &en, -1);
274 /* this needs to be fixed when multipile selection
275 will be allowed */
276 if (en)
277 gtk_entry_set_text(GTK_ENTRY(((GnockyNewSmsInfo *) user_data)->sms_number), en->number);
278 tmp = tmp->next;
279 }
280 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
281 g_list_free (rows);
282
283 /* GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
284 GtkTreeViewColumn *treevc = NULL;
285 GtkTreePath *treepath = NULL;
286 GtkTreeIter iter;
287 gn_phonebook_entry *en;
288
289 if (!gtk_tree_view_get_path_at_pos
290 (GTK_TREE_VIEW(widget), ev->x, ev->y, &treepath, &treevc, NULL, NULL))
291 return FALSE;
292 gtk_tree_model_get_iter(model, &iter, treepath);
293 gtk_tree_model_get(model, &iter, COL_PB_POINTER, &en, -1);
294 */
295 }
296 gtk_widget_destroy(phone_search);
297 g_object_unref(phone_search_xml);
298 g_object_unref (model);
299
300 }
301
gnocky_new_sms_clicked(GtkWidget * widget,gpointer data)302 void gnocky_new_sms_clicked(GtkWidget *widget, gpointer data)
303 {
304 GtkWidget *new_sms;
305 GtkWidget *phonebook_search_button;
306 GtkWidget *sms_number;
307 GnockyNewSmsInfo new_sms_info;
308 int res;
309
310 new_sms_xml = create_gladexml("gnocky-new-sms.glade", "new_sms_dialog");
311
312 if (!new_sms_xml)
313 g_error("Cannot create new sms view!\n");
314
315 new_sms = glade_xml_get_widget(new_sms_xml, "new_sms_dialog");
316 glade_xml_signal_autoconnect(new_sms_xml);
317
318 /* set signal by hand... */
319 phonebook_search_button = glade_xml_get_widget(new_sms_xml, "phonebook_search_button");
320 new_sms_info.sms_number = glade_xml_get_widget(new_sms_xml, "sms_number");
321 new_sms_info.parent = GTK_WINDOW(new_sms);
322 g_signal_connect(G_OBJECT(phonebook_search_button), "clicked",
323 G_CALLBACK(gnocky_sms_phonebook_search_clicked), &new_sms_info);
324
325 gtk_window_set_transient_for (GTK_WINDOW (new_sms), GTK_WINDOW (window));
326 res = gtk_dialog_run(GTK_DIALOG(new_sms));
327
328 gnocky_new_sms_count_characters(glade_xml_get_widget(new_sms_xml, "sms_text"), NULL, NULL);
329
330 if (res == GTK_RESPONSE_OK) {
331 GtkWidget *entry;
332 gchar *number, *text, *sms_text;
333 GtkTextBuffer *buffer;
334 GtkTextIter start, end;
335 gn_sms *sms;
336
337 entry = glade_xml_get_widget(new_sms_xml, "sms_number");
338 number = g_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(entry)), -1, NULL, NULL, NULL);
339
340 entry = glade_xml_get_widget(new_sms_xml, "sms_text");
341 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry));
342
343 gtk_text_buffer_get_start_iter(buffer, &start);
344 gtk_text_buffer_get_iter_at_offset(buffer, &end, GN_SMS_MAX_LENGTH);
345
346 text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
347 sms_text = g_locale_from_utf8(text, -1, NULL, NULL, NULL);
348 g_free(text);
349
350 sms = g_new0(gn_sms, 1);
351 gn_sms_default_submit(sms);
352 strncpy(sms->remote.number, number, sizeof(sms->remote.number) - 1);
353 if (number[0] == '+') {
354 sms->remote.type = GN_GSM_NUMBER_International;
355 } else {
356 sms->remote.type = GN_GSM_NUMBER_Unknown;
357 }
358 strncpy(sms->user_data[0].u.text, sms_text, strlen(sms_text));
359 sms->user_data[0].length = strlen(sms_text);
360
361 sms->user_data[0].type = GN_SMS_DATA_Text;
362 if (!gn_char_def_alphabet(sms->user_data[0].u.text))
363 sms->dcs.u.general.alphabet = GN_SMS_DCS_UCS2;
364 sms->user_data[1].type = GN_SMS_DATA_None;
365 g_free(number);
366 g_free(sms_text);
367
368 gnocky_event_push(GNOCKY_EVENT_SEND_SMS, sms);
369 }
370
371 gtk_widget_destroy(new_sms);
372 g_object_unref(new_sms_xml);
373 new_sms_xml = NULL;
374 }
375
gnocky_sms_load_from_phone_clicked(GtkWidget * widget,gpointer data)376 void gnocky_sms_load_from_phone_clicked(GtkWidget *widget, gpointer data)
377 {
378 gnocky_event_push(GNOCKY_EVENT_READ_SMS_LIST, NULL);
379 }
380
sms_pressed(GtkWidget * widget,GdkEventKey * ev,gpointer user_data)381 gboolean sms_pressed(GtkWidget *widget, GdkEventKey *ev, gpointer user_data)
382 {
383 if (ev->keyval == GDK_Delete) {
384 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
385 GtkTreePath *treepath = NULL;
386 GtkTreeIter iter;
387 GtkWidget *dialog;
388 gint res;
389 gn_sms *sms;
390
391 gtk_tree_view_get_cursor (GTK_TREE_VIEW(widget), &treepath, NULL);
392 if (!treepath) return FALSE;
393 gtk_tree_model_get_iter(model, &iter, treepath);
394 gtk_tree_model_get(model, &iter, COL_POINTER, &sms, -1);
395
396 dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
397 GTK_BUTTONS_OK_CANCEL,
398 _("Do you want to delete this SMS?"));
399
400 res = gtk_dialog_run(GTK_DIALOG(dialog));
401 if (res == GTK_RESPONSE_OK) {
402 gnocky_event_push(GNOCKY_EVENT_DELETE_SMS, sms);
403 }
404 gtk_tree_path_free(treepath);
405
406 gtk_widget_destroy(dialog);
407 }
408 return FALSE;
409 }
410
sms_clicked(GtkWidget * treeview,GdkEventButton * ev,gpointer user_data)411 static gboolean sms_clicked(GtkWidget *treeview, GdkEventButton *ev, gpointer user_data)
412 {
413 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
414 GtkTreePath *treepath = NULL;
415 GtkTreeIter iter;
416 GtkWidget *widget;
417 GtkTextBuffer *buffer;
418 gn_sms *sms;
419 gchar *tmp, *sender;
420 gchar *utf_body;
421
422 gtk_tree_view_get_cursor (GTK_TREE_VIEW(treeview), &treepath, NULL);
423 if (!treepath) return FALSE;
424 gtk_tree_model_get_iter(model, &iter, treepath);
425 gtk_tree_path_free(treepath);
426 gtk_tree_model_get(model, &iter, COL_POINTER, &sms, -1);
427
428 widget = glade_xml_get_widget(sms_xml, "sms_body");
429 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
430 utf_body = g_locale_to_utf8(sms->user_data[0].u.text, -1, NULL, NULL, NULL);
431 gtk_text_buffer_set_text (buffer, utf_body, -1);
432 g_free(utf_body);
433
434 widget = glade_xml_get_widget(sms_xml, "from_label");
435
436 sender = gnocky_pb_get_name(sms->remote.number);
437
438 if (!sender) {
439 tmp = g_strdup(sms->remote.number);
440 } else {
441 gchar *utf_sender = g_locale_to_utf8(sender, -1, NULL, NULL, NULL);
442 tmp = g_strdup_printf("<b>%s</b> (%s)", utf_sender, sms->remote.number);
443 g_free(sender);
444 g_free(utf_sender);
445 }
446
447 gtk_label_set_markup(GTK_LABEL(widget), tmp);
448 g_free(tmp);
449
450 widget = glade_xml_get_widget(sms_xml, "date_label");
451 tmp = g_strdup_printf("<b>%02d/%02d/%04d %02d:%02d</b>",
452 sms->smsc_time.day, sms->smsc_time.month, sms->smsc_time.year, sms->smsc_time.hour, sms->smsc_time.minute);
453 gtk_label_set_markup(GTK_LABEL(widget), tmp);
454 g_free(tmp);
455
456 return FALSE;
457 }
458
gnocky_sms_view_destroy(GtkWidget * sms_view)459 void gnocky_sms_view_destroy(GtkWidget *sms_view)
460 {
461 if (sms_view)
462 gtk_widget_destroy(sms_view);
463 if (sms_xml)
464 g_object_unref(sms_xml);
465 }
466
gnocky_sms_view_create()467 GtkWidget *gnocky_sms_view_create()
468 {
469 GtkTreeModel *model;
470 GtkWidget *sms_tree;
471 GtkWidget *sv;
472 GtkTreeSelection *selection;
473
474 sms_xml = create_gladexml("gnocky-sms-view.glade", "sms_view");
475
476 if (!sms_xml) {
477 g_error("Cannot create sms view!\n");
478 gnocky_main_quit();
479 }
480
481 glade_xml_signal_autoconnect(sms_xml);
482
483 sv = glade_xml_get_widget(sms_xml, "sms_view");
484
485 if (sv == NULL) {
486 g_error("uhm... sv == NULL!!!\n");
487 }
488
489 model = gnocky_sms_create_model();
490 sms_tree = glade_xml_get_widget(sms_xml, "sms_tree");
491 gtk_tree_view_set_model(GTK_TREE_VIEW(sms_tree), model);
492 g_object_unref (model);
493
494 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(sms_tree));
495 g_signal_connect_swapped (G_OBJECT (selection), "changed", G_CALLBACK (sms_clicked), G_OBJECT (sms_tree));
496
497 gnocky_sms_add_columns(GTK_TREE_VIEW(sms_tree));
498
499 return sv;
500 }
501
gnocky_sms_view_update(GnockyPhoneMonitor pm)502 void gnocky_sms_view_update(GnockyPhoneMonitor pm)
503 {
504 if (g_mutex_trylock(sms_mutex)) {
505 GSList *tmp = sms_list;
506 if (sms_updated) {
507 gtk_list_store_clear(store);
508 while (tmp) {
509 gn_sms *sms = tmp->data;
510 gchar *sender;
511 gchar *date;
512
513 sender = gnocky_pb_get_name(sms->remote.number);
514 if (!sender) {
515 sender = g_strdup(sms->remote.number);
516 } else {
517 gchar *utf_sender = g_locale_to_utf8(sender, -1, NULL, NULL, NULL);
518 g_free(sender);
519 sender = utf_sender;
520 }
521 date = g_strdup_printf("%02d/%02d/%04d %02d:%02d",
522 sms->smsc_time.day, sms->smsc_time.month, sms->smsc_time.year, sms->smsc_time.hour, sms->smsc_time.minute);
523
524 gtk_list_store_append (store, &iter);
525 gtk_list_store_set (store, &iter, COL_SENDER, sender, COL_DATE, date, COL_MEMORY, gn_memory_type2str(sms->memory_type), COL_POINTER, sms, -1);
526
527 g_free(sender);
528 g_free(date);
529 tmp = tmp->next;
530 }
531 sms_updated = FALSE;
532 }
533 g_mutex_unlock(sms_mutex);
534 }
535 }
536