Mercurial > pidgin
annotate src/gtksavedstatuses.c @ 11849:dc51cdcb648e
[gaim-migrate @ 14140]
sf patch #1339135, from Sadrul Habib Chowdhury
Hi. Bleeter found this bug:
(1) open up some conversation window
(2) open the smiley dialog
(3) close the conversation window. the smiley dialog
remains open
(4) select some smiley
(5) Gaim crashes
This patch fixes this crash. It shouldn't cause any
probs with regards to gtk-version-checking. The other
code handling the smiley-dialog doesn't do the
version-checking, so this shouldn't be necessary either.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 27 Oct 2005 12:00:17 +0000 |
parents | 9ca386c15ffe |
children | 7d2d926704aa |
rev | line source |
---|---|
10418 | 1 /** |
2 * @file gtksavedstatus.c GTK+ Saved Status Editor UI | |
3 * @ingroup gtkui | |
4 * | |
5 * gaim | |
6 * | |
7 * Gaim is the legal property of its developers, whose names are too numerous | |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 | |
26 #include "account.h" | |
27 #include "internal.h" | |
10420 | 28 #include "notify.h" |
10418 | 29 #include "request.h" |
30 #include "savedstatuses.h" | |
31 #include "status.h" | |
32 #include "util.h" | |
33 | |
34 #include "gtkblist.h" | |
11735 | 35 #include "gtkexpander.h" |
10418 | 36 #include "gtkgaim.h" |
37 #include "gtkimhtml.h" | |
38 #include "gtkimhtmltoolbar.h" | |
39 #include "gtksavedstatuses.h" | |
40 #include "gtkstock.h" | |
41 #include "gtkutils.h" | |
42 | |
43 enum | |
44 { | |
11811 | 45 /* A hidden column containing a pointer to the GaimStatusType */ |
46 STATUS_WINDOW_COLUMN_STATUS, | |
47 | |
10421 | 48 STATUS_WINDOW_COLUMN_TITLE, |
49 STATUS_WINDOW_COLUMN_TYPE, | |
50 STATUS_WINDOW_COLUMN_MESSAGE, | |
51 STATUS_WINDOW_NUM_COLUMNS | |
52 }; | |
53 | |
54 enum | |
55 { | |
10418 | 56 STATUS_EDITOR_COLUMN_CUSTOM_STATUS, |
57 STATUS_EDITOR_COLUMN_ICON, | |
58 STATUS_EDITOR_COLUMN_SCREENNAME, | |
59 STATUS_EDITOR_NUM_COLUMNS | |
60 }; | |
61 | |
10421 | 62 typedef struct |
10418 | 63 { |
10421 | 64 GtkWidget *window; |
65 GtkListStore *model; | |
66 GtkWidget *treeview; | |
11811 | 67 GtkWidget *use_button; |
10421 | 68 GtkWidget *modify_button; |
69 GtkWidget *delete_button; | |
70 } StatusWindow; | |
10418 | 71 |
72 typedef struct | |
73 { | |
74 GtkWidget *window; | |
75 GtkListStore *model; | |
76 GtkWidget *treeview; | |
10420 | 77 GtkWidget *save_button; |
78 | |
79 gchar *original_title; | |
80 GtkEntry *title; | |
81 GtkOptionMenu *type; | |
82 GtkIMHtml *message; | |
10418 | 83 } StatusEditor; |
84 | |
85 static StatusWindow *status_window = NULL; | |
86 | |
10421 | 87 |
88 /************************************************************************** | |
89 * Status window | |
90 **************************************************************************/ | |
91 | |
92 static gboolean | |
93 status_window_find_savedstatus(GtkTreeIter *iter, const char *title) | |
94 { | |
95 GtkTreeModel *model = GTK_TREE_MODEL(status_window->model); | |
10439 | 96 char *cur; |
10421 | 97 |
98 if (!gtk_tree_model_get_iter_first(model, iter)) | |
99 return FALSE; | |
100 | |
101 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &cur, -1); | |
102 if (!strcmp(title, cur)) | |
10439 | 103 { |
104 g_free(cur); | |
10421 | 105 return TRUE; |
10439 | 106 } |
107 g_free(cur); | |
10421 | 108 |
109 while (gtk_tree_model_iter_next(model, iter)) | |
110 { | |
111 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &cur, -1); | |
112 if (!strcmp(title, cur)) | |
10439 | 113 { |
114 g_free(cur); | |
10421 | 115 return TRUE; |
10439 | 116 } |
117 g_free(cur); | |
10421 | 118 } |
119 | |
120 return FALSE; | |
121 } | |
122 | |
123 static gboolean | |
124 status_window_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) | |
125 { | |
126 StatusWindow *dialog = user_data; | |
127 | |
128 dialog->window = NULL; | |
129 gaim_gtk_status_window_hide(); | |
130 | |
131 return FALSE; | |
132 } | |
133 | |
134 static void | |
11811 | 135 status_window_use_cb(GtkButton *button, StatusWindow *dialog) |
136 { | |
137 GtkTreeSelection *selection; | |
138 GtkTreeIter iter; | |
139 GaimSavedStatus *saved_status; | |
140 GList *list; | |
141 | |
142 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); | |
143 | |
144 if (gtk_tree_selection_count_selected_rows(selection) != 1) | |
145 /* | |
146 * This shouldn't happen because the "Use" button should have | |
147 * been grayed out. Oh well. | |
148 */ | |
149 return; | |
150 | |
151 list = gtk_tree_selection_get_selected_rows(selection, NULL); | |
152 | |
153 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), | |
154 &iter, list->data)) | |
155 { | |
156 gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, | |
157 STATUS_WINDOW_COLUMN_STATUS, &saved_status, | |
158 -1); | |
159 | |
160 gaim_savedstatus_activate(saved_status); | |
161 } | |
162 | |
163 g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL); | |
164 g_list_free(list); | |
165 } | |
166 | |
167 static void | |
10421 | 168 status_window_add_cb(GtkButton *button, gpointer user_data) |
169 { | |
170 gaim_gtk_status_editor_show(NULL); | |
171 } | |
172 | |
173 static void | |
174 status_window_modify_foreach(GtkTreeModel *model, GtkTreePath *path, | |
175 GtkTreeIter *iter, gpointer user_data) | |
176 { | |
177 GaimSavedStatus *status; | |
178 | |
11811 | 179 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_STATUS, &status, -1); |
10421 | 180 gaim_gtk_status_editor_show(status); |
181 } | |
182 | |
183 static void | |
184 status_window_modify_cb(GtkButton *button, gpointer user_data) | |
185 { | |
186 StatusWindow *dialog = user_data; | |
187 GtkTreeSelection *selection; | |
188 | |
189 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); | |
190 | |
191 gtk_tree_selection_selected_foreach(selection, status_window_modify_foreach, user_data); | |
192 } | |
193 | |
194 static void | |
195 status_window_delete_confirm_cb(char *title) | |
196 { | |
197 GtkTreeIter iter; | |
198 | |
199 if (status_window_find_savedstatus(&iter, title)) | |
200 gtk_list_store_remove(status_window->model, &iter); | |
201 | |
202 gaim_savedstatus_delete(title); | |
203 | |
204 g_free(title); | |
205 } | |
206 | |
207 static void | |
208 status_window_delete_foreach(GtkTreeModel *model, GtkTreePath *path, | |
209 GtkTreeIter *iter, gpointer user_data) | |
210 { | |
10439 | 211 char *title; |
10435 | 212 char *title_escaped, *buf; |
10421 | 213 |
214 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &title, -1); | |
215 | |
10732
c4cb90065e1d
[gaim-migrate @ 12334]
Luke Schierer <lschiere@pidgin.im>
parents:
10591
diff
changeset
|
216 title_escaped = g_markup_escape_text(title, -1); |
10435 | 217 buf = g_strdup_printf(_("Are you sure you want to delete %s?"), title_escaped); |
218 free(title_escaped); | |
10439 | 219 gaim_request_action(NULL, NULL, buf, NULL, 0, title, 2, |
10421 | 220 _("Delete"), status_window_delete_confirm_cb, |
221 _("Cancel"), g_free); | |
222 g_free(buf); | |
223 } | |
224 | |
225 static void | |
226 status_window_delete_cb(GtkButton *button, gpointer user_data) | |
227 { | |
228 StatusWindow *dialog = user_data; | |
229 GtkTreeSelection *selection; | |
230 | |
231 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); | |
232 | |
233 gtk_tree_selection_selected_foreach(selection, status_window_delete_foreach, user_data); | |
234 } | |
235 | |
236 static void | |
237 status_window_close_cb(GtkButton *button, gpointer user_data) | |
238 { | |
239 gaim_gtk_status_window_hide(); | |
240 } | |
241 | |
11780 | 242 #if !GTK_CHECK_VERSION(2,2,0) |
243 static void | |
244 get_selected_helper(GtkTreeModel *model, GtkTreePath *path, | |
245 GtkTreeIter *iter, gpointer user_data) | |
246 { | |
11811 | 247 *((gboolean *)user_data)++; |
11780 | 248 } |
249 #endif | |
250 | |
10421 | 251 static void |
252 status_selected_cb(GtkTreeSelection *sel, gpointer user_data) | |
253 { | |
254 StatusWindow *dialog = user_data; | |
11811 | 255 int num_selected; |
10421 | 256 |
257 #if GTK_CHECK_VERSION(2,2,0) | |
11811 | 258 num_selected = gtk_tree_selection_count_selected_rows(sel); |
10421 | 259 #else |
11811 | 260 gtk_tree_selection_selected_foreach(sel, get_selected_helper, &num_selected); |
10421 | 261 #endif |
262 | |
11811 | 263 gtk_widget_set_sensitive(dialog->use_button, (num_selected == 1)); |
264 gtk_widget_set_sensitive(dialog->modify_button, (num_selected > 0)); | |
265 gtk_widget_set_sensitive(dialog->delete_button, (num_selected > 0)); | |
10421 | 266 } |
267 | |
268 static void | |
269 add_status_to_saved_status_list(GtkListStore *model, GaimSavedStatus *saved_status) | |
270 { | |
271 GtkTreeIter iter; | |
272 const char *title; | |
273 const char *type; | |
274 char *message; | |
275 | |
11651 | 276 if (gaim_savedstatus_is_transient(saved_status)) |
277 return; | |
278 | |
10421 | 279 title = gaim_savedstatus_get_title(saved_status); |
280 type = gaim_primitive_get_name_from_type(gaim_savedstatus_get_type(saved_status)); | |
281 message = gaim_markup_strip_html(gaim_savedstatus_get_message(saved_status)); | |
282 | |
283 gtk_list_store_append(model, &iter); | |
284 gtk_list_store_set(model, &iter, | |
11811 | 285 STATUS_WINDOW_COLUMN_STATUS, saved_status, |
10421 | 286 STATUS_WINDOW_COLUMN_TITLE, title, |
287 STATUS_WINDOW_COLUMN_TYPE, type, | |
288 STATUS_WINDOW_COLUMN_MESSAGE, message, | |
289 -1); | |
290 free(message); | |
291 } | |
292 | |
293 static void | |
294 populate_saved_status_list(StatusWindow *dialog) | |
295 { | |
296 const GList *saved_statuses; | |
297 | |
298 gtk_list_store_clear(dialog->model); | |
299 | |
300 for (saved_statuses = gaim_savedstatuses_get_all(); saved_statuses != NULL; | |
301 saved_statuses = g_list_next(saved_statuses)) | |
302 { | |
303 add_status_to_saved_status_list(dialog->model, saved_statuses->data); | |
304 } | |
305 } | |
306 | |
10435 | 307 static gboolean |
308 search_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data) | |
309 { | |
10439 | 310 gboolean result; |
311 char *haystack; | |
10435 | 312 |
313 gtk_tree_model_get(model, iter, column, &haystack, -1); | |
314 | |
10439 | 315 result = (gaim_strcasestr(haystack, key) == NULL); |
316 | |
317 g_free(haystack); | |
318 | |
319 return result; | |
10435 | 320 } |
321 | |
10421 | 322 static GtkWidget * |
323 create_saved_status_list(StatusWindow *dialog) | |
324 { | |
325 GtkWidget *sw; | |
326 GtkWidget *treeview; | |
327 GtkTreeSelection *sel; | |
328 GtkTreeViewColumn *column; | |
329 GtkCellRenderer *renderer; | |
330 | |
331 /* Create the scrolled window */ | |
332 sw = gtk_scrolled_window_new(0, 0); | |
333 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
334 GTK_POLICY_AUTOMATIC, | |
335 GTK_POLICY_ALWAYS); | |
336 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), | |
337 GTK_SHADOW_IN); | |
338 gtk_widget_show(sw); | |
339 | |
340 /* Create the list model */ | |
341 dialog->model = gtk_list_store_new(STATUS_WINDOW_NUM_COLUMNS, | |
11811 | 342 G_TYPE_POINTER, |
10421 | 343 G_TYPE_STRING, |
344 G_TYPE_STRING, | |
345 G_TYPE_STRING); | |
346 | |
347 /* Create the treeview */ | |
348 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); | |
349 dialog->treeview = treeview; | |
350 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); | |
351 | |
352 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); | |
353 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); | |
354 g_signal_connect(G_OBJECT(sel), "changed", | |
355 G_CALLBACK(status_selected_cb), dialog); | |
356 | |
357 gtk_container_add(GTK_CONTAINER(sw), treeview); | |
358 gtk_widget_show(treeview); | |
359 | |
360 /* Add columns */ | |
361 column = gtk_tree_view_column_new(); | |
362 gtk_tree_view_column_set_title(column, _("Title")); | |
363 gtk_tree_view_column_set_resizable(column, TRUE); | |
11548 | 364 gtk_tree_view_column_set_min_width(column, 100); |
10421 | 365 gtk_tree_view_column_set_sort_column_id(column, |
366 STATUS_WINDOW_COLUMN_TITLE); | |
367 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); | |
368 renderer = gtk_cell_renderer_text_new(); | |
369 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
370 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
371 STATUS_WINDOW_COLUMN_TITLE); | |
11548 | 372 #if GTK_CHECK_VERSION(2,6,0) |
373 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); | |
374 #endif | |
10421 | 375 |
376 column = gtk_tree_view_column_new(); | |
377 gtk_tree_view_column_set_title(column, _("Type")); | |
378 gtk_tree_view_column_set_resizable(column, TRUE); | |
379 gtk_tree_view_column_set_sort_column_id(column, | |
380 STATUS_WINDOW_COLUMN_TYPE); | |
381 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); | |
382 renderer = gtk_cell_renderer_text_new(); | |
383 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
384 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
385 STATUS_WINDOW_COLUMN_TYPE); | |
386 | |
387 column = gtk_tree_view_column_new(); | |
388 gtk_tree_view_column_set_title(column, _("Message")); | |
389 gtk_tree_view_column_set_resizable(column, TRUE); | |
390 gtk_tree_view_column_set_sort_column_id(column, | |
391 STATUS_WINDOW_COLUMN_MESSAGE); | |
392 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); | |
393 renderer = gtk_cell_renderer_text_new(); | |
394 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
395 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
396 STATUS_WINDOW_COLUMN_MESSAGE); | |
10435 | 397 #if GTK_CHECK_VERSION(2,6,0) |
10502 | 398 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
10435 | 399 #endif |
400 | |
401 /* Enable CTRL+F searching */ | |
402 gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), STATUS_WINDOW_COLUMN_TITLE); | |
403 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview), search_func, NULL, NULL); | |
10421 | 404 |
10422 | 405 /* Sort the title column by default */ |
406 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->model), | |
407 STATUS_WINDOW_COLUMN_TITLE, | |
408 GTK_SORT_ASCENDING); | |
409 | |
10421 | 410 /* Populate list */ |
411 populate_saved_status_list(dialog); | |
412 | |
413 return sw; | |
414 } | |
415 | |
416 static gboolean | |
417 configure_cb(GtkWidget *widget, GdkEventConfigure *event, StatusWindow *dialog) | |
418 { | |
419 if (GTK_WIDGET_VISIBLE(widget)) { | |
420 gaim_prefs_set_int("/gaim/gtk/status/dialog/width", event->width); | |
421 gaim_prefs_set_int("/gaim/gtk/status/dialog/height", event->height); | |
422 } | |
423 | |
424 return FALSE; | |
425 } | |
426 | |
427 void | |
428 gaim_gtk_status_window_show(void) | |
429 { | |
430 StatusWindow *dialog; | |
431 GtkWidget *bbox; | |
432 GtkWidget *button; | |
433 GtkWidget *list; | |
434 GtkWidget *vbox; | |
435 GtkWidget *win; | |
436 int width, height; | |
437 | |
438 if (status_window != NULL) { | |
439 gtk_window_present(GTK_WINDOW(status_window->window)); | |
440 return; | |
441 } | |
442 | |
443 status_window = dialog = g_new0(StatusWindow, 1); | |
444 | |
445 width = gaim_prefs_get_int("/gaim/gtk/status/dialog/width"); | |
446 height = gaim_prefs_get_int("/gaim/gtk/status/dialog/height"); | |
447 | |
448 dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
449 gtk_window_set_default_size(GTK_WINDOW(win), width, height); | |
450 gtk_window_set_role(GTK_WINDOW(win), "statuses"); | |
451 gtk_window_set_title(GTK_WINDOW(win), _("Saved Statuses")); | |
11243 | 452 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); |
10421 | 453 |
454 g_signal_connect(G_OBJECT(win), "delete_event", | |
455 G_CALLBACK(status_window_destroy_cb), dialog); | |
456 g_signal_connect(G_OBJECT(win), "configure_event", | |
457 G_CALLBACK(configure_cb), dialog); | |
458 | |
459 /* Setup the vbox */ | |
11243 | 460 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); |
10421 | 461 gtk_container_add(GTK_CONTAINER(win), vbox); |
462 gtk_widget_show(vbox); | |
463 | |
464 /* List of saved status states */ | |
465 list = create_saved_status_list(dialog); | |
466 gtk_box_pack_start(GTK_BOX(vbox), list, TRUE, TRUE, 0); | |
467 | |
468 /* Button box. */ | |
469 bbox = gtk_hbutton_box_new(); | |
11243 | 470 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); |
10421 | 471 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); |
472 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); | |
473 gtk_widget_show(bbox); | |
474 | |
11811 | 475 /* Use button */ |
476 /* TODO: It might be better if the button said "Use" or "Activate" */ | |
11832 | 477 button = gaim_pixbuf_button_from_stock(_("_Use"), GTK_STOCK_EXECUTE, |
478 GAIM_BUTTON_HORIZONTAL); | |
11811 | 479 dialog->use_button = button; |
480 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
481 gtk_widget_set_sensitive(button, FALSE); | |
482 gtk_widget_show(button); | |
483 | |
484 g_signal_connect(G_OBJECT(button), "clicked", | |
485 G_CALLBACK(status_window_use_cb), dialog); | |
486 | |
10421 | 487 /* Add button */ |
488 button = gtk_button_new_from_stock(GTK_STOCK_ADD); | |
489 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
490 gtk_widget_show(button); | |
491 | |
492 g_signal_connect(G_OBJECT(button), "clicked", | |
493 G_CALLBACK(status_window_add_cb), dialog); | |
494 | |
495 /* Modify button */ | |
496 button = gtk_button_new_from_stock(GAIM_STOCK_MODIFY); | |
497 dialog->modify_button = button; | |
498 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
499 gtk_widget_set_sensitive(button, FALSE); | |
500 gtk_widget_show(button); | |
501 | |
502 g_signal_connect(G_OBJECT(button), "clicked", | |
503 G_CALLBACK(status_window_modify_cb), dialog); | |
504 | |
505 /* Delete button */ | |
506 button = gtk_button_new_from_stock(GTK_STOCK_DELETE); | |
507 dialog->delete_button = button; | |
508 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
509 gtk_widget_set_sensitive(button, FALSE); | |
510 gtk_widget_show(button); | |
511 | |
512 g_signal_connect(G_OBJECT(button), "clicked", | |
513 G_CALLBACK(status_window_delete_cb), dialog); | |
514 | |
515 /* Close button */ | |
516 button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); | |
517 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
518 gtk_widget_show(button); | |
519 | |
520 g_signal_connect(G_OBJECT(button), "clicked", | |
521 G_CALLBACK(status_window_close_cb), dialog); | |
522 | |
523 gtk_widget_show(win); | |
524 } | |
525 | |
526 void | |
527 gaim_gtk_status_window_hide(void) | |
528 { | |
529 if (status_window == NULL) | |
530 return; | |
531 | |
532 if (status_window->window != NULL) | |
533 gtk_widget_destroy(status_window->window); | |
534 | |
535 g_free(status_window); | |
536 status_window = NULL; | |
537 } | |
538 | |
539 | |
540 /************************************************************************** | |
541 * Status editor | |
542 **************************************************************************/ | |
10420 | 543 |
10418 | 544 static gboolean |
545 status_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) | |
546 { | |
10574 | 547 StatusEditor *dialog = user_data; |
10418 | 548 |
10574 | 549 g_free(dialog->original_title); |
10418 | 550 g_free(dialog); |
551 | |
552 return FALSE; | |
553 } | |
554 | |
555 static void | |
556 status_editor_cancel_cb(GtkButton *button, gpointer user_data) | |
557 { | |
10574 | 558 StatusEditor *dialog = user_data; |
10418 | 559 |
560 gtk_widget_destroy(dialog->window); | |
561 | |
10574 | 562 g_free(dialog->original_title); |
10418 | 563 g_free(dialog); |
564 } | |
565 | |
566 static void | |
567 status_editor_save_cb(GtkButton *button, gpointer user_data) | |
568 { | |
10420 | 569 StatusEditor *dialog = user_data; |
570 const char *title; | |
571 GaimStatusPrimitive type; | |
572 char *message, *unformatted; | |
573 GaimSavedStatus *status; | |
574 | |
575 title = gtk_entry_get_text(dialog->title); | |
576 | |
577 /* | |
578 * If the title is already taken then show an error dialog and | |
579 * don't do anything. | |
580 */ | |
581 if ((gaim_savedstatus_find(title) != NULL) && | |
582 ((dialog->original_title == NULL) || (strcmp(title, dialog->original_title)))) | |
583 { | |
584 gaim_notify_error(NULL, NULL, _("Title already in use. You must " | |
585 "choose a unique title."), NULL); | |
586 return; | |
587 } | |
588 | |
589 type = gtk_option_menu_get_history(dialog->type); | |
590 message = gtk_imhtml_get_markup(dialog->message); | |
591 unformatted = gaim_markup_strip_html(message); | |
592 | |
593 /* | |
594 * If we're editing an existing status, remove the old one to | |
595 * make way for the modified one. | |
596 */ | |
597 if (dialog->original_title != NULL) | |
598 { | |
599 GtkTreeIter iter; | |
600 | |
601 gaim_savedstatus_delete(dialog->original_title); | |
602 | |
603 if (status_window_find_savedstatus(&iter, dialog->original_title)) | |
604 { | |
605 gtk_list_store_remove(status_window->model, &iter); | |
606 } | |
607 } | |
608 | |
609 status = gaim_savedstatus_new(title, type); | |
610 if (*unformatted != '\0') | |
611 gaim_savedstatus_set_message(status, message); | |
612 g_free(message); | |
613 g_free(unformatted); | |
614 | |
615 gtk_widget_destroy(dialog->window); | |
10574 | 616 g_free(dialog->original_title); |
10420 | 617 g_free(dialog); |
618 | |
619 add_status_to_saved_status_list(status_window->model, status); | |
620 } | |
621 | |
622 static void | |
623 status_editor_custom_status_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data) | |
624 { | |
625 /* StatusEditor *dialog = (StatusEditor *)data; */ | |
626 | |
627 /* TODO: Need to allow user to set a custom status for the highlighted account, somehow */ | |
628 } | |
629 | |
630 static void | |
631 editor_title_changed_cb(GtkWidget *widget, gpointer user_data) | |
632 { | |
633 StatusEditor *dialog = user_data; | |
634 const gchar *text; | |
635 | |
636 text = gtk_entry_get_text(dialog->title); | |
637 | |
638 gtk_widget_set_sensitive(dialog->save_button, (*text != '\0')); | |
10418 | 639 } |
640 | |
641 static GtkWidget * | |
10419 | 642 create_status_type_menu(GaimStatusPrimitive type) |
10418 | 643 { |
10419 | 644 int i; |
10418 | 645 GtkWidget *dropdown; |
646 GtkWidget *menu; | |
647 GtkWidget *item; | |
648 | |
649 dropdown = gtk_option_menu_new(); | |
650 menu = gtk_menu_new(); | |
651 | |
10419 | 652 for (i = 0; i < GAIM_STATUS_NUM_PRIMITIVES; i++) |
653 { | |
654 item = gtk_menu_item_new_with_label(gaim_primitive_get_name_from_type(i)); | |
655 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | |
656 gtk_widget_show(item); | |
657 } | |
10418 | 658 |
10419 | 659 gtk_menu_set_active(GTK_MENU(menu), type); |
10418 | 660 gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu); |
661 gtk_widget_show(menu); | |
662 | |
663 return dropdown; | |
664 } | |
665 | |
666 static void | |
667 status_editor_add_columns(StatusEditor *dialog) | |
668 { | |
669 GtkCellRenderer *renderer; | |
670 GtkTreeViewColumn *column; | |
671 | |
672 /* Custom status column */ | |
673 renderer = gtk_cell_renderer_toggle_new(); | |
674 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog->treeview), | |
675 -1, _("Custom status"), | |
676 renderer, | |
677 "active", STATUS_EDITOR_COLUMN_CUSTOM_STATUS, | |
678 NULL); | |
679 column = gtk_tree_view_get_column(GTK_TREE_VIEW(dialog->treeview), 1); | |
680 g_signal_connect(G_OBJECT(renderer), "toggled", | |
681 G_CALLBACK(status_editor_custom_status_cb), dialog); | |
682 | |
683 /* Screen Name column */ | |
684 column = gtk_tree_view_column_new(); | |
685 gtk_tree_view_column_set_resizable(column, TRUE); | |
686 gtk_tree_view_column_set_title(column, _("Screen Name")); | |
687 gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); | |
688 gtk_tree_view_column_set_resizable(column, TRUE); | |
689 | |
690 /* Icon */ | |
691 renderer = gtk_cell_renderer_pixbuf_new(); | |
692 gtk_tree_view_column_pack_start(column, renderer, FALSE); | |
693 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", | |
694 STATUS_EDITOR_COLUMN_ICON); | |
695 | |
696 /* Screen Name */ | |
697 renderer = gtk_cell_renderer_text_new(); | |
698 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
699 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
700 STATUS_EDITOR_COLUMN_SCREENNAME); | |
701 } | |
702 | |
703 static void | |
704 status_editor_set_account(GtkListStore *store, GaimAccount *account, GtkTreeIter *iter) | |
705 { | |
706 GdkPixbuf *pixbuf; | |
707 GdkPixbuf *scale; | |
708 | |
709 scale = NULL; | |
710 | |
10884 | 711 pixbuf = gaim_gtk_create_prpl_icon(account); |
10418 | 712 |
713 if (pixbuf != NULL) | |
714 { | |
715 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); | |
716 | |
11251 | 717 if (gaim_account_is_disconnected(account)) |
10418 | 718 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE); |
719 } | |
720 | |
721 gtk_list_store_set(store, iter, | |
722 STATUS_EDITOR_COLUMN_ICON, scale, | |
723 STATUS_EDITOR_COLUMN_SCREENNAME, gaim_account_get_username(account), | |
724 -1); | |
725 | |
726 if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); | |
727 if (scale != NULL) g_object_unref(G_OBJECT(scale)); | |
728 } | |
729 | |
730 static void | |
731 status_editor_add_account(StatusEditor *dialog, GaimAccount *account) | |
732 { | |
733 GtkTreeIter iter; | |
734 | |
735 gtk_list_store_append(dialog->model, &iter); | |
736 | |
737 status_editor_set_account(dialog->model, account, &iter); | |
738 } | |
739 | |
740 static void | |
741 status_editor_populate_list(StatusEditor *dialog) | |
742 { | |
743 GList *l; | |
744 | |
745 gtk_list_store_clear(dialog->model); | |
746 | |
747 for (l = gaim_accounts_get_all(); l != NULL; l = l->next) | |
748 status_editor_add_account(dialog, (GaimAccount *)l->data); | |
749 } | |
750 | |
751 void | |
10419 | 752 gaim_gtk_status_editor_show(GaimSavedStatus *status) |
10418 | 753 { |
754 StatusEditor *dialog; | |
755 GtkSizeGroup *sg; | |
756 GtkWidget *bbox; | |
757 GtkWidget *button; | |
758 GtkWidget *dbox; | |
11735 | 759 GtkWidget *expander; |
10418 | 760 GtkWidget *dropdown; |
761 GtkWidget *entry; | |
762 GtkWidget *frame; | |
763 GtkWidget *hbox; | |
764 GtkWidget *label; | |
765 GtkWidget *sw; | |
766 GtkWidget *text; | |
767 GtkWidget *toolbar; | |
768 GtkWidget *vbox; | |
769 GtkWidget *win; | |
770 | |
771 dialog = g_new0(StatusEditor, 1); | |
772 | |
10420 | 773 if (status != NULL) |
774 dialog->original_title = g_strdup(gaim_savedstatus_get_title(status)); | |
775 | |
10418 | 776 dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
777 gtk_window_set_role(GTK_WINDOW(win), "status"); | |
778 gtk_window_set_title(GTK_WINDOW(win), _("Status")); | |
779 gtk_window_set_resizable(GTK_WINDOW(win), FALSE); | |
11243 | 780 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); |
10418 | 781 |
782 g_signal_connect(G_OBJECT(win), "delete_event", | |
783 G_CALLBACK(status_editor_destroy_cb), dialog); | |
784 | |
785 /* Setup the vbox */ | |
11243 | 786 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); |
10418 | 787 gtk_container_add(GTK_CONTAINER(win), vbox); |
788 gtk_widget_show(vbox); | |
789 | |
790 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); | |
791 | |
792 /* Title */ | |
11243 | 793 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
10418 | 794 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
795 gtk_widget_show(hbox); | |
796 | |
797 label = gtk_label_new_with_mnemonic(_("_Title:")); | |
798 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
799 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
800 gtk_widget_show(label); | |
801 gtk_size_group_add_widget(sg, label); | |
802 | |
803 entry = gtk_entry_new(); | |
10420 | 804 dialog->title = GTK_ENTRY(entry); |
10419 | 805 if (status != NULL) |
10420 | 806 gtk_entry_set_text(GTK_ENTRY(entry), dialog->original_title); |
10418 | 807 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); |
808 gtk_widget_show(entry); | |
10420 | 809 g_signal_connect(G_OBJECT(entry), "changed", |
810 G_CALLBACK(editor_title_changed_cb), dialog); | |
10418 | 811 |
812 /* Status type */ | |
11243 | 813 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
10418 | 814 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
815 gtk_widget_show(hbox); | |
816 | |
817 label = gtk_label_new_with_mnemonic(_("_Status:")); | |
818 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
819 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
820 gtk_widget_show(label); | |
821 gtk_size_group_add_widget(sg, label); | |
822 | |
10419 | 823 if (status != NULL) |
824 dropdown = create_status_type_menu(gaim_savedstatus_get_type(status)); | |
825 else | |
826 dropdown = create_status_type_menu(GAIM_STATUS_AWAY); | |
10420 | 827 dialog->type = GTK_OPTION_MENU(dropdown); |
10418 | 828 gtk_box_pack_start(GTK_BOX(hbox), dropdown, TRUE, TRUE, 0); |
829 gtk_widget_show(dropdown); | |
830 | |
831 /* Status message */ | |
11243 | 832 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
10418 | 833 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
834 gtk_widget_show(hbox); | |
835 | |
836 label = gtk_label_new_with_mnemonic(_("_Message:")); | |
837 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
838 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
839 gtk_widget_show(label); | |
840 gtk_size_group_add_widget(sg, label); | |
841 | |
842 frame = gaim_gtk_create_imhtml(TRUE, &text, &toolbar); | |
10420 | 843 dialog->message = GTK_IMHTML(text); |
10418 | 844 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); |
845 gtk_widget_show(frame); | |
846 | |
10574 | 847 if ((status != NULL) && (gaim_savedstatus_get_message(status) != NULL)) |
10419 | 848 gtk_imhtml_append_text(GTK_IMHTML(text), |
849 gaim_savedstatus_get_message(status), 0); | |
850 | |
11735 | 851 /* Custom status message expander */ |
852 expander = gtk_expander_new_with_mnemonic(_("Use a _different status for some accounts")); | |
853 gtk_box_pack_start(GTK_BOX(vbox), expander, FALSE, FALSE, 0); | |
854 gtk_widget_show(expander); | |
10418 | 855 |
11735 | 856 /* Setup the box that the expander will cover */ |
11243 | 857 dbox = gtk_vbox_new(FALSE, GAIM_HIG_CAT_SPACE); |
11735 | 858 gtk_container_add(GTK_CONTAINER(expander), dbox); |
859 gtk_widget_show(dbox); | |
10418 | 860 |
861 /* Custom status message treeview */ | |
862 sw = gtk_scrolled_window_new(NULL, NULL); | |
863 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
864 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
865 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), | |
866 GTK_SHADOW_IN); | |
867 gtk_box_pack_start(GTK_BOX(dbox), sw, TRUE, TRUE, 0); | |
868 gtk_widget_show(sw); | |
869 | |
870 /* Create the list model */ | |
871 dialog->model = gtk_list_store_new(STATUS_EDITOR_NUM_COLUMNS, | |
872 G_TYPE_BOOLEAN, | |
873 GDK_TYPE_PIXBUF, G_TYPE_STRING); | |
874 | |
875 /* Create the treeview */ | |
876 dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); | |
877 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); | |
878 gtk_widget_set_size_request(dialog->treeview, 400, 250); | |
879 gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); | |
880 gtk_widget_show(dialog->treeview); | |
881 | |
882 /* Add columns */ | |
883 status_editor_add_columns(dialog); | |
884 | |
885 /* Populate list */ | |
886 status_editor_populate_list(dialog); | |
887 | |
888 /* Button box */ | |
889 bbox = gtk_hbutton_box_new(); | |
11243 | 890 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); |
10418 | 891 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); |
892 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); | |
893 gtk_widget_show(bbox); | |
894 | |
895 /* Cancel button */ | |
896 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); | |
897 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
898 gtk_widget_show(button); | |
899 | |
900 g_signal_connect(G_OBJECT(button), "clicked", | |
901 G_CALLBACK(status_editor_cancel_cb), dialog); | |
902 | |
903 /* Save button */ | |
904 button = gtk_button_new_from_stock(GTK_STOCK_SAVE); | |
10420 | 905 dialog->save_button = button; |
10418 | 906 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
907 gtk_widget_show(button); | |
908 | |
909 g_signal_connect(G_OBJECT(button), "clicked", | |
910 G_CALLBACK(status_editor_save_cb), dialog); | |
911 | |
912 gtk_widget_show(win); | |
913 } | |
914 | |
915 | |
10421 | 916 /************************************************************************** |
10814
364a2ef907ae
[gaim-migrate @ 12468]
Luke Schierer <lschiere@pidgin.im>
parents:
10732
diff
changeset
|
917 * GTK+ saved status glue |
10421 | 918 **************************************************************************/ |
10418 | 919 |
920 void * | |
921 gaim_gtk_status_get_handle() | |
922 { | |
923 static int handle; | |
924 | |
925 return &handle; | |
926 } | |
927 | |
928 void | |
929 gaim_gtk_status_init(void) | |
930 { | |
931 gaim_prefs_add_none("/gaim/gtk/status"); | |
932 gaim_prefs_add_none("/gaim/gtk/status/dialog"); | |
933 gaim_prefs_add_int("/gaim/gtk/status/dialog/width", 550); | |
934 gaim_prefs_add_int("/gaim/gtk/status/dialog/height", 250); | |
935 } | |
936 | |
937 void | |
938 gaim_gtk_status_uninit(void) | |
939 { | |
940 gaim_gtk_status_window_hide(); | |
941 } |