2 * Copyright (C) 1998-2006 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
28 #include <gtk/gtkalignment.h>
29 #include <gtk/gtkcellrenderertext.h>
30 #include <gtk/gtkcheckbutton.h>
31 #include <gtk/gtkcombobox.h>
32 #include <gtk/gtkentry.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtklabel.h>
35 #include <gtk/gtkliststore.h>
36 #include <gtk/gtkscrolledwindow.h>
37 #include <gtk/gtkspinbutton.h>
38 #include <gtk/gtkstock.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtktreeselection.h>
41 #include <gtk/gtkvbox.h>
42 #include <gtk/gtkvseparator.h>
43 #include <gdk/gdkkeysyms.h>
45 #include "../common/xchat.h"
46 #include "../common/xchatc.h"
47 #include "../common/cfgfiles.h"
48 #include "../common/outbound.h"
49 #include "../common/util.h"
50 #include "../common/fe.h"
51 #include "../common/server.h"
56 #include "custom-list.h"
68 typedef struct /* this is now in custom-list.h */
74 /* channel string lives beyond "users" */
75 #define GET_CHAN(row) (((char *)row)+sizeof(chanlistrow))
80 #define GET_MODEL(xserv) (gtk_tree_view_get_model(GTK_TREE_VIEW(xserv->gui->chanlist_list)))
84 chanlist_match (server
*serv
, const char *str
)
86 switch (serv
->gui
->chanlist_search_type
)
89 return match (GTK_ENTRY (serv
->gui
->chanlist_wild
)->text
, str
);
91 if (!serv
->gui
->have_regex
)
93 /* regex returns 0 if it's a match: */
94 return !regexec (&serv
->gui
->chanlist_match_regex
, str
, 1, NULL
, REG_NOTBOL
);
95 default: /* case 0: */
96 return nocasestrstr (str
, GTK_ENTRY (serv
->gui
->chanlist_wild
)->text
) ? 1 : 0;
101 * Updates the caption to reflect the number of users and channels
104 chanlist_update_caption (server
*serv
)
108 snprintf (tbuf
, sizeof tbuf
,
109 _("Displaying %d/%d users on %d/%d channels."),
110 serv
->gui
->chanlist_users_shown_count
,
111 serv
->gui
->chanlist_users_found_count
,
112 serv
->gui
->chanlist_channels_shown_count
,
113 serv
->gui
->chanlist_channels_found_count
);
115 gtk_label_set_text (GTK_LABEL (serv
->gui
->chanlist_label
), tbuf
);
116 serv
->gui
->chanlist_caption_is_stale
= FALSE
;
120 chanlist_update_buttons (server
*serv
)
122 if (serv
->gui
->chanlist_channels_shown_count
)
124 gtk_widget_set_sensitive (serv
->gui
->chanlist_join
, TRUE
);
125 gtk_widget_set_sensitive (serv
->gui
->chanlist_savelist
, TRUE
);
129 gtk_widget_set_sensitive (serv
->gui
->chanlist_join
, FALSE
);
130 gtk_widget_set_sensitive (serv
->gui
->chanlist_savelist
, FALSE
);
135 chanlist_reset_counters (server
*serv
)
137 serv
->gui
->chanlist_users_found_count
= 0;
138 serv
->gui
->chanlist_users_shown_count
= 0;
139 serv
->gui
->chanlist_channels_found_count
= 0;
140 serv
->gui
->chanlist_channels_shown_count
= 0;
142 chanlist_update_caption (serv
);
143 chanlist_update_buttons (serv
);
146 /* free up our entire linked list and all the nodes */
149 chanlist_data_free (server
*serv
)
154 if (serv
->gui
->chanlist_data_stored_rows
)
156 for (rows
= serv
->gui
->chanlist_data_stored_rows
; rows
!= NULL
;
160 g_free (data
->topic
);
161 g_free (data
->collation_key
);
165 g_slist_free (serv
->gui
->chanlist_data_stored_rows
);
166 serv
->gui
->chanlist_data_stored_rows
= NULL
;
169 g_slist_free (serv
->gui
->chanlist_pending_rows
);
170 serv
->gui
->chanlist_pending_rows
= NULL
;
173 /* add any rows we received from the server in the last 0.25s to the GUI */
176 chanlist_flush_pending (server
*serv
)
178 GSList
*list
= serv
->gui
->chanlist_pending_rows
;
184 if (serv
->gui
->chanlist_caption_is_stale
)
185 chanlist_update_caption (serv
);
188 model
= GET_MODEL (serv
);
193 custom_list_append (CUSTOM_LIST (model
), row
);
197 g_slist_free (serv
->gui
->chanlist_pending_rows
);
198 serv
->gui
->chanlist_pending_rows
= NULL
;
199 chanlist_update_caption (serv
);
203 chanlist_timeout (server
*serv
)
205 chanlist_flush_pending (serv
);
210 * Places a data row into the gui GtkTreeView, if and only if the row matches
211 * the user and regex/search requirements.
214 chanlist_place_row_in_gui (server
*serv
, chanlistrow
*next_row
, gboolean force
)
218 /* First, update the 'found' counter values */
219 serv
->gui
->chanlist_users_found_count
+= next_row
->users
;
220 serv
->gui
->chanlist_channels_found_count
++;
222 if (serv
->gui
->chanlist_channels_shown_count
== 1)
223 /* join & save buttons become live */
224 chanlist_update_buttons (serv
);
226 if (next_row
->users
< serv
->gui
->chanlist_minusers
)
228 serv
->gui
->chanlist_caption_is_stale
= TRUE
;
232 if (next_row
->users
> serv
->gui
->chanlist_maxusers
233 && serv
->gui
->chanlist_maxusers
> 0)
235 serv
->gui
->chanlist_caption_is_stale
= TRUE
;
239 if (GTK_ENTRY (serv
->gui
->chanlist_wild
)->text
[0])
241 /* Check what the user wants to match. If both buttons or _neither_
242 * button is checked, look for match in both by default.
244 if (serv
->gui
->chanlist_match_wants_channel
==
245 serv
->gui
->chanlist_match_wants_topic
)
247 if (!chanlist_match (serv
, GET_CHAN (next_row
))
248 && !chanlist_match (serv
, next_row
->topic
))
250 serv
->gui
->chanlist_caption_is_stale
= TRUE
;
255 else if (serv
->gui
->chanlist_match_wants_channel
)
257 if (!chanlist_match (serv
, GET_CHAN (next_row
)))
259 serv
->gui
->chanlist_caption_is_stale
= TRUE
;
264 else if (serv
->gui
->chanlist_match_wants_topic
)
266 if (!chanlist_match (serv
, next_row
->topic
))
268 serv
->gui
->chanlist_caption_is_stale
= TRUE
;
274 if (force
|| serv
->gui
->chanlist_channels_shown_count
< 20)
276 model
= GET_MODEL (serv
);
277 /* makes it appear fast :) */
278 custom_list_append (CUSTOM_LIST (model
), next_row
);
279 chanlist_update_caption (serv
);
282 /* add it to GUI at the next update interval */
283 serv
->gui
->chanlist_pending_rows
= g_slist_prepend (serv
->gui
->chanlist_pending_rows
, next_row
);
285 /* Update the 'shown' counter values */
286 serv
->gui
->chanlist_users_shown_count
+= next_row
->users
;
287 serv
->gui
->chanlist_channels_shown_count
++;
290 /* Performs the LIST download from the IRC server. */
293 chanlist_do_refresh (server
*serv
)
295 if (serv
->gui
->chanlist_flash_tag
)
297 g_source_remove (serv
->gui
->chanlist_flash_tag
);
298 serv
->gui
->chanlist_flash_tag
= 0;
301 if (!serv
->connected
)
303 fe_message (_("Not connected."), FE_MSG_ERROR
);
307 custom_list_clear ((CustomList
*)GET_MODEL (serv
));
308 gtk_widget_set_sensitive (serv
->gui
->chanlist_refresh
, FALSE
);
310 chanlist_data_free (serv
);
311 chanlist_reset_counters (serv
);
313 /* can we request a list with minusers arg? */
314 if (serv
->use_listargs
)
316 /* yes - it will download faster */
317 serv
->p_list_channels (serv
, "", serv
->gui
->chanlist_minusers
);
318 /* don't allow the spin button below this value from now on */
319 serv
->gui
->chanlist_minusers_downloaded
= serv
->gui
->chanlist_minusers
;
323 /* download all, filter minusers locally only */
324 serv
->p_list_channels (serv
, "", 1);
325 serv
->gui
->chanlist_minusers_downloaded
= 1;
328 /* gtk_spin_button_set_range ((GtkSpinButton *)serv->gui->chanlist_min_spin,
329 serv->gui->chanlist_minusers_downloaded, 999999);*/
333 chanlist_refresh (GtkWidget
* wid
, server
*serv
)
335 chanlist_do_refresh (serv
);
339 * Fills the gui GtkTreeView with stored items from the GSList.
342 chanlist_build_gui_list (server
*serv
)
346 /* first check if the list is present */
347 if (serv
->gui
->chanlist_data_stored_rows
== NULL
)
349 /* start a download */
350 chanlist_do_refresh (serv
);
354 custom_list_clear ((CustomList
*)GET_MODEL (serv
));
356 /* discard pending rows FIXME: free the structs? */
357 g_slist_free (serv
->gui
->chanlist_pending_rows
);
358 serv
->gui
->chanlist_pending_rows
= NULL
;
360 /* Reset the counters */
361 chanlist_reset_counters (serv
);
363 /* Refill the list */
364 for (rows
= serv
->gui
->chanlist_data_stored_rows
; rows
!= NULL
;
367 chanlist_place_row_in_gui (serv
, rows
->data
, TRUE
);
370 custom_list_resort ((CustomList
*)GET_MODEL (serv
));
374 * Accepts incoming channel data from inbound.c, allocates new space for a
375 * chanlistrow, adds it to our linked list and calls chanlist_place_row_in_gui.
378 fe_add_chan_list (server
*serv
, char *chan
, char *users
, char *topic
)
380 chanlistrow
*next_row
;
381 int len
= strlen (chan
) + 1;
383 /* we allocate the struct and channel string in one go */
384 next_row
= malloc (sizeof (chanlistrow
) + len
);
385 memcpy (((char *)next_row
) + sizeof (chanlistrow
), chan
, len
);
386 next_row
->topic
= strip_color (topic
, -1, STRIP_ALL
);
387 next_row
->collation_key
= g_utf8_collate_key (chan
, len
-1);
388 if (!(next_row
->collation_key
))
389 next_row
->collation_key
= g_strdup (chan
);
390 next_row
->users
= atoi (users
);
392 /* add this row to the data */
393 serv
->gui
->chanlist_data_stored_rows
=
394 g_slist_prepend (serv
->gui
->chanlist_data_stored_rows
, next_row
);
396 /* _possibly_ add the row to the gui */
397 chanlist_place_row_in_gui (serv
, next_row
, FALSE
);
401 fe_chan_list_end (server
*serv
)
403 /* download complete */
404 chanlist_flush_pending (serv
);
405 gtk_widget_set_sensitive (serv
->gui
->chanlist_refresh
, TRUE
);
406 custom_list_resort ((CustomList
*)GET_MODEL (serv
));
410 chanlist_search_pressed (GtkButton
* button
, server
*serv
)
412 chanlist_build_gui_list (serv
);
416 chanlist_find_cb (GtkWidget
* wid
, server
*serv
)
418 /* recompile the regular expression. */
419 if (serv
->gui
->have_regex
)
421 serv
->gui
->have_regex
= 0;
422 regfree (&serv
->gui
->chanlist_match_regex
);
425 if (regcomp (&serv
->gui
->chanlist_match_regex
, GTK_ENTRY (wid
)->text
,
426 REG_ICASE
| REG_EXTENDED
| REG_NOSUB
) == 0)
427 serv
->gui
->have_regex
= 1;
431 chanlist_match_channel_button_toggled (GtkWidget
* wid
, server
*serv
)
433 serv
->gui
->chanlist_match_wants_channel
= GTK_TOGGLE_BUTTON (wid
)->active
;
437 chanlist_match_topic_button_toggled (GtkWidget
* wid
, server
*serv
)
439 serv
->gui
->chanlist_match_wants_topic
= GTK_TOGGLE_BUTTON (wid
)->active
;
443 chanlist_get_selected (server
*serv
, gboolean get_topic
)
446 GtkTreeSelection
*sel
= gtk_tree_view_get_selection (GTK_TREE_VIEW (serv
->gui
->chanlist_list
));
450 if (!gtk_tree_selection_get_selected (sel
, &model
, &iter
))
453 gtk_tree_model_get (model
, &iter
, get_topic
? COL_TOPIC
: COL_CHANNEL
, &chan
, -1);
458 chanlist_join (GtkWidget
* wid
, server
*serv
)
460 char tbuf
[CHANLEN
+ 6];
461 char *chan
= chanlist_get_selected (serv
, FALSE
);
464 if (serv
->connected
&& (strcmp (chan
, "*") != 0))
466 snprintf (tbuf
, sizeof (tbuf
), "join %s", chan
);
467 handle_command (serv
->server_session
, tbuf
, FALSE
);
475 chanlist_filereq_done (server
*serv
, char *file
)
481 GtkTreeModel
*model
= GET_MODEL (serv
);
487 fh
= xchat_open_file (file
, O_TRUNC
| O_WRONLY
| O_CREAT
, 0600,
488 XOF_DOMODE
| XOF_FULLPATH
);
492 snprintf (buf
, sizeof buf
, "XChat Channel List: %s - %s\n",
493 serv
->servername
, ctime (&t
));
494 write (fh
, buf
, strlen (buf
));
496 if (gtk_tree_model_get_iter_first (model
, &iter
))
500 gtk_tree_model_get (model
, &iter
,
503 COL_TOPIC
, &topic
, -1);
504 snprintf (buf
, sizeof buf
, "%-16s %-5d%s\n", chan
, users
, topic
);
507 write (fh
, buf
, strlen (buf
));
509 while (gtk_tree_model_iter_next (model
, &iter
));
516 chanlist_save (GtkWidget
* wid
, server
*serv
)
519 GtkTreeModel
*model
= GET_MODEL (serv
);
521 if (gtk_tree_model_get_iter_first (model
, &iter
))
522 gtkutil_file_req (_("Select an output filename"), chanlist_filereq_done
,
523 serv
, NULL
, FRF_WRITE
);
527 chanlist_flash (server
*serv
)
529 if (serv
->gui
->chanlist_refresh
->state
!= GTK_STATE_ACTIVE
)
530 gtk_widget_set_state (serv
->gui
->chanlist_refresh
, GTK_STATE_ACTIVE
);
532 gtk_widget_set_state (serv
->gui
->chanlist_refresh
, GTK_STATE_PRELIGHT
);
538 chanlist_minusers (GtkSpinButton
*wid
, server
*serv
)
540 serv
->gui
->chanlist_minusers
= gtk_spin_button_get_value_as_int (wid
);
542 if (serv
->gui
->chanlist_minusers
< serv
->gui
->chanlist_minusers_downloaded
)
544 if (serv
->gui
->chanlist_flash_tag
== 0)
545 serv
->gui
->chanlist_flash_tag
= g_timeout_add (500, (GSourceFunc
)chanlist_flash
, serv
);
549 if (serv
->gui
->chanlist_flash_tag
)
551 g_source_remove (serv
->gui
->chanlist_flash_tag
);
552 serv
->gui
->chanlist_flash_tag
= 0;
558 chanlist_maxusers (GtkSpinButton
*wid
, server
*serv
)
560 serv
->gui
->chanlist_maxusers
= gtk_spin_button_get_value_as_int (wid
);
564 chanlist_dclick_cb (GtkTreeView
*view
, GtkTreePath
*path
,
565 GtkTreeViewColumn
*column
, gpointer data
)
567 chanlist_join (0, (server
*) data
); /* double clicked a row */
571 chanlist_menu_destroy (GtkWidget
*menu
, gpointer userdata
)
573 gtk_widget_destroy (menu
);
574 g_object_unref (menu
);
578 chanlist_copychannel (GtkWidget
*item
, server
*serv
)
580 char *chan
= chanlist_get_selected (serv
, FALSE
);
583 gtkutil_copy_to_clipboard (item
, NULL
, chan
);
589 chanlist_copytopic (GtkWidget
*item
, server
*serv
)
591 char *topic
= chanlist_get_selected (serv
, TRUE
);
594 gtkutil_copy_to_clipboard (item
, NULL
, topic
);
600 chanlist_button_cb (GtkTreeView
*tree
, GdkEventButton
*event
, server
*serv
)
603 GtkTreeSelection
*sel
;
607 if (event
->button
!= 3)
610 if (!gtk_tree_view_get_path_at_pos (tree
, event
->x
, event
->y
, &path
, 0, 0, 0))
613 /* select what they right-clicked on */
614 sel
= gtk_tree_view_get_selection (tree
);
615 gtk_tree_selection_unselect_all (sel
);
616 gtk_tree_selection_select_path (sel
, path
);
617 gtk_tree_path_free (path
);
619 menu
= gtk_menu_new ();
621 gtk_menu_set_screen (GTK_MENU (menu
), gdk_drawable_get_screen (event
->window
));
623 g_object_ref_sink (menu
);
624 g_object_unref (menu
);
625 g_signal_connect (G_OBJECT (menu
), "selection-done",
626 G_CALLBACK (chanlist_menu_destroy
), NULL
);
627 mg_create_icon_item (_("_Join Channel"), GTK_STOCK_JUMP_TO
, menu
,
628 chanlist_join
, serv
);
629 mg_create_icon_item (_("_Copy Channel Name"), GTK_STOCK_COPY
, menu
,
630 chanlist_copychannel
, serv
);
631 mg_create_icon_item (_("Copy _Topic Text"), GTK_STOCK_COPY
, menu
,
632 chanlist_copytopic
, serv
);
634 chan
= chanlist_get_selected (serv
, FALSE
);
635 menu_addfavoritemenu (serv
, menu
, chan
);
638 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
644 chanlist_destroy_widget (GtkWidget
*wid
, server
*serv
)
646 custom_list_clear ((CustomList
*)GET_MODEL (serv
));
647 chanlist_data_free (serv
);
649 if (serv
->gui
->chanlist_flash_tag
)
651 g_source_remove (serv
->gui
->chanlist_flash_tag
);
652 serv
->gui
->chanlist_flash_tag
= 0;
655 if (serv
->gui
->chanlist_tag
)
657 g_source_remove (serv
->gui
->chanlist_tag
);
658 serv
->gui
->chanlist_tag
= 0;
661 if (serv
->gui
->have_regex
)
663 regfree (&serv
->gui
->chanlist_match_regex
);
664 serv
->gui
->have_regex
= 0;
669 chanlist_closegui (GtkWidget
*wid
, server
*serv
)
671 if (is_server (serv
))
672 serv
->gui
->chanlist_window
= NULL
;
676 chanlist_add_column (GtkWidget
*tree
, int textcol
, int size
, char *title
, gboolean right_justified
)
678 GtkCellRenderer
*renderer
;
679 GtkTreeViewColumn
*col
;
681 renderer
= gtk_cell_renderer_text_new ();
683 g_object_set (G_OBJECT (renderer
), "xalign", (gfloat
) 1.0, NULL
);
684 g_object_set (G_OBJECT (renderer
), "ypad", (gint
) 0, NULL
);
685 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree
), -1, title
,
686 renderer
, "text", textcol
, NULL
);
687 gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer
), 1);
689 col
= gtk_tree_view_get_column (GTK_TREE_VIEW (tree
), textcol
);
690 gtk_tree_view_column_set_sort_column_id (col
, textcol
);
691 gtk_tree_view_column_set_resizable (col
, TRUE
);
692 if (textcol
!= COL_TOPIC
)
694 gtk_tree_view_column_set_sizing (col
, GTK_TREE_VIEW_COLUMN_FIXED
);
695 gtk_tree_view_column_set_fixed_width (col
, size
);
700 chanlist_combo_cb (GtkWidget
*combo
, server
*serv
)
702 serv
->gui
->chanlist_search_type
= gtk_combo_box_get_active (GTK_COMBO_BOX (combo
));
706 chanlist_opengui (server
*serv
, int do_refresh
)
708 GtkWidget
*vbox
, *hbox
, *table
, *wid
, *view
;
712 if (serv
->gui
->chanlist_window
)
714 mg_bring_tofront (serv
->gui
->chanlist_window
);
718 snprintf (tbuf
, sizeof tbuf
, _("XChat: Channel List (%s)"),
719 server_get_network (serv
, TRUE
));
721 serv
->gui
->chanlist_pending_rows
= NULL
;
722 serv
->gui
->chanlist_tag
= 0;
723 serv
->gui
->chanlist_flash_tag
= 0;
724 serv
->gui
->chanlist_data_stored_rows
= NULL
;
726 if (!serv
->gui
->chanlist_minusers
)
727 serv
->gui
->chanlist_minusers
= 5;
729 if (!serv
->gui
->chanlist_maxusers
)
730 serv
->gui
->chanlist_maxusers
= 9999;
732 serv
->gui
->chanlist_window
=
733 mg_create_generic_tab ("ChanList", tbuf
, FALSE
, TRUE
, chanlist_closegui
,
734 serv
, 640, 480, &vbox
, serv
);
736 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 6);
737 gtk_box_set_spacing (GTK_BOX (vbox
), 12);
739 /* make a label to store the user/channel info */
740 wid
= gtk_label_new (NULL
);
741 gtk_box_pack_start (GTK_BOX (vbox
), wid
, 0, 0, 0);
742 gtk_widget_show (wid
);
743 serv
->gui
->chanlist_label
= wid
;
745 /* ============================================================= */
747 store
= (GtkListStore
*) custom_list_new();
748 view
= gtkutil_treeview_new (vbox
, GTK_TREE_MODEL (store
), NULL
, -1);
749 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view
->parent
),
751 serv
->gui
->chanlist_list
= view
;
753 g_signal_connect (G_OBJECT (view
), "row_activated",
754 G_CALLBACK (chanlist_dclick_cb
), serv
);
755 g_signal_connect (G_OBJECT (view
), "button-press-event",
756 G_CALLBACK (chanlist_button_cb
), serv
);
758 chanlist_add_column (view
, COL_CHANNEL
, 96, _("Channel"), FALSE
);
759 chanlist_add_column (view
, COL_USERS
, 50, _("Users"), TRUE
);
760 chanlist_add_column (view
, COL_TOPIC
, 50, _("Topic"), FALSE
);
761 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view
), TRUE
);
762 /* this is a speed up, but no horizontal scrollbar :( */
763 /*gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);*/
764 gtk_widget_show (view
);
766 /* ============================================================= */
768 table
= gtk_table_new (4, 4, FALSE
);
769 gtk_table_set_col_spacings (GTK_TABLE (table
), 12);
770 gtk_table_set_row_spacings (GTK_TABLE (table
), 3);
771 gtk_box_pack_start (GTK_BOX (vbox
), table
, 0, 1, 0);
772 gtk_widget_show (table
);
774 wid
= gtkutil_button (NULL
, GTK_STOCK_FIND
, 0, chanlist_search_pressed
, serv
,
776 serv
->gui
->chanlist_search
= wid
;
777 gtk_table_attach (GTK_TABLE (table
), wid
, 3, 4, 3, 4,
778 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
780 wid
= gtkutil_button (NULL
, GTK_STOCK_REFRESH
, 0, chanlist_refresh
, serv
,
781 _("_Download List"));
782 serv
->gui
->chanlist_refresh
= wid
;
783 gtk_table_attach (GTK_TABLE (table
), wid
, 3, 4, 2, 3,
784 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
786 wid
= gtkutil_button (NULL
, GTK_STOCK_SAVE_AS
, 0, chanlist_save
, serv
,
788 serv
->gui
->chanlist_savelist
= wid
;
789 gtk_table_attach (GTK_TABLE (table
), wid
, 3, 4, 1, 2,
790 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
792 wid
= gtkutil_button (NULL
, GTK_STOCK_JUMP_TO
, 0, chanlist_join
, serv
,
794 serv
->gui
->chanlist_join
= wid
;
795 gtk_table_attach (GTK_TABLE (table
), wid
, 3, 4, 0, 1,
796 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
798 /* ============================================================= */
800 wid
= gtk_label_new (_("Show only:"));
801 gtk_misc_set_alignment (GTK_MISC (wid
), 0, 0.5);
802 gtk_table_attach (GTK_TABLE (table
), wid
, 0, 1, 3, 4,
803 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
804 gtk_widget_show (wid
);
806 hbox
= gtk_hbox_new (0, 0);
807 gtk_box_set_spacing (GTK_BOX (hbox
), 9);
808 gtk_table_attach (GTK_TABLE (table
), hbox
, 1, 2, 3, 4,
809 GTK_FILL
, GTK_FILL
, 0, 0);
810 gtk_widget_show (hbox
);
812 wid
= gtk_label_new (_("channels with"));
813 gtk_box_pack_start (GTK_BOX (hbox
), wid
, 0, 0, 0);
814 gtk_widget_show (wid
);
816 wid
= gtk_spin_button_new_with_range (1, 999999, 1);
817 gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid
),
818 serv
->gui
->chanlist_minusers
);
819 g_signal_connect (G_OBJECT (wid
), "value_changed",
820 G_CALLBACK (chanlist_minusers
), serv
);
821 gtk_box_pack_start (GTK_BOX (hbox
), wid
, 0, 0, 0);
822 gtk_widget_show (wid
);
823 serv
->gui
->chanlist_min_spin
= wid
;
825 wid
= gtk_label_new (_("to"));
826 gtk_box_pack_start (GTK_BOX (hbox
), wid
, 0, 0, 0);
827 gtk_widget_show (wid
);
829 wid
= gtk_spin_button_new_with_range (1, 999999, 1);
830 gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid
),
831 serv
->gui
->chanlist_maxusers
);
832 g_signal_connect (G_OBJECT (wid
), "value_changed",
833 G_CALLBACK (chanlist_maxusers
), serv
);
834 gtk_box_pack_start (GTK_BOX (hbox
), wid
, 0, 0, 0);
835 gtk_widget_show (wid
);
837 wid
= gtk_label_new (_("users."));
838 gtk_box_pack_start (GTK_BOX (hbox
), wid
, 0, 0, 0);
839 gtk_widget_show (wid
);
841 /* ============================================================= */
843 wid
= gtk_label_new (_("Look in:"));
844 gtk_misc_set_alignment (GTK_MISC (wid
), 0, 0.5);
845 gtk_table_attach (GTK_TABLE (table
), wid
, 0, 1, 2, 3,
846 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
847 gtk_widget_show (wid
);
849 hbox
= gtk_hbox_new (0, 0);
850 gtk_box_set_spacing (GTK_BOX (hbox
), 12);
851 gtk_table_attach (GTK_TABLE (table
), hbox
, 1, 2, 2, 3,
852 GTK_FILL
, GTK_FILL
, 0, 0);
853 gtk_widget_show (hbox
);
855 wid
= gtk_check_button_new_with_label (_("Channel name"));
856 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid
), TRUE
);
857 gtk_signal_connect (GTK_OBJECT (wid
), "toggled",
859 (chanlist_match_channel_button_toggled
), serv
);
860 gtk_box_pack_start (GTK_BOX (hbox
), wid
, 0, 0, 0);
861 gtk_widget_show (wid
);
863 wid
= gtk_check_button_new_with_label (_("Topic"));
864 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid
), TRUE
);
865 gtk_signal_connect (GTK_OBJECT (wid
), "toggled",
866 GTK_SIGNAL_FUNC (chanlist_match_topic_button_toggled
),
868 gtk_box_pack_start (GTK_BOX (hbox
), wid
, 0, 0, 0);
869 gtk_widget_show (wid
);
871 serv
->gui
->chanlist_match_wants_channel
= 1;
872 serv
->gui
->chanlist_match_wants_topic
= 1;
874 /* ============================================================= */
876 wid
= gtk_label_new (_("Search type:"));
877 gtk_misc_set_alignment (GTK_MISC (wid
), 0, 0.5);
878 gtk_table_attach (GTK_TABLE (table
), wid
, 0, 1, 1, 2,
879 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
880 gtk_widget_show (wid
);
882 wid
= gtk_combo_box_new_text ();
883 gtk_combo_box_append_text (GTK_COMBO_BOX (wid
), _("Simple Search"));
884 gtk_combo_box_append_text (GTK_COMBO_BOX (wid
), _("Pattern Match (Wildcards)"));
885 gtk_combo_box_append_text (GTK_COMBO_BOX (wid
), _("Regular Expression"));
886 gtk_combo_box_set_active (GTK_COMBO_BOX (wid
), serv
->gui
->chanlist_search_type
);
887 gtk_table_attach (GTK_TABLE (table
), wid
, 1, 2, 1, 2,
888 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
889 g_signal_connect (G_OBJECT (wid
), "changed",
890 G_CALLBACK (chanlist_combo_cb
), serv
);
891 gtk_widget_show (wid
);
893 /* ============================================================= */
895 wid
= gtk_label_new (_("Find:"));
896 gtk_misc_set_alignment (GTK_MISC (wid
), 0, 0.5);
897 gtk_table_attach (GTK_TABLE (table
), wid
, 0, 1, 0, 1,
898 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
899 gtk_widget_show (wid
);
901 wid
= gtk_entry_new_with_max_length (255);
902 gtk_signal_connect (GTK_OBJECT (wid
), "changed",
903 GTK_SIGNAL_FUNC (chanlist_find_cb
), serv
);
904 gtk_signal_connect (GTK_OBJECT (wid
), "activate",
905 GTK_SIGNAL_FUNC (chanlist_search_pressed
),
907 gtk_table_attach (GTK_TABLE (table
), wid
, 1, 2, 0, 1,
908 GTK_EXPAND
| GTK_FILL
, 0, 0, 0);
909 gtk_widget_show (wid
);
910 serv
->gui
->chanlist_wild
= wid
;
912 chanlist_find_cb (wid
, serv
);
914 /* ============================================================= */
916 wid
= gtk_vseparator_new ();
917 gtk_table_attach (GTK_TABLE (table
), wid
, 2, 3, 0, 5,
918 GTK_SHRINK
| GTK_FILL
, GTK_SHRINK
| GTK_FILL
, 0, 0);
919 gtk_widget_show (wid
);
921 g_signal_connect (G_OBJECT (serv
->gui
->chanlist_window
), "destroy",
922 G_CALLBACK (chanlist_destroy_widget
), serv
);
924 /* reset the counters. */
925 chanlist_reset_counters (serv
);
927 serv
->gui
->chanlist_tag
= g_timeout_add (250, (GSourceFunc
)chanlist_timeout
, serv
);
930 chanlist_do_refresh (serv
);
932 chanlist_update_buttons (serv
);
933 gtk_widget_show (serv
->gui
->chanlist_window
);
934 gtk_widget_grab_focus (serv
->gui
->chanlist_refresh
);