1 (* Copyright 2004 b8_bavard, INRIA *)
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 (* The rooms window of MLgui *)
32 module M
= GuiMessages
39 let (!!) = Options.(!!)
40 let (=:=) = Options.(=:=)
41 let (<:>) = GuiTools.(<:>)
43 let verbose = O.gtk_verbose_rooms
46 Printf2.lprintf ("GuiRooms: " ^^ fmt
)
48 (*************************************************************************)
52 (*************************************************************************)
55 try int_of_string key
with _
-> raise Not_found
57 (*************************************************************************)
61 (*************************************************************************)
65 let num = room_num key
in
66 Hashtbl.find
G.rooms
num
67 with _
-> raise Not_found
69 (*************************************************************************)
73 (*************************************************************************)
75 let keys_to_rooms keys
=
79 let s = room_of_key k
in
84 (*************************************************************************)
88 (*************************************************************************)
90 let room_key room_num =
91 Printf.sprintf
"%d" room_num
93 (*************************************************************************)
97 (*************************************************************************)
99 let (dialogs
: (int * GuiTemplates.chat_buffer
) list
ref) = ref []
101 (*************************************************************************)
103 (* Global variables *)
105 (*************************************************************************)
107 let (current_room
: int option ref) = ref None
108 let (chat_box
: GuiTemplates.chat_view
option ref) = ref None
110 let (room_label
: GMisc.label
option ref) = ref None
111 let (user_label
: GMisc.label
option ref) = ref None
113 let nrooms_opened = ref 0
114 let (view_context
: GPango.context
option ref) = ref None
116 (*************************************************************************)
120 (*************************************************************************)
122 module RoomUsers
= GuiUsers.UserList
(struct
124 let columns = O.rooms_users_columns
125 let view_context = view_context
126 let module_name = "RoomUsers"
130 let userstore = new RoomUsers.g_user
()
132 module Rooms
= GuiTemplates.Gview
(struct
134 module Column
= GuiColumns.Room
136 type item
= room_info
138 let columns = O.rooms_columns
139 let get_key = (fun r
-> room_key r
.room_num)
140 let module_name = "Rooms"
145 let room_cols = new GTree.column_list
in
146 let room_network_str = room_cols#add
Gobject.Data.string in
147 let room_network_pixb = room_cols#add
Gobject.Data.gobject_option
in
148 let room_name = room_cols#add
Gobject.Data.string in
149 let room_name_pixb = room_cols#add
Gobject.Data.gobject_option
in
150 let room_state_str = room_cols#add
Gobject.Data.string in
151 let room_nusers = room_cols#add
Gobject.Data.int in
153 inherit Rooms.g_list
room_cols
155 (*************************************************************************)
159 (*************************************************************************)
161 method from_item row ro
=
162 store#set ~row ~column
:room_network_str (Mi.network_name ro
.room_network
);
163 store#set ~row ~column
:room_network_pixb (Mi.network_pixb ro
.room_network ~size
:A.SMALL
());
164 store#set ~row ~column
:room_name (U.utf8_of ro
.room_name);
165 store#set ~row ~column
:room_name_pixb (Mi.room_state_to_icon ro
.room_state ~size
:A.SMALL
);
166 store#set ~row ~column
:room_state_str (Mi.room_state_to_string ro
.room_state
);
167 store#set ~row ~column
:room_nusers ro
.room_nusers
169 (*************************************************************************)
173 (*************************************************************************)
175 method from_new_item row ro ro_new
=
176 if ro
.room_state
<> ro_new
.room_state
178 store#set ~row ~column
:room_name_pixb (Mi.room_state_to_icon ro_new
.room_state ~size
:A.SMALL
);
179 store#set ~row ~column
:room_state_str (Mi.room_state_to_string ro_new
.room_state
);
181 if ro
.room_nusers <> ro_new
.room_nusers
183 store#set ~row ~column
:room_nusers ro_new
.room_nusers
186 (*************************************************************************)
190 (*************************************************************************)
192 method content col c
=
193 let autosize = match col#sizing
with `AUTOSIZE
-> true | _
-> false in
197 if !!O.gtk_look_use_icons
199 let renderer = GTree.cell_renderer_pixbuf
[`XALIGN
0.;`XPAD
4] in
200 col#pack ~expand
:false renderer;
201 col#add_attribute
renderer "pixbuf" room_name_pixb
203 let renderer = GTree.cell_renderer_text
[`XALIGN
0.] in
204 col#pack ~expand
:false renderer;
206 then col#add_attribute
renderer "text" room_name
207 else col#set_cell_data_func
renderer
209 match !view_context with
210 Some context
when col#width
> 0 ->
213 if !!O.gtk_look_use_icons
214 then (col#
width - 4 - !!O.gtk_look_lists_icon_size
) - 4 * !G.char_width
215 else col#
width - 4 * !G.char_width
217 let name = model#get ~row ~column
:room_name in
218 let s = GuiTools.fit_string_to_pixels
name ~context ~pixels
:width in
219 renderer#set_properties
[ `TEXT
s ]
221 | _
-> renderer#set_properties
[ `TEXT
"" ]
227 let renderer = GTree.cell_renderer_text
[`XALIGN
0.] in
229 col#add_attribute
renderer "text" room_nusers
234 let renderer = GTree.cell_renderer_text
[`XALIGN
0.] in
236 col#add_attribute
renderer "text" room_state_str
239 | Col_room_network
->
241 if !!O.gtk_look_use_icons
243 let renderer = GTree.cell_renderer_pixbuf
[`XALIGN
0.] in
245 col#add_attribute
renderer "pixbuf" room_network_pixb
247 let renderer = GTree.cell_renderer_text
[`XALIGN
0.] in
249 col#add_attribute
renderer "text" room_network_str
253 (*************************************************************************)
257 (*************************************************************************)
259 method sort_items c k1 k2
=
261 let ro1 = room_of_key k1
in
262 let ro2 = room_of_key k2
in
264 Col_room_name
-> compare
(String.lowercase
ro1.room_name) (String.lowercase
ro2.room_name)
265 | Col_room_nusers
-> compare
ro1.room_nusers ro2.room_nusers
266 | Col_room_state
-> compare
ro1.room_state
ro2.room_state
267 | Col_room_network
-> compare
ro1.room_network
ro2.room_network
270 (*************************************************************************)
272 (* force_update_icons *)
274 (*************************************************************************)
276 method force_update_icons
() =
278 let ro = room_of_key k
in
279 store#set ~row ~column
:room_network_pixb (Mi.network_pixb
ro.room_network ~size
:A.SMALL
());
280 store#set ~row ~column
:room_name_pixb (Mi.room_state_to_icon
ro.room_state ~size
:A.SMALL
);
284 let row = self#find_row k
in
285 Gaux.may ~
f:(f k
) row
287 ) (self#all_items
())
291 let roomstore = new g_room
()
294 (*************************************************************************)
296 (* update_rooms_label *)
298 (*************************************************************************)
300 let update_rooms_label () =
301 match !room_label
with
305 create_default_bold_markup
306 (Printf.sprintf
"%s (%d / %d)" !M.rT_lb_rooms
!nrooms_opened roomstore#nitems
)
308 label#set_label
markup
312 (*************************************************************************)
314 (* update_users_label *)
316 (*************************************************************************)
318 let update_users_label () =
319 match !user_label
with
323 create_default_bold_markup
324 (Printf.sprintf
"%s (%d)" !M.rT_lb_users
userstore#nitems
)
326 label#set_label
markup
330 (*************************************************************************)
332 (* message to the core *)
334 (*************************************************************************)
336 let close_open_room sel
() =
337 let l = keys_to_rooms sel
in
339 match ro.room_state
with
340 RoomOpened
-> GuiCom.send
(SetRoomState
(ro.room_num, RoomClosed
))
341 | _
-> GuiCom.send
(SetRoomState
(ro.room_num, RoomOpened
))
344 let on_entry_return num s =
345 GuiCom.send
(SendMessage
(num, PublicMessage
(0, s)))
347 let get_user_info user_num
=
348 GuiCom.send
(GetUser_info user_num
)
350 (*************************************************************************)
354 (*************************************************************************)
361 `I
(!M.rT_me_close_open_room
, close_open_room sel
) ;
364 (*************************************************************************)
368 (*************************************************************************)
370 let on_select_room sel
=
373 update_users_label ();
374 (if !!verbose then lprintf'
"Searching box for chats\n");
377 Some w
-> (w#clear
(); w
)
381 [] -> (if !!verbose then lprintf'
"No room selected\n")
385 let ro = room_of_key k
in
386 current_room
:= Some
ro.room_num;
387 match ro.room_state
with
390 List.iter
(fun user_num
->
392 let u = Hashtbl.find
G.users user_num
in
393 userstore#add_item
u ~
f:update_users_label ();
394 with _
-> get_user_info user_num
397 let chat_buf = List.assoc
ro.room_num !dialogs
in
398 box#set_buffer
chat_buf
399 with _
-> (if !!verbose then lprintf'
"No chat dialog availabale\n")
401 | _
-> (if !!verbose then lprintf'
"room_users empty\n")
404 with _
-> (if !!verbose then lprintf'
"No chat_box found\n")
406 (*************************************************************************)
408 (* on_double_click_room *)
410 (*************************************************************************)
412 let on_double_click_room k
=
413 close_open_room [k
] ()
415 (*************************************************************************)
419 (*************************************************************************)
423 let ro = room_of_key k
in
424 not
(List.memq
ro.room_network
!G.networks_filtered
)
427 (*************************************************************************)
429 (* Templates initialization *)
431 (*************************************************************************)
434 roomstore#set_filter
filter_room
436 (*************************************************************************)
440 (*************************************************************************)
443 List.iter
(fun (_, chat_buf) ->
449 | Some
box -> box#
clear ()
452 current_room
:= None
;
456 update_rooms_label ();
457 update_users_label ()
459 (*************************************************************************)
461 (* message from the core *)
463 (*************************************************************************)
465 let hashtbl_rooms_update ro ro_new
=
466 ro.room_state
<- ro_new
.room_state
;
467 ro.room_users
<- ro_new
.room_users
;
468 ro.room_messages
<- ro_new
.room_messages
;
469 ro.room_nusers <- ro_new
.room_nusers
471 let add_chat_to_room ro =
472 match ro.room_state
with
475 let chat_buf = GuiTemplates.chat_buffer ~on_entry
:(on_entry_return ro.room_num) () in
476 dialogs
:= (ro.room_num, chat_buf) :: !dialogs
;
478 update_rooms_label ()
483 let chat_buf = List.assoc
ro.room_num !dialogs
in
485 dialogs
:= List.remove_assoc
ro.room_num !dialogs
;
486 List.iter
(fun user_num
->
487 Hashtbl.remove
G.users user_num
489 let num = match !current_room
with Some n
-> n
| _ -> assert false in
490 let box = match !chat_box
with Some w
-> w
| _ -> assert false in
496 update_rooms_label ();
497 update_users_label ()
505 (if !!verbose then lprintf'
"Adding room %s num: %d\n" ro.room_name ro.room_num);
507 roomstore#add_item
ro ~
f:update_rooms_label ();
508 Hashtbl.add
G.rooms
ro.room_num ro
513 (if !!verbose then lprintf'
"Room_info of %s\n" r
.room_name);
514 let ro = Hashtbl.find
G.rooms r
.room_num in
515 let row = roomstore#find_row
(room_key r
.room_num) in
516 (* no need to keep ro.room_messages, it is stored in dialogs *)
517 let ro_new = {r
with room_users
= ro.room_users
} in
518 (if ro_new.room_state
<> ro.room_state
519 then add_chat_to_room ro_new);
520 Gaux.may ~
f:(fun r
-> roomstore#update_item r
ro ro_new) row;
521 hashtbl_rooms_update ro ro_new
524 let find_user_name user_num
=
526 let u = Hashtbl.find
G.users user_num
in
528 with _ -> raise Not_found
530 let message_from_server s =
531 let len = String.length
s in
538 let pos = String.index
s '
>'
in
539 let u = String.sub
s 1 (pos - 1) in
540 let mes = String.sub
s (pos + 1) (len - pos - 1) in
542 with _ -> (s, "From server", false)
544 | _ -> (s, "From server", false)
546 end else ("", "From server", false)
548 let add_room_message room_num msg
=
549 (if !!verbose then lprintf'
"Adding message to room %d\n" room_num);
551 let chat_buf = List.assoc
room_num !dialogs
in
552 let (mes, name, priv
) =
554 ServerMessage
s -> message_from_server s
555 | PublicMessage
(n
, s) -> (s, (find_user_name n
), false)
556 | PrivateMessage
(n
, s) -> (s, (find_user_name n
), true)
558 chat_buf#insert_text
mes name ~priv
();
559 (* no need to store [msg] in the record field room_messages, it is stored in dialogs *)
562 let remove_room_user room_num user_num
=
563 (if !!verbose then lprintf'
"Removing user to room %d\n" room_num);
565 let ro = Hashtbl.find
G.rooms
room_num in
566 let _row = roomstore#find_row
(room_key room_num) in
567 (if List.mem user_num
ro.room_users
568 then ro.room_users
<- List.filter
(fun n
-> n
<> user_num
) ro.room_users
);
570 match (!current_room
, ro.room_state
) with
571 (Some n
, RoomOpened
) when n
= room_num ->
574 let _u = Hashtbl.find
G.users user_num
in
575 userstore#remove_item
(GuiUsers.user_key user_num
);
576 update_users_label ();
581 Hashtbl.remove
G.users user_num
(* remove the user from G.users if it exists *)
584 (if !!verbose then lprintf'
"room not found in remove_user ... removing user %d\n" user_num
);
585 Hashtbl.remove
G.users user_num
(* Anyway remove the user if the room does'nt exist *)
588 let add_room_user room_num user_num
=
589 (if !!verbose then lprintf'
"Adding user to room %d\n" room_num);
591 let ro = Hashtbl.find
G.rooms
room_num in
592 let _row = roomstore#find_row
(room_key room_num) in
593 (if not
(List.mem user_num
ro.room_users
)
594 then ro.room_users
<- user_num
:: ro.room_users
);
595 match (!current_room
, ro.room_state
) with
596 (Some n
, RoomOpened
) when n
= room_num ->
599 let u = Hashtbl.find
G.users user_num
in
600 userstore#add_item
u ~
f:update_users_label ()
607 (if !!verbose then lprintf'
"room not found in add_user ... removing user %d\n" user_num
);
608 Hashtbl.remove
G.users user_num
(* remove the user if the room does'nt exist *)
611 let update_user_info u_new
=
612 match !current_room
with
616 let ro = Hashtbl.find
G.rooms
room_num in
617 if List.mem u_new
.user_num
ro.room_users
620 let u = Hashtbl.find
G.users u_new
.user_num
in
621 let row = userstore#find_row
(GuiUsers.user_key u_new
.user_num
) in
622 Gaux.may ~
f:(fun r
-> userstore#update_item r
u u_new
) row;
623 GuiUsers.hashtbl_users_update
u u_new
630 (*************************************************************************)
632 (* message from GuiNetwoks *)
634 (*************************************************************************)
636 let reset_rooms_filter () =
637 roomstore#refresh_filter
()
639 (*************************************************************************)
643 (*************************************************************************)
649 GPack.paned `HORIZONTAL
()
652 GPack.paned `HORIZONTAL
653 ~packing
:hpaned_rooms#add2
()
655 ignore
(hpaned_rooms#connect#destroy ~callback
:
657 view_context := None
;
659 current_room
:= None
;
665 GPack.vbox ~homogeneous
:false ~border_width
:6 ~spacing
:6
666 ~packing
:hpaned_rooms#add1
()
669 GPack.vbox ~homogeneous
:false ~border_width
:6 ~spacing
:6
670 ~packing
:hpaned_users#add1
()
673 GPack.vbox ~border_width
:6 ~spacing
:6
674 ~packing
:hpaned_users#add2
()
678 GBin.event_box ~packing
:(vbox_rooms#pack ~expand
:false ~fill
:true) ()
680 rooms_evbox#misc#modify_bg
[(`NORMAL
, (`NAME
"#AFAFF4"))];
682 GMisc.label ~xalign
:0. ~yalign
:0.
683 ~xpad
:3 ~ypad
:3 ~packing
:rooms_evbox#add
()
686 GBin.event_box ~packing
:(vbox_users#pack ~expand
:false ~fill
:true) ()
688 users_evbox#misc#modify_bg
[(`NORMAL
, (`NAME
"#AFAFF4"))];
690 GMisc.label ~xalign
:0. ~yalign
:0.
691 ~xpad
:3 ~ypad
:3 ~packing
:users_evbox#add
()
694 GBin.event_box ~packing
:(vbox_chat#pack ~expand
:false ~fill
:true) ()
696 chat_evbox#misc#modify_bg
[(`NORMAL
, (`NAME
"#AFAFF4"))];
697 let markup = GuiTools.create_default_bold_markup
!M.rT_lb_chat
in
699 GMisc.label ~xalign
:0. ~yalign
:0. ~
markup
700 ~xpad
:3 ~ypad
:3 ~packing
:chat_evbox#add
()
704 Rooms.treeview ~mode
:`MULTIPLE
705 ~packing
:(vbox_rooms#pack ~expand
:true ~fill
:true) ()
707 view_context := Some
roomview#view#misc#pango_context
;
708 roomview#set_model
roomstore#gmodel
;
709 roomview#set_menu
room_menu;
710 roomview#set_on_select
on_select_room;
711 roomview#set_on_double_click
on_double_click_room;
713 RoomUsers.treeview ~mode
:`MULTIPLE
714 ~packing
:(vbox_users#pack ~expand
:true ~fill
:true) ()
716 userview#set_model
userstore#gmodel
;
717 userview#set_menu
GuiUsers.user_menu
;
719 GuiTemplates.chat_view ~extended
:true ~my_name
:!G. client_name
720 ~packing
:(vbox_chat#pack ~expand
:true ~fill
:true) ()
723 GuiTools.set_hpaned
hpaned_rooms O.rooms_hpane_left
;
724 GuiTools.get_hpaned
hpaned_rooms O.rooms_hpane_left
;
725 GuiTools.set_hpaned
hpaned_users O.rooms_hpane2_left
;
726 GuiTools.get_hpaned
hpaned_users O.rooms_hpane2_left
;
728 chat_box
:= Some
chat_view;
730 rooms_label#set_use_markup
true;
731 room_label
:= Some
rooms_label;
732 update_rooms_label ();
734 users_label#set_use_markup
true;
735 user_label
:= Some
users_label;
736 update_users_label ();