From 893f15aeeec3897466bffe66eeb71ac651d22a23 Mon Sep 17 00:00:00 2001 From: Travis Shirk <travis@pobox.com> Date: Thu, 5 Jan 2006 05:51:28 +0000 Subject: [PATCH] Working on GroupchatControl --- data/iconsets/crystal/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/dcraven/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/gnome/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/gossip/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/gota/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/nuvola/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/simplebulb/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/stellar/16x16/muc_active.png | Bin 0 -> 852 bytes data/iconsets/sun/16x16/muc_active.png | Bin 0 -> 852 bytes src/chat_control.py | 18 +- src/common/contacts.py | 2 + src/gajim.py | 20 +- src/groupchat_control.py | 270 +++++++++++++++++- src/message_control.py | 3 - src/message_window.py | 12 +- src/roster_window.py | 14 +- 16 files changed, 293 insertions(+), 46 deletions(-) create mode 100644 data/iconsets/crystal/16x16/muc_active.png create mode 100644 data/iconsets/dcraven/16x16/muc_active.png create mode 100644 data/iconsets/gnome/16x16/muc_active.png create mode 100644 data/iconsets/gossip/16x16/muc_active.png create mode 100644 data/iconsets/gota/16x16/muc_active.png create mode 100644 data/iconsets/nuvola/16x16/muc_active.png create mode 100644 data/iconsets/simplebulb/16x16/muc_active.png create mode 100644 data/iconsets/stellar/16x16/muc_active.png create mode 100644 data/iconsets/sun/16x16/muc_active.png diff --git a/data/iconsets/crystal/16x16/muc_active.png b/data/iconsets/crystal/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/dcraven/16x16/muc_active.png b/data/iconsets/dcraven/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/gnome/16x16/muc_active.png b/data/iconsets/gnome/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/gossip/16x16/muc_active.png b/data/iconsets/gossip/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/gota/16x16/muc_active.png b/data/iconsets/gota/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/nuvola/16x16/muc_active.png b/data/iconsets/nuvola/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/simplebulb/16x16/muc_active.png b/data/iconsets/simplebulb/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/stellar/16x16/muc_active.png b/data/iconsets/stellar/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/data/iconsets/sun/16x16/muc_active.png b/data/iconsets/sun/16x16/muc_active.png new file mode 100644 index 0000000000000000000000000000000000000000..5984ee8e80abafb95b0e598476f72bae07178e7f GIT binary patch literal 852 zcmV-a1FQUrP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)e9B_3kYNE@y-AM0^vzS zK~y-)rITGqQ*ju^pR=7gw;gu0<xJOR(hSO3RuCf!!9Ix~Mo1B1(oGj#Bq3pi&_zfP z6-6Kw5d{TBNH={NB^o7BlqTZG)XjaI)jm8sJMHY_ob&HO8x|BnFTC*n-;0MI@Bev# z|14_ZgAif>z|8N{07QzS{whHK90vN|vYi*so}3;FHBXHX($U%Er@bD}<y<cJOsCVS z05ky9-vucE$Y!&q(;XdGWi`LWJ33~Y^p0yLr~I(n?ZIo;uJ3vN;^mGR{}`+06{+dq zf!-$1zJ7|L)B?ftSFhN&eLcH1TK(ekVh(MGHUe}bAO)>2`+9Ehe9WoHirMFzLVH_# zG!ad;5JH|5Xztv<=df5xVirpY;d^!x#oI;H&?9pDoQJHgbLCyGTE$wnh%k(iFpQD7 zTy;+p37#nsEVEb1@i<S4igXBY0#;flkl;q(thVFKsRmjU1k~18k@WS#)A|^)oLd(R z1&shi8UU)7I^-IslT3KMxY(V9Wh9M<BlXz1ibK~4_uLQ3B4k4^TDF-m#FxJ_GbXV> zpb&st+X^GogZn-}X7?f=597gSGu(sSXkM`qBsC6I;!wGZMK-qXi{0VK6a<cU``meJ zy$RO(xub{@0ATCE3HU3Dv45}=vJe4BR1C-=RGLKh(a|HNgpjxf0H(g1Rstvn03u4r zd&4NV`LVUJ3d=23u-n!kXe_~i5CQ;%b>YUF{kIM%iUJJ)-0>K0ZpeJRyJY&^S0gtZ zWlf1_NmWov=OhGp4&hV;v2<dgf3)v2Z#D^nXrSgT44zLKX97Vc77l{~MP12UI+ilb zw(GSzDk6Nt=&TQtoGmD<&#e9M`f%Si8UW@Ek)Cf5LLfZNUg?^=ymXolZI6gwwR#vR zJq!Q^)k;?+8UmZo>-9ycKPKfT)$q_T6X#<(F)Pskh>b1Fl~$DJmpL3smNhHXzeJW0 e@@s$=1nLLl22;pmHDJO30000<MNUMnLSTYdn0JN% literal 0 HcmV?d00001 diff --git a/src/chat_control.py b/src/chat_control.py index 1215ccc41a..a4379ef8bf 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -588,6 +588,14 @@ class ChatControlBase(MessageControl): self.sent_history_pos = self.sent_history_pos + 1 conv_buf.set_text(self.sent_history[self.sent_history_pos]) + def lighten_color(self, color): + p = 0.4 + mask = 0 + color.red = int((color.red * p) + (mask * (1 - p))) + color.green = int((color.green * p) + (mask * (1 - p))) + color.blue = int((color.blue * p) + (mask * (1 - p))) + return color + ################################################################################ class ChatControl(ChatControlBase): '''A control for standard 1-1 chat''' @@ -802,6 +810,9 @@ class ChatControl(ChatControlBase): if not message or message == '\n' or self._process_command(message): return + # refresh timers + self.reset_kbd_mouse_timeout_vars() + contact = self.contact jid = self.contact.jid @@ -968,11 +979,7 @@ class ChatControl(ChatControlBase): # In inactive tab color to be lighter against the darker inactive # background if self.parent_win.get_active_control() != self: - p = 0.4 - mask = 0 - color.red = int((color.red * p) + (mask * (1 - p))) - color.green = int((color.green * p) + (mask * (1 - p))) - color.blue = int((color.blue * p) + (mask * (1 - p))) + color = self.lighten_color(color) label_str = self.contact.name if num_unread: # if unread, text in the label becomes bold @@ -992,7 +999,6 @@ class ChatControl(ChatControlBase): return tab_img - def remove_possible_switch_to_menuitems(self, menu): ''' remove duplicate 'Switch to' if they exist and return clean menu''' childs = menu.get_children() diff --git a/src/common/contacts.py b/src/common/contacts.py index 2a9a2f4500..f5049cf026 100644 --- a/src/common/contacts.py +++ b/src/common/contacts.py @@ -103,6 +103,7 @@ class Contacts: def create_contact(self, jid='', name='', groups=[], show='', status='', sub='', ask='', resource='', priority=5, keyID='', our_chatstate=None, chatstate=None): + print "creating Contact:", jid return Contact(jid, name, groups, show, status, sub, ask, resource, priority, keyID, our_chatstate, chatstate) @@ -234,6 +235,7 @@ class Contacts: def create_gc_contact(self, room_jid='', name='', show='', status='', role='', affiliation='', jid='', resource=''): + print "creating GC_Contact:", jid return GC_Contact(room_jid, name, show, status, role, affiliation, jid, resource) diff --git a/src/gajim.py b/src/gajim.py index efaf36e5ea..ddfbde14e4 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -403,7 +403,8 @@ class Interface: elif gajim.connections[account].connected in (2, 3): # we're online or chat show_notification = True - if self.instances[account]['gc'].has_key(jid): # it's a Private Message + chat_control = gajim.interface.msg_win_mgr.get_control(jid) + if chat_control and chat_control.type_id == TYPE_GC: # it's a Private Message nick = gajim.get_nick_from_fjid(array[0]) fjid = array[0] if not gajim.interface.msg_win_mgr.has_window(fjid) and \ @@ -411,8 +412,7 @@ class Interface: if show_notification: notify.notify(_('New Private Message'), fjid, account, 'pm') - self.instances[account]['gc'][jid].on_private_message(jid, nick, - array[1], array[2]) + chat_control.on_private_message(nick, array[1], array[2]) return if gajim.config.get('ignore_unknown_contacts') and \ @@ -421,14 +421,14 @@ class Interface: # Handle chat states contact = gajim.contacts.get_first_contact_from_jid(account, jid) - if gajim.interface.msg_win_mgr.has_window(jid): - chat_ctl = gajim.interface.msg_win_mgr.get_control(jid) + if chat_control and chat_control.type_id == message_control.TYPE_CHAT: + ctl = gajim.interface.msg_win_mgr.get_control(jid) if chatstate is not None: # he or she sent us reply, so he supports jep85 contact.chatstate = chatstate if contact.our_chatstate == 'ask': # we were jep85 disco? contact.our_chatstate = 'active' # no more - chat_ctl.handle_incoming_chatstate() + ctl.handle_incoming_chatstate() elif contact.chatstate != 'active': # got no valid jep85 answer, peer does not support it contact.chatstate = False @@ -442,7 +442,7 @@ class Interface: first = False if not gajim.interface.msg_win_mgr.has_window(jid) and \ - not gajim.awaiting_events[account].has_key(jid): + not gajim.awaiting_events[account].has_key(jid): first = True if gajim.config.get('notify_on_new_message'): show_notification = False @@ -704,7 +704,8 @@ class Interface: # ('GC_MSG', account, (jid, msg, time)) jids = array[0].split('/', 1) room_jid = jids[0] - if not self.instances[account]['gc'].has_key(room_jid): + gc_control = gajim.interface.msg_win_mgr.get_control(room_jid) + if not gc_control: return if len(jids) == 1: # message from server @@ -712,8 +713,7 @@ class Interface: else: # message from someone nick = jids[1] - self.instances[account]['gc'][room_jid].on_message(room_jid, nick, - array[1], array[2]) + gc_control.on_message(nick, array[1], array[2]) if self.remote_ctrl: self.remote_ctrl.raise_signal('GCMessage', (account, array)) diff --git a/src/groupchat_control.py b/src/groupchat_control.py index ccb39020e5..73d65aa174 100644 --- a/src/groupchat_control.py +++ b/src/groupchat_control.py @@ -12,6 +12,7 @@ ## GNU General Public License for more details. ## +import time import gtk import gtk.glade import pango @@ -49,7 +50,7 @@ class PrivateChatControl(ChatControl): def __init__(self, parent_win, contact, acct): ChatControl.__init__(self, parent_win, contact, acct) self.TYPE_ID = 'pm' - self.display_name = _('Private char') + self.display_name = _('Private chat') class GroupchatControl(ChatControlBase): TYPE_ID = message_control.TYPE_GC @@ -57,6 +58,11 @@ class GroupchatControl(ChatControlBase): def __init__(self, parent_win, contact, acct): ChatControlBase.__init__(self, self.TYPE_ID, parent_win, 'muc_child_vbox', _('Group Chat'), contact, acct); + + self.room_jid = self.contact.jid + self.nick = contact.name + self.name = self.room_jid.split('@')[0] + self.compact_view_always = gajim.config.get('always_compact_view_gc') # alphanum sorted self.muc_cmds = ['ban', 'chat', 'query', 'clear', 'close', 'compact', 'help', 'invite', @@ -64,13 +70,17 @@ class GroupchatControl(ChatControlBase): # muc attention states (when we are mentioned in a muc) # if the room jid is in the list, the room has mentioned us self.muc_attentions = [] + self.list_treeview = None + self.allow_focus_out_line = True + # holds the iter's offset which points to the end of --- line + self.focus_out_end_iter_offset = None # connect the menuitems to their respective functions - xm = gtk.glade.XML(GTKGUI_GLADE, 'gc_popup_menu', APP) + xm = gtk.glade.XML(GTKGUI_GLADE, 'gc_control_popup_menu', APP) xm.signal_autoconnect(self) self.gc_popup_menu = xm.get_widget('gc_popup_menu') - def markup_tab_label(self, label_str, chatstate): + def get_tab_label(self, chatstate): '''Markup the label if necessary. Returns a tuple such as: (new_label_str, color) either of which can be None @@ -83,31 +93,47 @@ class GroupchatControl(ChatControlBase): color = None theme = gajim.config.get('roster_theme') if chatstate == 'attention' and (not has_focus or not current_tab): - if jid not in self.muc_attentions: - self.muc_attentions.append(jid) + if self.room_jid not in self.muc_attentions: + self.muc_attentions.append(self.room_jid) color = gajim.config.get_per('themes', theme, 'state_muc_directed_msg') elif chatstate: if chatstate == 'active' or (current_tab and has_focus): - if jid in self.muc_attentions: - self.muc_attentions.remove(jid) + if self.room_jid in self.muc_attentions: + self.muc_attentions.remove(self.room_jid) color = gajim.config.get_per('themes', theme, 'state_active_color') elif chatstate == 'newmsg' and (not has_focus or not current_tab) and\ - jid not in self.muc_attentions: + self.room_jid not in self.muc_attentions: color = gajim.config.get_per('themes', theme, 'state_muc_msg') if color: color = gtk.gdk.colormap_get_system().alloc_color(color) - # The widget state depend on whether this tab is the "current" tab - if current_tab: - nickname.modify_fg(gtk.STATE_NORMAL, color) - else: - nickname.modify_fg(gtk.STATE_ACTIVE, color) + # We set the color for when it's the current tab or not + # FIXME: why was this only happening for inactive or gone + #if chatstate in ('inactive', 'gone'): + # In inactive tab color to be lighter against the darker inactive + # background + if self.parent_win.get_active_control() != self: + color = self.lighten_color(color) + label_str = self.name if num_unread: # if unread, text in the label becomes bold label_str = '<b>' + str(num_unread) + label_str + '</b>' return (label_str, color) + def get_tab_image(self): + # Set tab image (always 16x16); unread messages show the 'message' image + img_16 = gajim.interface.roster.get_appropriate_state_images(self.room_jid) + + # nb_unread is the number directed messages (msgs that mention our nick) + tab_image = None + if self.nb_unread and gajim.config.get('show_unread_tab_icon'): + tab_image = img_16['message'] + else: + + tab_image = img_16['muc_active'] + return tab_image + def prepare_context_menu(self): '''sets compact view menuitem active state sets active and sensitivity state for toggle_gpg_menuitem @@ -118,3 +144,221 @@ class GroupchatControl(ChatControlBase): childs[5].set_active(self.compact_view_current_state) menu = self.remove_possible_switch_to_menuitems(menu) return menu + + def on_message(self, nick, msg, tim): + if not nick: + # message from server + self.print_conversation(msg, tim = tim) + else: + # message from someone + self.print_conversation(msg, nick, tim) + + def on_private_message(self, nick, msg, tim): + # Do we have a queue? + fjid = self.room_jid + '/' + nick + qs = gajim.awaiting_events[self.account] + no_queue = True + if qs.has_key(fjid): + no_queue = False + + # We print if window is opened + pm_control = gajim.interface.get_control(fjid) + if pm_control: + pm_control.print_conversation(msg, tim = tim) + return + + if no_queue: + qs[fjid] = [] + qs[fjid].append(('chat', (msg, '', 'incoming', tim, False, ''))) + + autopopup = gajim.config.get('autopopup') + autopopupaway = gajim.config.get('autopopupaway') + iter = self.get_contact_iter(nick) + path = self.list_treeview.get_model().get_path(iter) + if not autopopup or (not autopopupaway and \ + gajim.connections[self.account].connected > 2): + if no_queue: # We didn't have a queue: we change icons + model = self.list_treeview.get_model() + state_images =\ + gajim.interface.roster.get_appropriate_state_images(self.room_jid) + image = state_images['message'] + model[iter][C_IMG] = image + if gajim.interface.systray_enabled: + gajim.interface.systray.add_jid(fjid, self.account, 'pm') + self.parent_win.show_title() + else: + gc_c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) + gajim.interface.roster.new_chat(gc_c, self.account) + # Scroll to line + self.list_treeview.expand_row(path[0:1], False) + self.list_treeview.scroll_to_cell(path) + self.list_treeview.set_cursor(path) + + def get_contact_iter(self, nick): + model = self.list_treeview.get_model() + fin = False + role_iter = model.get_iter_root() + if not role_iter: + return None + while not fin: + fin2 = False + user_iter = model.iter_children(role_iter) + if not user_iter: + fin2 = True + while not fin2: + if nick == model[user_iter][C_NICK].decode('utf-8'): + return user_iter + user_iter = model.iter_next(user_iter) + if not user_iter: + fin2 = True + role_iter = model.iter_next(role_iter) + if not role_iter: + fin = True + return None + + def print_conversation(self, text, contact = '', tim = None): + '''Print a line in the conversation: + if contact is set: it's a message from someone + if contact is not set: it's a message from the server or help''' + if isinstance(text, str): + text = unicode(text, 'utf-8') + other_tags_for_name = [] + other_tags_for_text = [] + if contact: + if contact == self.nick: # it's us + kind = 'outgoing' + else: + kind = 'incoming' + # muc-specific chatstate + self.parent_win.redraw_tab(self.contact, 'newmsg') + else: + kind = 'status' + + if kind == 'incoming': # it's a message NOT from us + # highlighting and sounds + (highlight, sound) = self.highlighting_for_message(text, tim) + if highlight: + self.redraw_tab(self.contact, 'attention') # muc-specific chatstate + other_tags_for_name.append('bold') + other_tags_for_text.append('marked') + if sound == 'received': + helpers.play_sound('muc_message_received') + elif sound == 'highlight': + helpers.play_sound('muc_message_highlight') + + self.check_and_possibly_add_focus_out_line() + + ChatControlBase.print_conversation_line(self, text, kind, contact, tim, + other_tags_for_name, [], other_tags_for_text) + + def highlighting_for_message(self, text, tim): + '''Returns a 2-Tuple. The first says whether or not to highlight the + text, the second, what sound to play.''' + highlight, sound = (None, None) + + # Do we play a sound on every muc message? + if gajim.config.get_per('soundevents', 'muc_message_received', 'enabled'): + if gajim.config.get('notify_on_all_muc_messages'): + sound = 'received' + + # Are any of the defined highlighting words in the text? + if self.needs_visual_notification(text): + highlight = True + if gajim.config.get_per('soundevents', 'muc_message_highlight', + 'enabled'): + sound = 'highlight' + + # Is it a history message? Don't want sound-floods when we join. + if tim != time.localtime(): + sound = None + + return (highlight, sound) + + def check_and_possibly_add_focus_out_line(self): + '''checks and possibly adds focus out line for room_jid if it needs it + and does not already have it as last event. If it goes to add this line + it removes previous line first''' + + win = gajim.interface.msg_win_mgr.get_window(self.room_jid) + if self.room_jid == win.get_active_jid() and\ + win.window.get_property('has-toplevel-focus'): + # it's the current room and it's the focused window. + # we have full focus (we are reading it!) + return + + if not self.allow_focus_out_line: + # if room did not receive focus-in from the last time we added + # --- line then do not readd + return + + print_focus_out_line = False + buffer = self.conv_textview.get_buffer() + + if self.focus_out_end_iter_offset is None: + # this happens only first time we focus out on this room + print_focus_out_line = True + + else: + if self.focus_out_end_iter_offset != buffer.get_end_iter().get_offset(): + # this means after last-focus something was printed + # (else end_iter's offset is the same as before) + # only then print ---- line (eg. we avoid printing many following + # ---- lines) + print_focus_out_line = True + + if print_focus_out_line and buffer.get_char_count() > 0: + buffer.begin_user_action() + + # remove previous focus out line if such focus out line exists + if self.focus_out_end_iter_offset is not None: + end_iter_for_previous_line = buffer.get_iter_at_offset( + self.focus_out_end_iter_offset) + begin_iter_for_previous_line = end_iter_for_previous_line.copy() + begin_iter_for_previous_line.backward_chars(2) # img_char+1 (the '\n') + + # remove focus out line + buffer.delete(begin_iter_for_previous_line, + end_iter_for_previous_line) + + # add the new focus out line + # FIXME: Why is this loaded from disk everytime + path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png') + focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file) + end_iter = buffer.get_end_iter() + buffer.insert(end_iter, '\n') + buffer.insert_pixbuf(end_iter, focus_out_line_pixbuf) + + end_iter = buffer.get_end_iter() + before_img_iter = end_iter.copy() + before_img_iter.backward_char() # one char back (an image also takes one char) + buffer.apply_tag_by_name('focus-out-line', before_img_iter, end_iter) + #FIXME: remove this workaround when bug is fixed + # c http://bugzilla.gnome.org/show_bug.cgi?id=318569 + + self.allow_focus_out_line = False + + # update the iter we hold to make comparison the next time + self.focus_out_end_iter_offset = buffer.get_end_iter().get_offset() + + buffer.end_user_action() + + # scroll to the end (via idle in case the scrollbar has appeared) + gobject.idle_add(self.conv_textview.scroll_to_end) + + def needs_visual_notification(self, text): + '''checks text to see whether any of the words in (muc_highlight_words + and nick) appear.''' + + special_words = gajim.config.get('muc_highlight_words').split(';') + special_words.append(self.nick) + # Strip empties: ''.split(';') == [''] and would highlight everything. + # Also lowercase everything for case insensitive compare. + special_words = [word.lower() for word in special_words if word] + text = text.lower() + + text_splitted = text.split() + for word in text_splitted: # get each word of the text + for special_word in special_words: + if word.startswith(special_word): + return True + return False diff --git a/src/message_control.py b/src/message_control.py index 75d643964b..dcd8515fc9 100644 --- a/src/message_control.py +++ b/src/message_control.py @@ -119,9 +119,6 @@ class MessageControl: def send_message(self, message, keyID = '', type = 'chat', chatstate = None): '''Send the given message to the active tab''' - # refresh timers - self.reset_kbd_mouse_timeout_vars() - jid = self.contact.jid # Send and update history gajim.connections[self.account].send_message(jid, message, keyID, diff --git a/src/message_window.py b/src/message_window.py index 4641800b3a..4cc6010f75 100644 --- a/src/message_window.py +++ b/src/message_window.py @@ -43,10 +43,10 @@ class MessageWindow: self.widget_name = 'message_window' self.xml = gtk.glade.XML(GTKGUI_GLADE, self.widget_name, APP) self.window = self.xml.get_widget(self.widget_name) - # FIXME: assertion that !GTK_WIDGET_REALIZED fails +# FIXME: assertion that !GTK_WIDGET_REALIZED fails # gtk+ doesn't make use of the motion notify on gtkwindow by default # so this line adds that - #self.window.set_events(gtk.gdk.POINTER_MOTION_MASK) +# self.window.set_events(gtk.gdk.POINTER_MOTION_MASK) self.alignment = self.xml.get_widget('alignment') self.notebook = self.xml.get_widget('notebook') @@ -312,16 +312,16 @@ class MessageWindow: for ctl in self._controls.values(): ctl.update_tags() - def get_control(self, arg): + def get_control(self, key): '''Return the MessageControl for jid or n, where n is the notebook page index''' - if isinstance(arg, unicode): - jid = arg + if isinstance(key, unicode): + jid = key for ctl in self._controls.values(): if ctl.contact.jid == jid: return ctl return None else: - page_num = arg + page_num = key notebook = self.notebook if page_num == None: page_num = notebook.get_current_page() diff --git a/src/roster_window.py b/src/roster_window.py index df157282d5..bd696172bf 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -325,8 +325,7 @@ class RosterWindow: def join_gc_room(self, account, room_jid, nick, password): '''joins the room immediatelly''' - # FIXME - if room_jid in gajim.interface.instances[account]['gc'] and \ + if gajim.interface.msg_win_mgr.has_window(room_jid) and \ gajim.gc_connected[account][room_jid]: dialogs.ErrorDialog(_('You are already in room %s') % room_jid ).get_response() @@ -337,10 +336,11 @@ class RosterWindow: ).get_response() return room, server = room_jid.split('@') - if not room_jid in gajim.interface.instances[account]['gc']: + if not gajim.interface.msg_win_mgr.has_window(room_jid): self.new_room(room_jid, nick, account) - gajim.interface.instances[account]['gc'][room_jid].set_active_tab(room_jid) - gajim.interface.instances[account]['gc'][room_jid].window.present() + gc_win = gajim.interface.msg_win_mgr.get_window(room_jid) + gc_win.set_active_tab(room_jid) + gc_win.window.present() gajim.connections[account].join_gc(nick, room, server, password) if password: gajim.gc_passwords[room_jid] = password @@ -1705,10 +1705,8 @@ _('If "%s" accepts this request you will know his or her status.') % jid) mw.window.present() def new_room(self, room_jid, nick, account): - print "new_room" - # FIXME: Not contact. Use jid and nick # Get target window, create a control, and associate it with the window - contact = gajim.contacts.create_contact(jid = room_jid) + contact = gajim.contacts.create_contact(jid = room_jid, name = nick) mw = gajim.interface.msg_win_mgr.get_window(contact.jid) if not mw: mw = gajim.interface.msg_win_mgr.create_window(contact, account, -- GitLab