Mercurial > pidgin.yaz
annotate src/gtksavedstatuses.c @ 12116:e75ef7aa913e
[gaim-migrate @ 14416]
" This patch implements a replacement for the queuing
system from 1.x. It also obsoletes a previous patch
[#1338873] I submitted to prioritize the unseen states
in gtk conversations.
The attached envelope.png is ripped from the
msgunread.png already included in gaim. It should be
dropped in the pixmaps directory (Makefile.am is
updated accordingly in this patch).
The two separate queuing preferences from 1.x, queuing
messages while away and queuing all new messages (from
docklet), are replaced with a single 3-way preference
for conversations. The new preference is "Hide new IM
conversations". This preference can be set to never,
away and always.
When a gtk conversation is created, it may be placed in
a hidden conversation window instead of being placed
normally. This decision is based upon the preference
and possibly the away state of the account the
conversation is being created for. This *will* effect
conversations the user explicitly requests to be
created, so in these cases the caller must be sure to
present the conversation to the user, using
gaim_gtkconv_present_conversation(). This is done
already in gtkdialogs.c which handles creating
conversations requested by the user from gaim proper
(menus, double-clicking on budy in blist, etc.).
The main advantage to not queuing messages is that the
conversations exist, the message is written to the
conversation (and logged if appropriate) and the unseen
state is set on the conversation. This means no
additional features are needed to track whether there
are queued messages or not, just use the unseen state
on conversations.
Since conversations may not be visible (messages
"queued"), gaim proper needs some notification that
there are messages waiting. I opted for a menutray icon
that shows up when an im conversation has an unseen
message. Clicking this icon will focus (and show if
hidden) the first conversation with an unseen message.
This is essentially the same behavior of the docklet in
cvs right now, except that the icon is only visible
when there is a conversation with an unread message.
The api that is added is flexible enough to allow
either the docklet or the new blist menutray icon to be
visible for conversations of any/all types and for
unseen messages >= any state. Currently they are set to
only IM conversations and only unseen states >= TEXT
(system messages and no log messages will not trigger
blinking the docklet or showing the blist tray icon),
but these could be made preferences relatively easily
in the future. Other plugins could probably benefit as
well: gaim_gtk_conversations_get_first_unseen().
There is probably some limit to comment size, so I'll
stop rambling now. If anyone has more
questions/comments, catch me in #gaim, here or on
gaim-devel."
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Wed, 16 Nov 2005 18:17:01 +0000 |
parents | 3b52d94437f3 |
children | 5e24b8e49522 |
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 | |
12080 | 43 /* |
44 * TODO: Should attach to the account-deleted and account-added signals | |
45 * and update the GtkListStores in any StatusEditor windows that | |
46 * may be open. | |
47 */ | |
48 | |
49 /** | |
50 * These are used for the GtkTreeView when you're scrolling through | |
51 * all your saved statuses. | |
52 */ | |
10418 | 53 enum |
54 { | |
10421 | 55 STATUS_WINDOW_COLUMN_TITLE, |
56 STATUS_WINDOW_COLUMN_TYPE, | |
57 STATUS_WINDOW_COLUMN_MESSAGE, | |
58 STATUS_WINDOW_NUM_COLUMNS | |
59 }; | |
60 | |
12080 | 61 /** |
62 * These is used for the GtkTreeView containing the list of accounts | |
63 * at the bottom of the window when you're editing a particular | |
64 * saved status. | |
65 */ | |
10421 | 66 enum |
67 { | |
12080 | 68 /** A hidden column containing a pointer to the GaimAccount */ |
69 STATUS_EDITOR_COLUMN_ACCOUNT, | |
70 STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, | |
10418 | 71 STATUS_EDITOR_COLUMN_ICON, |
72 STATUS_EDITOR_COLUMN_SCREENNAME, | |
12080 | 73 /** A hidden column containing the ID of this GaimStatusType. */ |
74 STATUS_EDITOR_COLUMN_STATUS_ID, | |
75 STATUS_EDITOR_COLUMN_STATUS_NAME, | |
76 STATUS_EDITOR_COLUMN_STATUS_MESSAGE, | |
10418 | 77 STATUS_EDITOR_NUM_COLUMNS |
78 }; | |
79 | |
12080 | 80 /** |
81 * These are used in the GtkComboBox to select the specific | |
82 * GaimStatusType when setting a substatus for a particular saved | |
83 * status. | |
84 */ | |
85 enum | |
86 { | |
87 /** A hidden column containing a pointer to the GaimAccount. */ | |
88 SUBSTATUS_COLUMN_ACCOUNT, | |
89 SUBSTATUS_COLUMN_ICON, | |
90 /** A hidden column containing the ID of this GaimStatusType. */ | |
91 SUBSTATUS_COLUMN_STATUS_ID, | |
92 SUBSTATUS_COLUMN_STATUS_NAME, | |
93 SUBSTATUS_NUM_COLUMNS | |
94 }; | |
95 | |
10421 | 96 typedef struct |
10418 | 97 { |
10421 | 98 GtkWidget *window; |
99 GtkListStore *model; | |
100 GtkWidget *treeview; | |
11811 | 101 GtkWidget *use_button; |
10421 | 102 GtkWidget *modify_button; |
103 GtkWidget *delete_button; | |
104 } StatusWindow; | |
10418 | 105 |
106 typedef struct | |
107 { | |
108 GtkWidget *window; | |
109 GtkListStore *model; | |
110 GtkWidget *treeview; | |
10420 | 111 GtkWidget *save_button; |
112 | |
113 gchar *original_title; | |
114 GtkEntry *title; | |
115 GtkOptionMenu *type; | |
116 GtkIMHtml *message; | |
10418 | 117 } StatusEditor; |
118 | |
12080 | 119 typedef struct |
120 { | |
121 StatusEditor *status_editor; | |
122 GaimAccount *account; | |
123 | |
124 GtkWidget *window; | |
125 GtkListStore *model; | |
126 GtkComboBox *box; | |
127 GtkIMHtml *message; | |
128 GtkIMHtmlToolbar *toolbar; | |
129 } SubStatusEditor; | |
130 | |
10418 | 131 static StatusWindow *status_window = NULL; |
132 | |
10421 | 133 |
134 /************************************************************************** | |
135 * Status window | |
136 **************************************************************************/ | |
137 | |
138 static gboolean | |
139 status_window_find_savedstatus(GtkTreeIter *iter, const char *title) | |
140 { | |
141 GtkTreeModel *model = GTK_TREE_MODEL(status_window->model); | |
10439 | 142 char *cur; |
10421 | 143 |
144 if (!gtk_tree_model_get_iter_first(model, iter)) | |
145 return FALSE; | |
146 | |
147 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &cur, -1); | |
148 if (!strcmp(title, cur)) | |
10439 | 149 { |
150 g_free(cur); | |
10421 | 151 return TRUE; |
10439 | 152 } |
153 g_free(cur); | |
10421 | 154 |
155 while (gtk_tree_model_iter_next(model, iter)) | |
156 { | |
157 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &cur, -1); | |
158 if (!strcmp(title, cur)) | |
10439 | 159 { |
160 g_free(cur); | |
10421 | 161 return TRUE; |
10439 | 162 } |
163 g_free(cur); | |
10421 | 164 } |
165 | |
166 return FALSE; | |
167 } | |
168 | |
169 static gboolean | |
170 status_window_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) | |
171 { | |
172 StatusWindow *dialog = user_data; | |
173 | |
174 dialog->window = NULL; | |
175 gaim_gtk_status_window_hide(); | |
176 | |
177 return FALSE; | |
178 } | |
179 | |
11888 | 180 #if !GTK_CHECK_VERSION(2,2,0) |
181 static void | |
182 count_selected_helper(GtkTreeModel *model, GtkTreePath *path, | |
183 GtkTreeIter *iter, gpointer user_data) | |
184 { | |
185 (*(gint *)user_data)++; | |
186 } | |
187 | |
188 static void | |
189 list_selected_helper(GtkTreeModel *model, GtkTreePath *path, | |
190 GtkTreeIter *iter, gpointer user_data) | |
191 { | |
11889 | 192 GList **list = (GList **)user_data; |
193 *list = g_list_append(*list, gtk_tree_path_copy(path)); | |
11888 | 194 } |
195 #endif | |
196 | |
10421 | 197 static void |
11811 | 198 status_window_use_cb(GtkButton *button, StatusWindow *dialog) |
199 { | |
200 GtkTreeSelection *selection; | |
201 GtkTreeIter iter; | |
11889 | 202 GList *list = NULL; |
11888 | 203 int num_selected = 0; |
11811 | 204 |
205 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); | |
206 | |
11888 | 207 #if GTK_CHECK_VERSION(2,2,0) |
208 num_selected = gtk_tree_selection_count_selected_rows(selection); | |
209 #else | |
210 gtk_tree_selection_selected_foreach(selection, count_selected_helper, &num_selected); | |
211 #endif | |
212 if (num_selected != 1) | |
11811 | 213 /* |
214 * This shouldn't happen because the "Use" button should have | |
215 * been grayed out. Oh well. | |
216 */ | |
217 return; | |
218 | |
11888 | 219 #if GTK_CHECK_VERSION(2,2,0) |
11811 | 220 list = gtk_tree_selection_get_selected_rows(selection, NULL); |
11888 | 221 #else |
222 gtk_tree_selection_selected_foreach(selection, list_selected_helper, &list); | |
223 #endif | |
11811 | 224 |
225 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), | |
226 &iter, list->data)) | |
227 { | |
12080 | 228 gchar *title; |
229 GaimSavedStatus *saved_status; | |
11811 | 230 gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, |
12080 | 231 STATUS_WINDOW_COLUMN_TITLE, &title, |
11811 | 232 -1); |
12080 | 233 saved_status = gaim_savedstatus_find(title); |
234 g_free(title); | |
11811 | 235 gaim_savedstatus_activate(saved_status); |
236 } | |
237 | |
238 g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL); | |
239 g_list_free(list); | |
240 } | |
241 | |
242 static void | |
10421 | 243 status_window_add_cb(GtkButton *button, gpointer user_data) |
244 { | |
245 gaim_gtk_status_editor_show(NULL); | |
246 } | |
247 | |
248 static void | |
249 status_window_modify_foreach(GtkTreeModel *model, GtkTreePath *path, | |
250 GtkTreeIter *iter, gpointer user_data) | |
251 { | |
12080 | 252 gchar *title; |
253 GaimSavedStatus *saved_status; | |
10421 | 254 |
12080 | 255 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &title, -1); |
256 saved_status = gaim_savedstatus_find(title); | |
257 g_free(title); | |
258 gaim_gtk_status_editor_show(saved_status); | |
10421 | 259 } |
260 | |
261 static void | |
262 status_window_modify_cb(GtkButton *button, gpointer user_data) | |
263 { | |
264 StatusWindow *dialog = user_data; | |
265 GtkTreeSelection *selection; | |
266 | |
267 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); | |
268 | |
269 gtk_tree_selection_selected_foreach(selection, status_window_modify_foreach, user_data); | |
270 } | |
271 | |
272 static void | |
273 status_window_delete_confirm_cb(char *title) | |
274 { | |
275 GtkTreeIter iter; | |
276 | |
277 if (status_window_find_savedstatus(&iter, title)) | |
278 gtk_list_store_remove(status_window->model, &iter); | |
279 | |
280 gaim_savedstatus_delete(title); | |
281 | |
282 g_free(title); | |
283 } | |
284 | |
285 static void | |
286 status_window_delete_foreach(GtkTreeModel *model, GtkTreePath *path, | |
287 GtkTreeIter *iter, gpointer user_data) | |
288 { | |
10439 | 289 char *title; |
10435 | 290 char *title_escaped, *buf; |
10421 | 291 |
292 gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &title, -1); | |
293 | |
10732
c4cb90065e1d
[gaim-migrate @ 12334]
Luke Schierer <lschiere@pidgin.im>
parents:
10591
diff
changeset
|
294 title_escaped = g_markup_escape_text(title, -1); |
10435 | 295 buf = g_strdup_printf(_("Are you sure you want to delete %s?"), title_escaped); |
296 free(title_escaped); | |
10439 | 297 gaim_request_action(NULL, NULL, buf, NULL, 0, title, 2, |
10421 | 298 _("Delete"), status_window_delete_confirm_cb, |
299 _("Cancel"), g_free); | |
300 g_free(buf); | |
301 } | |
302 | |
303 static void | |
304 status_window_delete_cb(GtkButton *button, gpointer user_data) | |
305 { | |
306 StatusWindow *dialog = user_data; | |
307 GtkTreeSelection *selection; | |
308 | |
309 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); | |
310 | |
311 gtk_tree_selection_selected_foreach(selection, status_window_delete_foreach, user_data); | |
312 } | |
313 | |
314 static void | |
315 status_window_close_cb(GtkButton *button, gpointer user_data) | |
316 { | |
317 gaim_gtk_status_window_hide(); | |
318 } | |
319 | |
320 static void | |
321 status_selected_cb(GtkTreeSelection *sel, gpointer user_data) | |
322 { | |
323 StatusWindow *dialog = user_data; | |
11888 | 324 int num_selected = 0; |
10421 | 325 |
326 #if GTK_CHECK_VERSION(2,2,0) | |
11811 | 327 num_selected = gtk_tree_selection_count_selected_rows(sel); |
10421 | 328 #else |
11888 | 329 gtk_tree_selection_selected_foreach(sel, count_selected_helper, &num_selected); |
10421 | 330 #endif |
331 | |
11811 | 332 gtk_widget_set_sensitive(dialog->use_button, (num_selected == 1)); |
333 gtk_widget_set_sensitive(dialog->modify_button, (num_selected > 0)); | |
334 gtk_widget_set_sensitive(dialog->delete_button, (num_selected > 0)); | |
10421 | 335 } |
336 | |
337 static void | |
338 add_status_to_saved_status_list(GtkListStore *model, GaimSavedStatus *saved_status) | |
339 { | |
340 GtkTreeIter iter; | |
341 const char *title; | |
342 const char *type; | |
343 char *message; | |
344 | |
11651 | 345 if (gaim_savedstatus_is_transient(saved_status)) |
346 return; | |
347 | |
10421 | 348 title = gaim_savedstatus_get_title(saved_status); |
349 type = gaim_primitive_get_name_from_type(gaim_savedstatus_get_type(saved_status)); | |
350 message = gaim_markup_strip_html(gaim_savedstatus_get_message(saved_status)); | |
351 | |
352 gtk_list_store_append(model, &iter); | |
353 gtk_list_store_set(model, &iter, | |
354 STATUS_WINDOW_COLUMN_TITLE, title, | |
355 STATUS_WINDOW_COLUMN_TYPE, type, | |
356 STATUS_WINDOW_COLUMN_MESSAGE, message, | |
357 -1); | |
358 free(message); | |
359 } | |
360 | |
361 static void | |
362 populate_saved_status_list(StatusWindow *dialog) | |
363 { | |
364 const GList *saved_statuses; | |
365 | |
366 gtk_list_store_clear(dialog->model); | |
367 | |
368 for (saved_statuses = gaim_savedstatuses_get_all(); saved_statuses != NULL; | |
369 saved_statuses = g_list_next(saved_statuses)) | |
370 { | |
371 add_status_to_saved_status_list(dialog->model, saved_statuses->data); | |
372 } | |
373 } | |
374 | |
10435 | 375 static gboolean |
376 search_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data) | |
377 { | |
10439 | 378 gboolean result; |
379 char *haystack; | |
10435 | 380 |
381 gtk_tree_model_get(model, iter, column, &haystack, -1); | |
382 | |
10439 | 383 result = (gaim_strcasestr(haystack, key) == NULL); |
384 | |
385 g_free(haystack); | |
386 | |
387 return result; | |
10435 | 388 } |
389 | |
10421 | 390 static GtkWidget * |
391 create_saved_status_list(StatusWindow *dialog) | |
392 { | |
393 GtkWidget *sw; | |
394 GtkWidget *treeview; | |
395 GtkTreeSelection *sel; | |
396 GtkTreeViewColumn *column; | |
397 GtkCellRenderer *renderer; | |
398 | |
399 /* Create the scrolled window */ | |
400 sw = gtk_scrolled_window_new(0, 0); | |
401 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
402 GTK_POLICY_AUTOMATIC, | |
403 GTK_POLICY_ALWAYS); | |
404 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), | |
405 GTK_SHADOW_IN); | |
406 gtk_widget_show(sw); | |
407 | |
408 /* Create the list model */ | |
409 dialog->model = gtk_list_store_new(STATUS_WINDOW_NUM_COLUMNS, | |
410 G_TYPE_STRING, | |
411 G_TYPE_STRING, | |
412 G_TYPE_STRING); | |
413 | |
414 /* Create the treeview */ | |
415 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); | |
416 dialog->treeview = treeview; | |
417 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); | |
418 | |
419 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); | |
420 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); | |
421 g_signal_connect(G_OBJECT(sel), "changed", | |
422 G_CALLBACK(status_selected_cb), dialog); | |
423 | |
424 gtk_container_add(GTK_CONTAINER(sw), treeview); | |
425 gtk_widget_show(treeview); | |
426 | |
427 /* Add columns */ | |
428 column = gtk_tree_view_column_new(); | |
429 gtk_tree_view_column_set_title(column, _("Title")); | |
430 gtk_tree_view_column_set_resizable(column, TRUE); | |
11548 | 431 gtk_tree_view_column_set_min_width(column, 100); |
10421 | 432 gtk_tree_view_column_set_sort_column_id(column, |
433 STATUS_WINDOW_COLUMN_TITLE); | |
434 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); | |
435 renderer = gtk_cell_renderer_text_new(); | |
436 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
437 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
438 STATUS_WINDOW_COLUMN_TITLE); | |
11548 | 439 #if GTK_CHECK_VERSION(2,6,0) |
440 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); | |
441 #endif | |
10421 | 442 |
443 column = gtk_tree_view_column_new(); | |
444 gtk_tree_view_column_set_title(column, _("Type")); | |
445 gtk_tree_view_column_set_resizable(column, TRUE); | |
446 gtk_tree_view_column_set_sort_column_id(column, | |
447 STATUS_WINDOW_COLUMN_TYPE); | |
448 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); | |
449 renderer = gtk_cell_renderer_text_new(); | |
450 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
451 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
452 STATUS_WINDOW_COLUMN_TYPE); | |
453 | |
454 column = gtk_tree_view_column_new(); | |
455 gtk_tree_view_column_set_title(column, _("Message")); | |
456 gtk_tree_view_column_set_resizable(column, TRUE); | |
457 gtk_tree_view_column_set_sort_column_id(column, | |
458 STATUS_WINDOW_COLUMN_MESSAGE); | |
459 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); | |
460 renderer = gtk_cell_renderer_text_new(); | |
461 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
462 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
463 STATUS_WINDOW_COLUMN_MESSAGE); | |
10435 | 464 #if GTK_CHECK_VERSION(2,6,0) |
10502 | 465 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
10435 | 466 #endif |
467 | |
468 /* Enable CTRL+F searching */ | |
469 gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), STATUS_WINDOW_COLUMN_TITLE); | |
470 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview), search_func, NULL, NULL); | |
10421 | 471 |
10422 | 472 /* Sort the title column by default */ |
473 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->model), | |
474 STATUS_WINDOW_COLUMN_TITLE, | |
475 GTK_SORT_ASCENDING); | |
476 | |
10421 | 477 /* Populate list */ |
478 populate_saved_status_list(dialog); | |
479 | |
480 return sw; | |
481 } | |
482 | |
483 static gboolean | |
484 configure_cb(GtkWidget *widget, GdkEventConfigure *event, StatusWindow *dialog) | |
485 { | |
486 if (GTK_WIDGET_VISIBLE(widget)) { | |
487 gaim_prefs_set_int("/gaim/gtk/status/dialog/width", event->width); | |
488 gaim_prefs_set_int("/gaim/gtk/status/dialog/height", event->height); | |
489 } | |
490 | |
491 return FALSE; | |
492 } | |
493 | |
494 void | |
495 gaim_gtk_status_window_show(void) | |
496 { | |
497 StatusWindow *dialog; | |
498 GtkWidget *bbox; | |
499 GtkWidget *button; | |
500 GtkWidget *list; | |
501 GtkWidget *vbox; | |
502 GtkWidget *win; | |
503 int width, height; | |
504 | |
505 if (status_window != NULL) { | |
506 gtk_window_present(GTK_WINDOW(status_window->window)); | |
507 return; | |
508 } | |
509 | |
510 status_window = dialog = g_new0(StatusWindow, 1); | |
511 | |
512 width = gaim_prefs_get_int("/gaim/gtk/status/dialog/width"); | |
513 height = gaim_prefs_get_int("/gaim/gtk/status/dialog/height"); | |
514 | |
515 dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
516 gtk_window_set_default_size(GTK_WINDOW(win), width, height); | |
517 gtk_window_set_role(GTK_WINDOW(win), "statuses"); | |
518 gtk_window_set_title(GTK_WINDOW(win), _("Saved Statuses")); | |
11243 | 519 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); |
10421 | 520 |
521 g_signal_connect(G_OBJECT(win), "delete_event", | |
522 G_CALLBACK(status_window_destroy_cb), dialog); | |
523 g_signal_connect(G_OBJECT(win), "configure_event", | |
524 G_CALLBACK(configure_cb), dialog); | |
525 | |
526 /* Setup the vbox */ | |
11243 | 527 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); |
10421 | 528 gtk_container_add(GTK_CONTAINER(win), vbox); |
529 gtk_widget_show(vbox); | |
530 | |
531 /* List of saved status states */ | |
532 list = create_saved_status_list(dialog); | |
533 gtk_box_pack_start(GTK_BOX(vbox), list, TRUE, TRUE, 0); | |
534 | |
535 /* Button box. */ | |
536 bbox = gtk_hbutton_box_new(); | |
11243 | 537 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); |
10421 | 538 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); |
539 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); | |
540 gtk_widget_show(bbox); | |
541 | |
11811 | 542 /* Use button */ |
11832 | 543 button = gaim_pixbuf_button_from_stock(_("_Use"), GTK_STOCK_EXECUTE, |
544 GAIM_BUTTON_HORIZONTAL); | |
11811 | 545 dialog->use_button = button; |
546 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
547 gtk_widget_set_sensitive(button, FALSE); | |
548 gtk_widget_show(button); | |
549 | |
550 g_signal_connect(G_OBJECT(button), "clicked", | |
551 G_CALLBACK(status_window_use_cb), dialog); | |
552 | |
10421 | 553 /* Add button */ |
554 button = gtk_button_new_from_stock(GTK_STOCK_ADD); | |
555 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
556 gtk_widget_show(button); | |
557 | |
558 g_signal_connect(G_OBJECT(button), "clicked", | |
559 G_CALLBACK(status_window_add_cb), dialog); | |
560 | |
561 /* Modify button */ | |
562 button = gtk_button_new_from_stock(GAIM_STOCK_MODIFY); | |
563 dialog->modify_button = button; | |
564 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
565 gtk_widget_set_sensitive(button, FALSE); | |
566 gtk_widget_show(button); | |
567 | |
568 g_signal_connect(G_OBJECT(button), "clicked", | |
569 G_CALLBACK(status_window_modify_cb), dialog); | |
570 | |
571 /* Delete button */ | |
572 button = gtk_button_new_from_stock(GTK_STOCK_DELETE); | |
573 dialog->delete_button = button; | |
574 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
575 gtk_widget_set_sensitive(button, FALSE); | |
576 gtk_widget_show(button); | |
577 | |
578 g_signal_connect(G_OBJECT(button), "clicked", | |
579 G_CALLBACK(status_window_delete_cb), dialog); | |
580 | |
581 /* Close button */ | |
582 button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); | |
583 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
584 gtk_widget_show(button); | |
585 | |
586 g_signal_connect(G_OBJECT(button), "clicked", | |
587 G_CALLBACK(status_window_close_cb), dialog); | |
588 | |
589 gtk_widget_show(win); | |
590 } | |
591 | |
592 void | |
593 gaim_gtk_status_window_hide(void) | |
594 { | |
595 if (status_window == NULL) | |
596 return; | |
597 | |
598 if (status_window->window != NULL) | |
599 gtk_widget_destroy(status_window->window); | |
600 | |
601 g_free(status_window); | |
602 status_window = NULL; | |
603 } | |
604 | |
605 | |
606 /************************************************************************** | |
607 * Status editor | |
608 **************************************************************************/ | |
10420 | 609 |
10418 | 610 static gboolean |
611 status_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) | |
612 { | |
10574 | 613 StatusEditor *dialog = user_data; |
10418 | 614 |
10574 | 615 g_free(dialog->original_title); |
10418 | 616 g_free(dialog); |
617 | |
618 return FALSE; | |
619 } | |
620 | |
621 static void | |
622 status_editor_cancel_cb(GtkButton *button, gpointer user_data) | |
623 { | |
10574 | 624 StatusEditor *dialog = user_data; |
10418 | 625 |
626 gtk_widget_destroy(dialog->window); | |
627 | |
10574 | 628 g_free(dialog->original_title); |
10418 | 629 g_free(dialog); |
630 } | |
631 | |
632 static void | |
633 status_editor_save_cb(GtkButton *button, gpointer user_data) | |
634 { | |
10420 | 635 StatusEditor *dialog = user_data; |
636 const char *title; | |
637 GaimStatusPrimitive type; | |
638 char *message, *unformatted; | |
12080 | 639 GaimSavedStatus *saved_status = NULL; |
640 GtkTreeModel *model; | |
641 GtkTreeIter iter; | |
10420 | 642 |
643 title = gtk_entry_get_text(dialog->title); | |
644 | |
645 /* | |
646 * If the title is already taken then show an error dialog and | |
647 * don't do anything. | |
648 */ | |
649 if ((gaim_savedstatus_find(title) != NULL) && | |
650 ((dialog->original_title == NULL) || (strcmp(title, dialog->original_title)))) | |
651 { | |
652 gaim_notify_error(NULL, NULL, _("Title already in use. You must " | |
653 "choose a unique title."), NULL); | |
654 return; | |
655 } | |
656 | |
657 type = gtk_option_menu_get_history(dialog->type); | |
658 message = gtk_imhtml_get_markup(dialog->message); | |
659 unformatted = gaim_markup_strip_html(message); | |
660 | |
661 /* | |
12080 | 662 * If we're editing an old status, then lookup the old status (it's |
663 * possible that it has been deleted or renamed or something, and | |
664 * no longer exists). | |
10420 | 665 */ |
666 if (dialog->original_title != NULL) | |
667 { | |
668 GtkTreeIter iter; | |
669 | |
12080 | 670 saved_status = gaim_savedstatus_find(dialog->original_title); |
10420 | 671 |
672 if (status_window_find_savedstatus(&iter, dialog->original_title)) | |
673 { | |
674 gtk_list_store_remove(status_window->model, &iter); | |
675 } | |
676 } | |
677 | |
12080 | 678 if (saved_status == NULL) |
679 { | |
680 /* This is a new status */ | |
681 saved_status = gaim_savedstatus_new(title, type); | |
682 } | |
683 else | |
684 { | |
685 /* Modify the old status */ | |
686 if (strcmp(title, dialog->original_title)) | |
687 gaim_savedstatus_set_title(saved_status, title); | |
688 gaim_savedstatus_set_type(saved_status, type); | |
689 } | |
690 | |
10420 | 691 if (*unformatted != '\0') |
12080 | 692 gaim_savedstatus_set_message(saved_status, message); |
693 | |
694 /* Set any substatuses */ | |
695 model = GTK_TREE_MODEL(dialog->model); | |
696 if (gtk_tree_model_get_iter_first(model, &iter)) | |
697 { | |
698 GaimAccount *account; | |
699 gboolean enabled; | |
700 char *id; | |
701 char *message; | |
702 GaimStatusType *type; | |
703 | |
704 gtk_tree_model_get(model, &iter, | |
705 STATUS_EDITOR_COLUMN_ACCOUNT, &account, | |
706 STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, &enabled, | |
707 STATUS_EDITOR_COLUMN_STATUS_ID, &id, | |
708 STATUS_EDITOR_COLUMN_STATUS_MESSAGE, &message, | |
709 -1); | |
710 if (enabled) | |
711 { | |
712 type = gaim_account_get_status_type(account, id); | |
713 gaim_savedstatus_set_substatus(saved_status, account, type, message); | |
714 } | |
715 g_free(id); | |
716 g_free(message); | |
717 | |
718 while (gtk_tree_model_iter_next(model, &iter)) | |
719 { | |
720 gtk_tree_model_get(model, &iter, | |
721 STATUS_EDITOR_COLUMN_ACCOUNT, &account, | |
722 STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, &enabled, | |
723 STATUS_EDITOR_COLUMN_STATUS_ID, &id, | |
724 STATUS_EDITOR_COLUMN_STATUS_MESSAGE, &message, | |
725 -1); | |
726 if (enabled) | |
727 { | |
728 type = gaim_account_get_status_type(account, id); | |
729 gaim_savedstatus_set_substatus(saved_status, account, type, message); | |
730 } | |
731 g_free(id); | |
732 g_free(message); | |
733 } | |
734 } | |
735 | |
10420 | 736 g_free(message); |
737 g_free(unformatted); | |
738 | |
739 gtk_widget_destroy(dialog->window); | |
10574 | 740 g_free(dialog->original_title); |
10420 | 741 g_free(dialog); |
742 | |
12080 | 743 if (status_window != NULL) |
744 add_status_to_saved_status_list(status_window->model, saved_status); | |
10420 | 745 } |
746 | |
747 static void | |
748 editor_title_changed_cb(GtkWidget *widget, gpointer user_data) | |
749 { | |
750 StatusEditor *dialog = user_data; | |
751 const gchar *text; | |
752 | |
753 text = gtk_entry_get_text(dialog->title); | |
754 | |
755 gtk_widget_set_sensitive(dialog->save_button, (*text != '\0')); | |
10418 | 756 } |
757 | |
758 static GtkWidget * | |
10419 | 759 create_status_type_menu(GaimStatusPrimitive type) |
10418 | 760 { |
10419 | 761 int i; |
10418 | 762 GtkWidget *dropdown; |
763 GtkWidget *menu; | |
764 GtkWidget *item; | |
765 | |
766 dropdown = gtk_option_menu_new(); | |
767 menu = gtk_menu_new(); | |
768 | |
10419 | 769 for (i = 0; i < GAIM_STATUS_NUM_PRIMITIVES; i++) |
770 { | |
771 item = gtk_menu_item_new_with_label(gaim_primitive_get_name_from_type(i)); | |
772 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | |
773 gtk_widget_show(item); | |
774 } | |
10418 | 775 |
10419 | 776 gtk_menu_set_active(GTK_MENU(menu), type); |
10418 | 777 gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu); |
778 gtk_widget_show(menu); | |
779 | |
780 return dropdown; | |
781 } | |
782 | |
12080 | 783 static void edit_substatus(StatusEditor *status_editor, GaimAccount *account); |
784 | |
785 static void | |
786 edit_substatus_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data) | |
787 { | |
788 StatusEditor *dialog = user_data; | |
789 GtkTreeIter iter; | |
790 GaimAccount *account; | |
791 | |
792 gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); | |
793 gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, | |
794 STATUS_EDITOR_COLUMN_ACCOUNT, &account, | |
795 -1); | |
796 | |
797 edit_substatus(dialog, account); | |
798 } | |
799 | |
800 static void | |
801 status_editor_substatus_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data) | |
802 { | |
803 StatusEditor *dialog = (StatusEditor *)data; | |
804 GtkTreeIter iter; | |
805 gboolean enabled; | |
806 GaimAccount *account; | |
807 | |
808 gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(dialog->model), &iter, path_str); | |
809 gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, | |
810 STATUS_EDITOR_COLUMN_ACCOUNT, &account, | |
811 STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, &enabled, | |
812 -1); | |
813 | |
814 enabled = !enabled; | |
815 | |
816 if (enabled) | |
817 { | |
818 edit_substatus(dialog, account); | |
819 } | |
820 else | |
821 { | |
822 GaimSavedStatus *saved_status; | |
823 | |
824 /* Remove the substatus */ | |
825 saved_status = gaim_savedstatus_find(dialog->original_title); | |
826 gaim_savedstatus_unset_substatus(saved_status, account); | |
827 gtk_list_store_set(dialog->model, &iter, | |
828 STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, enabled, | |
829 STATUS_EDITOR_COLUMN_STATUS_ID, NULL, | |
830 STATUS_EDITOR_COLUMN_STATUS_NAME, NULL, | |
831 STATUS_EDITOR_COLUMN_STATUS_MESSAGE, NULL, | |
832 -1); | |
833 } | |
834 } | |
835 | |
10418 | 836 static void |
837 status_editor_add_columns(StatusEditor *dialog) | |
838 { | |
839 GtkCellRenderer *renderer; | |
840 GtkTreeViewColumn *column; | |
841 | |
12080 | 842 /* Enable Different status column */ |
10418 | 843 renderer = gtk_cell_renderer_toggle_new(); |
844 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog->treeview), | |
12080 | 845 -1, _("Different"), |
10418 | 846 renderer, |
12080 | 847 "active", STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, |
10418 | 848 NULL); |
849 column = gtk_tree_view_get_column(GTK_TREE_VIEW(dialog->treeview), 1); | |
850 g_signal_connect(G_OBJECT(renderer), "toggled", | |
12080 | 851 G_CALLBACK(status_editor_substatus_cb), dialog); |
10418 | 852 |
853 /* Screen Name column */ | |
854 column = gtk_tree_view_column_new(); | |
855 gtk_tree_view_column_set_resizable(column, TRUE); | |
856 gtk_tree_view_column_set_title(column, _("Screen Name")); | |
857 gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); | |
858 gtk_tree_view_column_set_resizable(column, TRUE); | |
859 | |
860 /* Icon */ | |
861 renderer = gtk_cell_renderer_pixbuf_new(); | |
862 gtk_tree_view_column_pack_start(column, renderer, FALSE); | |
863 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", | |
864 STATUS_EDITOR_COLUMN_ICON); | |
865 | |
866 /* Screen Name */ | |
867 renderer = gtk_cell_renderer_text_new(); | |
868 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
869 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
870 STATUS_EDITOR_COLUMN_SCREENNAME); | |
12080 | 871 |
872 /* Status column */ | |
873 column = gtk_tree_view_column_new(); | |
874 gtk_tree_view_column_set_resizable(column, TRUE); | |
875 gtk_tree_view_column_set_title(column, _("Status")); | |
876 gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); | |
877 gtk_tree_view_column_set_resizable(column, TRUE); | |
878 renderer = gtk_cell_renderer_text_new(); | |
879 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
880 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
881 STATUS_EDITOR_COLUMN_STATUS_NAME); | |
882 | |
883 /* Message column */ | |
884 column = gtk_tree_view_column_new(); | |
885 gtk_tree_view_column_set_resizable(column, TRUE); | |
886 gtk_tree_view_column_set_title(column, _("Message")); | |
887 gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); | |
888 gtk_tree_view_column_set_resizable(column, TRUE); | |
889 renderer = gtk_cell_renderer_text_new(); | |
890 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
891 gtk_tree_view_column_add_attribute(column, renderer, "text", | |
892 STATUS_EDITOR_COLUMN_STATUS_MESSAGE); | |
893 | |
894 g_signal_connect(G_OBJECT(dialog->treeview), "row-activated", | |
895 G_CALLBACK(edit_substatus_cb), dialog); | |
10418 | 896 } |
897 | |
898 static void | |
12080 | 899 status_editor_set_account(GtkListStore *store, GaimAccount *account, |
900 GtkTreeIter *iter, GaimSavedStatusSub *substatus) | |
10418 | 901 { |
902 GdkPixbuf *pixbuf; | |
903 GdkPixbuf *scale; | |
12080 | 904 const char *id = NULL, *name = NULL, *message = NULL; |
10418 | 905 |
906 scale = NULL; | |
907 | |
10884 | 908 pixbuf = gaim_gtk_create_prpl_icon(account); |
10418 | 909 |
910 if (pixbuf != NULL) | |
911 { | |
912 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); | |
913 | |
11251 | 914 if (gaim_account_is_disconnected(account)) |
10418 | 915 gdk_pixbuf_saturate_and_pixelate(scale, scale, 0.0, FALSE); |
916 } | |
917 | |
12080 | 918 if (substatus != NULL) |
919 { | |
920 const GaimStatusType *type; | |
921 | |
922 type = gaim_savedstatus_substatus_get_type(substatus); | |
923 id = gaim_status_type_get_id(type); | |
924 name = gaim_status_type_get_name(type); | |
925 if (gaim_status_type_get_attr(type, "message")) | |
926 message = gaim_savedstatus_substatus_get_message(substatus); | |
927 } | |
928 | |
10418 | 929 gtk_list_store_set(store, iter, |
12080 | 930 STATUS_EDITOR_COLUMN_ACCOUNT, account, |
931 STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, (substatus != NULL), | |
10418 | 932 STATUS_EDITOR_COLUMN_ICON, scale, |
933 STATUS_EDITOR_COLUMN_SCREENNAME, gaim_account_get_username(account), | |
12080 | 934 STATUS_EDITOR_COLUMN_STATUS_ID, id, |
935 STATUS_EDITOR_COLUMN_STATUS_NAME, name, | |
936 STATUS_EDITOR_COLUMN_STATUS_MESSAGE, message, | |
10418 | 937 -1); |
938 | |
939 if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); | |
940 if (scale != NULL) g_object_unref(G_OBJECT(scale)); | |
941 } | |
942 | |
943 static void | |
12080 | 944 status_editor_add_account(StatusEditor *dialog, GaimAccount *account, |
945 GaimSavedStatusSub *substatus) | |
10418 | 946 { |
947 GtkTreeIter iter; | |
948 | |
949 gtk_list_store_append(dialog->model, &iter); | |
950 | |
12080 | 951 status_editor_set_account(dialog->model, account, &iter, substatus); |
10418 | 952 } |
953 | |
954 static void | |
12080 | 955 status_editor_populate_list(StatusEditor *dialog, GaimSavedStatus *saved_status) |
10418 | 956 { |
12080 | 957 GList *iter; |
958 GaimSavedStatusSub *substatus; | |
10418 | 959 |
960 gtk_list_store_clear(dialog->model); | |
961 | |
12080 | 962 for (iter = gaim_accounts_get_all(); iter != NULL; iter = iter->next) |
963 { | |
964 GaimAccount *account = (GaimAccount *)iter->data; | |
965 | |
966 if (saved_status != NULL) | |
967 substatus = gaim_savedstatus_get_substatus(saved_status, account); | |
968 else | |
969 substatus = NULL; | |
970 | |
971 status_editor_add_account(dialog, account, substatus); | |
972 } | |
10418 | 973 } |
974 | |
975 void | |
12080 | 976 gaim_gtk_status_editor_show(GaimSavedStatus *saved_status) |
10418 | 977 { |
978 StatusEditor *dialog; | |
979 GtkSizeGroup *sg; | |
980 GtkWidget *bbox; | |
981 GtkWidget *button; | |
982 GtkWidget *dbox; | |
11735 | 983 GtkWidget *expander; |
10418 | 984 GtkWidget *dropdown; |
985 GtkWidget *entry; | |
986 GtkWidget *frame; | |
987 GtkWidget *hbox; | |
988 GtkWidget *label; | |
989 GtkWidget *sw; | |
990 GtkWidget *text; | |
991 GtkWidget *toolbar; | |
992 GtkWidget *vbox; | |
993 GtkWidget *win; | |
994 | |
995 dialog = g_new0(StatusEditor, 1); | |
996 | |
12080 | 997 if (saved_status != NULL) |
998 dialog->original_title = g_strdup(gaim_savedstatus_get_title(saved_status)); | |
10420 | 999 |
10418 | 1000 dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
1001 gtk_window_set_role(GTK_WINDOW(win), "status"); | |
1002 gtk_window_set_title(GTK_WINDOW(win), _("Status")); | |
1003 gtk_window_set_resizable(GTK_WINDOW(win), FALSE); | |
11243 | 1004 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); |
10418 | 1005 |
1006 g_signal_connect(G_OBJECT(win), "delete_event", | |
1007 G_CALLBACK(status_editor_destroy_cb), dialog); | |
1008 | |
1009 /* Setup the vbox */ | |
11243 | 1010 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); |
10418 | 1011 gtk_container_add(GTK_CONTAINER(win), vbox); |
1012 gtk_widget_show(vbox); | |
1013 | |
1014 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); | |
1015 | |
1016 /* Title */ | |
11243 | 1017 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
10418 | 1018 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
1019 gtk_widget_show(hbox); | |
1020 | |
1021 label = gtk_label_new_with_mnemonic(_("_Title:")); | |
1022 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
1023 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
1024 gtk_widget_show(label); | |
1025 gtk_size_group_add_widget(sg, label); | |
1026 | |
1027 entry = gtk_entry_new(); | |
10420 | 1028 dialog->title = GTK_ENTRY(entry); |
12080 | 1029 if (dialog->original_title != NULL) |
10420 | 1030 gtk_entry_set_text(GTK_ENTRY(entry), dialog->original_title); |
10418 | 1031 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); |
1032 gtk_widget_show(entry); | |
10420 | 1033 g_signal_connect(G_OBJECT(entry), "changed", |
1034 G_CALLBACK(editor_title_changed_cb), dialog); | |
10418 | 1035 |
1036 /* Status type */ | |
11243 | 1037 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
10418 | 1038 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
1039 gtk_widget_show(hbox); | |
1040 | |
1041 label = gtk_label_new_with_mnemonic(_("_Status:")); | |
1042 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
1043 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
1044 gtk_widget_show(label); | |
1045 gtk_size_group_add_widget(sg, label); | |
1046 | |
12080 | 1047 if (saved_status != NULL) |
1048 dropdown = create_status_type_menu(gaim_savedstatus_get_type(saved_status)); | |
10419 | 1049 else |
1050 dropdown = create_status_type_menu(GAIM_STATUS_AWAY); | |
10420 | 1051 dialog->type = GTK_OPTION_MENU(dropdown); |
10418 | 1052 gtk_box_pack_start(GTK_BOX(hbox), dropdown, TRUE, TRUE, 0); |
1053 gtk_widget_show(dropdown); | |
1054 | |
1055 /* Status message */ | |
11243 | 1056 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
10418 | 1057 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
1058 gtk_widget_show(hbox); | |
1059 | |
1060 label = gtk_label_new_with_mnemonic(_("_Message:")); | |
1061 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
1062 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
1063 gtk_widget_show(label); | |
1064 gtk_size_group_add_widget(sg, label); | |
1065 | |
1066 frame = gaim_gtk_create_imhtml(TRUE, &text, &toolbar); | |
10420 | 1067 dialog->message = GTK_IMHTML(text); |
10418 | 1068 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); |
1069 gtk_widget_show(frame); | |
1070 | |
12080 | 1071 if ((saved_status != NULL) && (gaim_savedstatus_get_message(saved_status) != NULL)) |
10419 | 1072 gtk_imhtml_append_text(GTK_IMHTML(text), |
12080 | 1073 gaim_savedstatus_get_message(saved_status), 0); |
10419 | 1074 |
12080 | 1075 /* Different status message expander */ |
11735 | 1076 expander = gtk_expander_new_with_mnemonic(_("Use a _different status for some accounts")); |
1077 gtk_box_pack_start(GTK_BOX(vbox), expander, FALSE, FALSE, 0); | |
1078 gtk_widget_show(expander); | |
10418 | 1079 |
11735 | 1080 /* Setup the box that the expander will cover */ |
11243 | 1081 dbox = gtk_vbox_new(FALSE, GAIM_HIG_CAT_SPACE); |
11735 | 1082 gtk_container_add(GTK_CONTAINER(expander), dbox); |
1083 gtk_widget_show(dbox); | |
10418 | 1084 |
12080 | 1085 /* Different status message treeview */ |
10418 | 1086 sw = gtk_scrolled_window_new(NULL, NULL); |
1087 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
1088 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
1089 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), | |
1090 GTK_SHADOW_IN); | |
1091 gtk_box_pack_start(GTK_BOX(dbox), sw, TRUE, TRUE, 0); | |
1092 gtk_widget_show(sw); | |
1093 | |
1094 /* Create the list model */ | |
1095 dialog->model = gtk_list_store_new(STATUS_EDITOR_NUM_COLUMNS, | |
12080 | 1096 G_TYPE_POINTER, |
10418 | 1097 G_TYPE_BOOLEAN, |
12080 | 1098 GDK_TYPE_PIXBUF, |
1099 G_TYPE_STRING, | |
1100 G_TYPE_STRING, | |
1101 G_TYPE_STRING, | |
1102 G_TYPE_STRING); | |
10418 | 1103 |
1104 /* Create the treeview */ | |
1105 dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); | |
1106 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); | |
1107 gtk_widget_set_size_request(dialog->treeview, 400, 250); | |
1108 gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); | |
1109 gtk_widget_show(dialog->treeview); | |
1110 | |
1111 /* Add columns */ | |
1112 status_editor_add_columns(dialog); | |
1113 | |
1114 /* Populate list */ | |
12080 | 1115 status_editor_populate_list(dialog, saved_status); |
10418 | 1116 |
1117 /* Button box */ | |
1118 bbox = gtk_hbutton_box_new(); | |
11243 | 1119 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); |
10418 | 1120 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); |
1121 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); | |
1122 gtk_widget_show(bbox); | |
1123 | |
1124 /* Cancel button */ | |
1125 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); | |
1126 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
1127 gtk_widget_show(button); | |
1128 | |
1129 g_signal_connect(G_OBJECT(button), "clicked", | |
1130 G_CALLBACK(status_editor_cancel_cb), dialog); | |
1131 | |
1132 /* Save button */ | |
1133 button = gtk_button_new_from_stock(GTK_STOCK_SAVE); | |
10420 | 1134 dialog->save_button = button; |
10418 | 1135 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); |
12080 | 1136 if (dialog->title == NULL) |
1137 gtk_widget_set_sensitive(button, FALSE); | |
10418 | 1138 gtk_widget_show(button); |
1139 | |
1140 g_signal_connect(G_OBJECT(button), "clicked", | |
1141 G_CALLBACK(status_editor_save_cb), dialog); | |
1142 | |
1143 gtk_widget_show(win); | |
1144 } | |
1145 | |
1146 | |
10421 | 1147 /************************************************************************** |
12080 | 1148 * SubStatus editor |
1149 **************************************************************************/ | |
1150 | |
1151 static void | |
1152 substatus_selection_changed_cb(GtkComboBox *box, gpointer user_data) | |
1153 { | |
1154 SubStatusEditor *select = user_data; | |
1155 GtkTreeIter iter; | |
1156 GaimAccount *account; | |
1157 char *id; | |
1158 GaimStatusType *type; | |
1159 | |
1160 if (!gtk_combo_box_get_active_iter(box, &iter)) | |
1161 return; | |
1162 gtk_tree_model_get(GTK_TREE_MODEL(select->model), &iter, | |
1163 SUBSTATUS_COLUMN_ACCOUNT, &account, | |
1164 SUBSTATUS_COLUMN_STATUS_ID, &id, | |
1165 -1); | |
1166 type = gaim_account_get_status_type(account, id); | |
1167 g_free(id); | |
1168 | |
1169 if (gaim_status_type_get_attr(type, "message") == NULL) | |
1170 { | |
1171 gtk_widget_set_sensitive(GTK_WIDGET(select->message), FALSE); | |
1172 gtk_widget_set_sensitive(GTK_WIDGET(select->toolbar), FALSE); | |
1173 } | |
1174 else | |
1175 { | |
1176 gtk_widget_set_sensitive(GTK_WIDGET(select->message), TRUE); | |
1177 gtk_widget_set_sensitive(GTK_WIDGET(select->toolbar), TRUE); | |
1178 } | |
1179 } | |
1180 | |
1181 static gboolean | |
1182 substatus_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) | |
1183 { | |
1184 SubStatusEditor *dialog = user_data; | |
1185 | |
1186 g_free(dialog); | |
1187 | |
1188 return FALSE; | |
1189 } | |
1190 | |
1191 void | |
1192 substatus_editor_cancel_cb(GtkButton *button, gpointer user_data) | |
1193 { | |
1194 SubStatusEditor *dialog = user_data; | |
1195 | |
1196 gtk_widget_destroy(dialog->window); | |
1197 | |
1198 g_free(dialog); | |
1199 } | |
1200 | |
1201 static gboolean | |
1202 status_editor_find_account_in_treemodel(GtkTreeIter *iter, | |
1203 StatusEditor *status_editor, | |
1204 GaimAccount *account) | |
1205 { | |
1206 GtkTreeModel *model; | |
1207 GaimAccount *cur; | |
1208 | |
1209 g_return_val_if_fail(status_editor != NULL, FALSE); | |
1210 g_return_val_if_fail(account != NULL, FALSE); | |
1211 | |
1212 model = GTK_TREE_MODEL(status_editor->model); | |
1213 | |
1214 if (!gtk_tree_model_get_iter_first(model, iter)) | |
1215 return FALSE; | |
1216 | |
1217 gtk_tree_model_get(model, iter, STATUS_EDITOR_COLUMN_ACCOUNT, &cur, -1); | |
1218 if (cur == account) | |
1219 return TRUE; | |
1220 | |
1221 while (gtk_tree_model_iter_next(model, iter)) | |
1222 { | |
1223 gtk_tree_model_get(model, iter, STATUS_EDITOR_COLUMN_ACCOUNT, &cur, -1); | |
1224 if (cur == account) | |
1225 return TRUE; | |
1226 } | |
1227 | |
1228 return FALSE; | |
1229 } | |
1230 | |
1231 void | |
1232 substatus_editor_ok_cb(GtkButton *button, gpointer user_data) | |
1233 { | |
1234 SubStatusEditor *dialog = user_data; | |
1235 StatusEditor *status_editor; | |
1236 GtkTreeIter iter; | |
1237 GaimAccount *account; | |
1238 GaimStatusType *type; | |
1239 char *id = NULL; | |
1240 char *message = NULL; | |
1241 const char *name = NULL; | |
1242 | |
1243 gtk_combo_box_get_active_iter(dialog->box, &iter); | |
1244 gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, | |
1245 SUBSTATUS_COLUMN_ACCOUNT, &account, | |
1246 SUBSTATUS_COLUMN_STATUS_ID, &id, | |
1247 -1); | |
1248 type = gaim_account_get_status_type(account, id); | |
1249 if (gaim_status_type_get_attr(type, "message") != NULL) | |
1250 message = gtk_imhtml_get_text(GTK_IMHTML(dialog->message), NULL, NULL); | |
1251 name = gaim_status_type_get_name(type); | |
1252 | |
1253 status_editor = dialog->status_editor; | |
1254 | |
1255 if (status_editor_find_account_in_treemodel(&iter, status_editor, account)) | |
1256 { | |
1257 gtk_list_store_set(status_editor->model, &iter, | |
1258 STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, TRUE, | |
1259 STATUS_EDITOR_COLUMN_STATUS_ID, id, | |
1260 STATUS_EDITOR_COLUMN_STATUS_NAME, name, | |
1261 STATUS_EDITOR_COLUMN_STATUS_MESSAGE, message, | |
1262 -1); | |
1263 } | |
1264 | |
1265 gtk_widget_destroy(dialog->window); | |
1266 g_free(id); | |
1267 g_free(message); | |
1268 g_free(dialog); | |
1269 } | |
1270 | |
1271 static void | |
1272 edit_substatus(StatusEditor *status_editor, GaimAccount *account) | |
1273 { | |
1274 char *tmp; | |
1275 SubStatusEditor *dialog; | |
1276 GtkSizeGroup *sg; | |
1277 GtkWidget *bbox; | |
1278 GtkWidget *button; | |
1279 GtkWidget *combo; | |
1280 GtkWidget *hbox; | |
1281 GtkWidget *frame; | |
1282 GtkWidget *label; | |
1283 GtkWidget *text; | |
1284 GtkWidget *toolbar; | |
1285 GtkWidget *vbox; | |
1286 GtkWidget *win; | |
1287 GtkTreeIter iter; | |
1288 GtkCellRenderer *rend; | |
1289 const char *id = NULL; | |
1290 const GList *list; | |
1291 gboolean select = FALSE; | |
1292 | |
1293 g_return_if_fail(status_editor != NULL); | |
1294 g_return_if_fail(account != NULL); | |
1295 | |
1296 dialog = g_new0(SubStatusEditor, 1); | |
1297 dialog->status_editor = status_editor; | |
1298 | |
1299 dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
1300 gtk_window_set_role(GTK_WINDOW(win), "substatus"); | |
1301 tmp = g_strdup_printf(_("Status for %s"), gaim_account_get_username(account)); | |
1302 gtk_window_set_title(GTK_WINDOW(win), tmp); | |
1303 g_free(tmp); | |
1304 gtk_window_set_resizable(GTK_WINDOW(win), FALSE); | |
1305 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); | |
1306 | |
1307 g_signal_connect(G_OBJECT(win), "delete_event", | |
1308 G_CALLBACK(substatus_editor_destroy_cb), dialog); | |
1309 | |
1310 /* Setup the vbox */ | |
1311 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); | |
1312 gtk_container_add(GTK_CONTAINER(win), vbox); | |
1313 gtk_widget_show(vbox); | |
1314 | |
1315 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); | |
1316 | |
1317 /* Status type */ | |
1318 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); | |
1319 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); | |
1320 gtk_widget_show(hbox); | |
1321 | |
1322 label = gtk_label_new_with_mnemonic(_("_Status:")); | |
1323 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
1324 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
1325 gtk_widget_show(label); | |
1326 gtk_size_group_add_widget(sg, label); | |
1327 | |
1328 dialog->model = gtk_list_store_new(SUBSTATUS_NUM_COLUMNS, | |
1329 G_TYPE_POINTER, | |
1330 GDK_TYPE_PIXBUF, | |
1331 G_TYPE_STRING, | |
1332 G_TYPE_STRING); | |
1333 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dialog->model)); | |
1334 dialog->box = GTK_COMBO_BOX(combo); | |
1335 | |
1336 rend = GTK_CELL_RENDERER(gtk_cell_renderer_pixbuf_new()); | |
1337 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, FALSE); | |
1338 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend, | |
1339 "pixbuf", SUBSTATUS_COLUMN_ICON, NULL); | |
1340 | |
1341 rend = GTK_CELL_RENDERER(gtk_cell_renderer_text_new()); | |
1342 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, TRUE); | |
1343 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend, | |
1344 "text", SUBSTATUS_COLUMN_STATUS_NAME, NULL); | |
1345 | |
1346 g_signal_connect(G_OBJECT(combo), "changed", | |
1347 G_CALLBACK(substatus_selection_changed_cb), dialog); | |
1348 | |
1349 gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0); | |
1350 gtk_widget_show(combo); | |
1351 | |
1352 /* Status mesage */ | |
1353 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); | |
1354 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); | |
1355 gtk_widget_show(hbox); | |
1356 | |
1357 label = gtk_label_new_with_mnemonic(_("_Message:")); | |
1358 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
1359 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
1360 gtk_widget_show(label); | |
1361 gtk_size_group_add_widget(sg, label); | |
1362 | |
1363 frame = gaim_gtk_create_imhtml(TRUE, &text, &toolbar); | |
1364 dialog->message = GTK_IMHTML(text); | |
1365 dialog->toolbar = GTK_IMHTMLTOOLBAR(toolbar); | |
1366 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); | |
1367 gtk_widget_show(frame); | |
1368 | |
1369 /* Button box */ | |
1370 bbox = gtk_hbutton_box_new(); | |
1371 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); | |
1372 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); | |
1373 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); | |
1374 gtk_widget_show(bbox); | |
1375 | |
1376 /* Cancel button */ | |
1377 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); | |
1378 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
1379 gtk_widget_show(button); | |
1380 | |
1381 g_signal_connect(G_OBJECT(button), "clicked", | |
1382 G_CALLBACK(substatus_editor_cancel_cb), dialog); | |
1383 | |
1384 /* OK button */ | |
1385 button = gtk_button_new_from_stock(GTK_STOCK_OK); | |
1386 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
1387 gtk_widget_show(button); | |
1388 | |
1389 g_signal_connect(G_OBJECT(button), "clicked", | |
1390 G_CALLBACK(substatus_editor_ok_cb), dialog); | |
1391 | |
1392 /* Seed the input widgets with the current values */ | |
1393 /* TODO: Get the current values from our parent's list store, not the saved_status! */ | |
1394 if (status_editor->original_title != NULL) | |
1395 { | |
1396 GaimSavedStatus *saved_status = NULL; | |
1397 GaimSavedStatusSub *substatus = NULL; | |
1398 | |
1399 saved_status = gaim_savedstatus_find(status_editor->original_title); | |
1400 if (saved_status != NULL) | |
1401 substatus = gaim_savedstatus_get_substatus(saved_status, account); | |
1402 | |
1403 if (substatus != NULL) | |
1404 { | |
1405 gtk_imhtml_append_text(dialog->message, | |
1406 gaim_savedstatus_substatus_get_message(substatus), | |
1407 0); | |
1408 id = gaim_status_type_get_id(gaim_savedstatus_substatus_get_type(substatus)); | |
1409 } | |
1410 } | |
1411 | |
1412 for (list = gaim_account_get_status_types(account); list; list = list->next) | |
1413 { | |
1414 GaimStatusType *status_type; | |
1415 GdkPixbuf *pixbuf, *scale = NULL; | |
1416 const char *id, *name; | |
1417 | |
1418 status_type = list->data; | |
1419 id = gaim_status_type_get_id(status_type); | |
1420 pixbuf = gaim_gtk_create_prpl_icon_with_status(account, status_type); | |
1421 if (pixbuf != NULL) | |
1422 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); | |
1423 name = gaim_status_type_get_name(status_type); | |
1424 | |
1425 gtk_list_store_append(dialog->model, &iter); | |
1426 gtk_list_store_set(dialog->model, &iter, | |
1427 SUBSTATUS_COLUMN_ACCOUNT, account, | |
1428 SUBSTATUS_COLUMN_ICON, scale, | |
1429 SUBSTATUS_COLUMN_STATUS_ID, id, | |
1430 SUBSTATUS_COLUMN_STATUS_NAME, name, | |
1431 -1); | |
1432 if (id && !strcmp(id, gaim_status_type_get_id(status_type))) | |
1433 { | |
1434 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter); | |
1435 select = TRUE; | |
1436 } | |
1437 } | |
1438 | |
1439 if (!select) | |
1440 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); | |
1441 | |
1442 gtk_widget_show(win); | |
1443 } | |
1444 | |
1445 | |
1446 /************************************************************************** | |
10814
364a2ef907ae
[gaim-migrate @ 12468]
Luke Schierer <lschiere@pidgin.im>
parents:
10732
diff
changeset
|
1447 * GTK+ saved status glue |
10421 | 1448 **************************************************************************/ |
10418 | 1449 |
1450 void * | |
1451 gaim_gtk_status_get_handle() | |
1452 { | |
1453 static int handle; | |
1454 | |
1455 return &handle; | |
1456 } | |
1457 | |
1458 void | |
1459 gaim_gtk_status_init(void) | |
1460 { | |
1461 gaim_prefs_add_none("/gaim/gtk/status"); | |
1462 gaim_prefs_add_none("/gaim/gtk/status/dialog"); | |
1463 gaim_prefs_add_int("/gaim/gtk/status/dialog/width", 550); | |
1464 gaim_prefs_add_int("/gaim/gtk/status/dialog/height", 250); | |
1465 } | |
1466 | |
1467 void | |
1468 gaim_gtk_status_uninit(void) | |
1469 { | |
1470 gaim_gtk_status_window_hide(); | |
1471 } |