merge from trunk
This commit is contained in:
commit
a3863703f0
47
ChangeLog
47
ChangeLog
|
@ -1,4 +1,47 @@
|
||||||
Gajim 0.13 (XX November 2009)
|
Gajim 0.14 (XX)
|
||||||
|
|
||||||
|
* Jingle audio / video chat
|
||||||
|
* Improve Startup time
|
||||||
|
* Copy emoticons, LaTeX expressions when they are selected
|
||||||
|
* Fix status icon transparency by using gtk.statusicon
|
||||||
|
* Groupchat auto-rejoin
|
||||||
|
* geolocation (with geoclue)
|
||||||
|
* use XDG standards
|
||||||
|
* SCRAM-SHA-1 and SASL EXTERNAL authentication
|
||||||
|
* MUC captcha
|
||||||
|
* Lots of refactoring
|
||||||
|
|
||||||
|
Gajim 0.13.4 (02 April 2010)
|
||||||
|
|
||||||
|
* Add japanese translation
|
||||||
|
* Fix some TLS connection
|
||||||
|
* Don't raise a lot of "DB Error" dialog
|
||||||
|
* Fix contact synchronisation
|
||||||
|
* Minor fixes
|
||||||
|
|
||||||
|
Gajim 0.13.3 (23 February 2010)
|
||||||
|
|
||||||
|
* Fix facebook xmpp server connection
|
||||||
|
* Fix copy / paste with Ctrl+C on non-latin keyboard
|
||||||
|
* Fix sending PEP information when connecting
|
||||||
|
* Fix parsing HTML messages that have ascii markup
|
||||||
|
|
||||||
|
Gajim 0.13.2 (14 January 2010)
|
||||||
|
|
||||||
|
* Fix some translations
|
||||||
|
* Fix string comparison according to locales
|
||||||
|
* Fix resizing of groupchat occupant treeview
|
||||||
|
* Fix some gnomekeyring glitches
|
||||||
|
* better SRV usage with libasyncns
|
||||||
|
* copy emoticons when we copy / paste in conversations
|
||||||
|
|
||||||
|
Gajim 0.13.1 (28 November 2009)
|
||||||
|
|
||||||
|
* Fix a bug when no account exists and bonjour is not available
|
||||||
|
* Fix a bug when opening advanced option in MUC
|
||||||
|
* Fix a bug when using non-BOSH proxies
|
||||||
|
|
||||||
|
Gajim 0.13 (24 November 2009)
|
||||||
|
|
||||||
* Improve gtkspell (fix memleak)
|
* Improve gtkspell (fix memleak)
|
||||||
* BOSH connection
|
* BOSH connection
|
||||||
|
@ -44,7 +87,7 @@ Gajim 0.12.2 (07 June 2009)
|
||||||
* Improve error messages handling
|
* Improve error messages handling
|
||||||
* Totem support for played music
|
* Totem support for played music
|
||||||
* Fix SSL with some servers
|
* Fix SSL with some servers
|
||||||
* Handle Xfce notification-daemon
|
* Handle XFCE notification-daemon
|
||||||
* Restore old behaviour of click on systray: left click to open events
|
* Restore old behaviour of click on systray: left click to open events
|
||||||
* Network manager 0.7 support
|
* Network manager 0.7 support
|
||||||
* Move logs file under windows to $APPDATA/gajim
|
* Move logs file under windows to $APPDATA/gajim
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
SUBDIRS = src data po icons
|
SUBDIRS = src data plugins po icons
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
|
|
||||||
<p>To specify where to install do:</p>
|
<p>To specify where to install do:</p>
|
||||||
<pre>
|
<pre>
|
||||||
su -c make PREFIX=custom_path install
|
./configure --prefix=custom_path
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h2>Running Gajim</h2>
|
<h2>Running Gajim</h2>
|
||||||
|
@ -98,7 +98,8 @@ or if you didn't 'make install' you can also run from gajim folder with<em>./lau
|
||||||
If you want to remove it from custom directory provide it as:
|
If you want to remove it from custom directory provide it as:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
make PREFIX=custom_path uninstall
|
./configure --prefix=custom_path
|
||||||
|
make uninstall
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h2>Miscellaneous</h2>
|
<h2>Miscellaneous</h2>
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
gajimversion="0.13.90.1"
|
||||||
|
if [ -d ".hg" ]; then
|
||||||
|
hgversion="-$(hexdump -n6 -e'6/1 "%02x"' .hg/dirstate)"
|
||||||
|
else
|
||||||
|
hgversion=""
|
||||||
|
fi
|
||||||
|
echo "define([AC_PACKAGE_VERSION], [${gajimversion}${hgversion}])" > m4/hgversion.m4
|
||||||
|
|
||||||
AM_ARGS="--add-missing --gnu --copy"
|
AM_ARGS="--add-missing --gnu --copy"
|
||||||
CONF_ARGS=""
|
CONF_ARGS=""
|
||||||
if test x`uname -s 2>/dev/null` = 'xDarwin' -a -f /Library/Frameworks/GTK+.framework/Versions/Current/env; then
|
if test x`uname -s 2>/dev/null` = 'xDarwin' -a -f /Library/Frameworks/GTK+.framework/Versions/Current/env; then
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
AC_INIT([Gajim - A Jabber Instant Messager],
|
AC_INIT([Gajim - A Jabber Instant Messager],
|
||||||
[0.13.10.2-dev],[http://trac.gajim.org/],[gajim])
|
["version-set-in-hgversion"],[http://trac.gajim.org/],[gajim])
|
||||||
AC_PREREQ([2.59])
|
AC_PREREQ([2.59])
|
||||||
|
|
||||||
AC_CONFIG_HEADER(config.h)
|
AC_CONFIG_HEADER(config.h)
|
||||||
|
@ -65,14 +65,17 @@ AC_ARG_ENABLE(site-packages,
|
||||||
instead of DATADIR/gajim/src.])]
|
instead of DATADIR/gajim/src.])]
|
||||||
,
|
,
|
||||||
AC_SUBST([gajim_srcdir], [\${pkgpythondir}])
|
AC_SUBST([gajim_srcdir], [\${pkgpythondir}])
|
||||||
|
AC_SUBST([gajim_pluginsdir], [\${pkgpythondir}])
|
||||||
,
|
,
|
||||||
AC_SUBST([gajim_srcdir], [\${datadir}/\${PACKAGE}/src])
|
AC_SUBST([gajim_srcdir], [\${datadir}/\${PACKAGE}/src])
|
||||||
|
AC_SUBST([gajim_pluginsdir], [\${datadir}/\${PACKAGE}/plugins])
|
||||||
)
|
)
|
||||||
|
|
||||||
AS_AC_EXPAND(GAJIM_SRCDIR, "${gajim_srcdir}")
|
AS_AC_EXPAND(GAJIM_SRCDIR, "${gajim_srcdir}")
|
||||||
AS_AC_EXPAND(PKGDATADIR, "${datadir}/${PACKAGE}")
|
AS_AC_EXPAND(PKGDATADIR, "${datadir}/${PACKAGE}")
|
||||||
AS_AC_EXPAND(DOCDIR, "${docdir}")
|
AS_AC_EXPAND(DOCDIR, "${docdir}")
|
||||||
AS_AC_EXPAND(LOCALEDIR, "${localedir}")
|
AS_AC_EXPAND(LOCALEDIR, "${localedir}")
|
||||||
|
AS_AC_EXPAND(GAJIM_PLUGINSDIR, "${gajim_pluginsdir}")
|
||||||
|
|
||||||
AC_SUBST(VERSION)
|
AC_SUBST(VERSION)
|
||||||
AC_SUBST(PACKAGE)
|
AC_SUBST(PACKAGE)
|
||||||
|
@ -94,6 +97,7 @@ AC_CONFIG_FILES([
|
||||||
scripts/gajim-remote:scripts/gajim.in
|
scripts/gajim-remote:scripts/gajim.in
|
||||||
scripts/gajim-history-manager:scripts/gajim.in
|
scripts/gajim-history-manager:scripts/gajim.in
|
||||||
po/Makefile.in
|
po/Makefile.in
|
||||||
|
plugins/Makefile
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
echo "
|
echo "
|
||||||
|
@ -101,6 +105,7 @@ echo "
|
||||||
Installation:
|
Installation:
|
||||||
Prefix ........... ${prefix}
|
Prefix ........... ${prefix}
|
||||||
Python modules ... ${GAJIM_SRCDIR}
|
Python modules ... ${GAJIM_SRCDIR}
|
||||||
|
Plugins .. ....... ${GAJIM_PLUGINSDIR}
|
||||||
Documentation .... ${DOCDIR}
|
Documentation .... ${DOCDIR}
|
||||||
Others ........... ${PKGDATADIR}
|
Others ........... ${PKGDATADIR}
|
||||||
*****************************"
|
*****************************"
|
||||||
|
|
|
@ -14,7 +14,7 @@ sounds_DATA = $(srcdir)/sounds/*.wav
|
||||||
otherdir = $(pkgdatadir)/data/other
|
otherdir = $(pkgdatadir)/data/other
|
||||||
other_DATA = other/servers.xml other/cacerts.pem
|
other_DATA = other/servers.xml other/cacerts.pem
|
||||||
|
|
||||||
man_MANS = gajim.1 gajim-remote.1
|
man_MANS = gajim.1 gajim-remote.1 gajim-history-manager.1
|
||||||
|
|
||||||
|
|
||||||
EXTRA_DIST = $(desktop_in_files) \
|
EXTRA_DIST = $(desktop_in_files) \
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
.\" 20050901
|
||||||
|
.TH "Gajim-history-manager" "1" "September 01, 2005" "Gajim dev team" ""
|
||||||
|
.SH "NAME"
|
||||||
|
Gajim-history-manager \- Tool to manage gajim logs
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
.B gajim-history-manager [\-c config-path] [\-h]
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
.B Gajim-history-manager
|
||||||
|
is a tool to manage (do some cleanup) log file of Gajim jabber client.
|
||||||
|
.PP
|
||||||
|
.SH "OPTIONS"
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-config-path\fR path
|
||||||
|
Path where logs.db is located. ~/.gajim by default.
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
Print this help.
|
||||||
|
.SH "FEEDBACK"
|
||||||
|
You can report bugs or feature requests in http://trac.gajim.org or in the mailing list: http://lists.gajim.org/cgi\-bin/listinfo/gajim\-devel. You can also find us in our room gajim@conference.gajim.org
|
||||||
|
.SH "AUTHORS"
|
||||||
|
Written by Yann Le Boulanger <asterix@lagaule.org>, Nikos Kouremenos <kourem@gmail.com> and Dimitur Kirov <dkirov@gmail.com>.
|
|
@ -217,7 +217,7 @@ to the Jabber network.</property>
|
||||||
<object class="GtkLabel" id="label1">
|
<object class="GtkLabel" id="label1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="xalign">0</property>
|
<property name="xalign">0</property>
|
||||||
<property name="label" translatable="yes">@</property>
|
<property name="label">@</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">2</property>
|
<property name="left_attach">2</property>
|
||||||
|
|
|
@ -422,6 +422,21 @@
|
||||||
<property name="position">3</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="finish_button">
|
||||||
|
<property name="label" translatable="yes">F_inish</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<signal name="clicked" handler="on_finish_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="close_button">
|
<object class="GtkButton" id="close_button">
|
||||||
<property name="label">gtk-close</property>
|
<property name="label">gtk-close</property>
|
||||||
|
@ -435,7 +450,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">4</property>
|
<property name="position">5</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -9,6 +9,13 @@
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="archiving_preferences_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Edit Archi_ving Preferences</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkMenuItem" id="privacy_lists_menuitem">
|
<object class="GtkMenuItem" id="privacy_lists_menuitem">
|
||||||
<property name="label" translatable="yes">Edit _Privacy Lists...</property>
|
<property name="label" translatable="yes">Edit _Privacy Lists...</property>
|
||||||
|
|
|
@ -0,0 +1,312 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy project-wide -->
|
||||||
|
<object class="GtkListStore" id="liststore1">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">No</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Yes</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore2">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Forbid</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore3">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Forbid</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore4">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Forbid</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkWindow" id="archiving_preferences_window">
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<signal name="destroy" handler="on_archiving_preferences_window_destroy"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="n_rows">4</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><i>Method Manual</i></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><i>Method Local</i></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><i>Method Auto</i></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="method_manual_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore4</property>
|
||||||
|
<signal name="changed" handler="on_method_foo_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext4"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="method_local_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore3</property>
|
||||||
|
<signal name="changed" handler="on_method_foo_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext3"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="method_auto_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore2</property>
|
||||||
|
<signal name="changed" handler="on_method_foo_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext2"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Auto</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="auto_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore1</property>
|
||||||
|
<signal name="changed" handler="on_auto_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext1"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">automatic</property>
|
||||||
|
<property name="vscrollbar_policy">automatic</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="item_treeview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<signal name="cursor_changed" handler="on_item_treeview_cursor_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">spread</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="add_button">
|
||||||
|
<property name="label">gtk-add</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_add_item_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="remove_button">
|
||||||
|
<property name="label">gtk-remove</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_remove_item_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="edit_button">
|
||||||
|
<property name="label">gtk-edit</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_edit_item_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="close_button">
|
||||||
|
<property name="label">gtk-close</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
File diff suppressed because it is too large
Load Diff
|
@ -75,6 +75,85 @@
|
||||||
<property name="position">0</property>
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHPaned" id="hpaned">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="border_width">3</property>
|
||||||
|
<property name="position">495</property>
|
||||||
|
<property name="position_set">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="gc_textviews_vbox">
|
||||||
|
<property name="width_request">0</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
|
||||||
|
<property name="width_request">200</property>
|
||||||
|
<property name="height_request">60</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">automatic</property>
|
||||||
|
<property name="vscrollbar_policy">automatic</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">never</property>
|
||||||
|
<property name="vscrollbar_policy">never</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">False</property>
|
||||||
|
<property name="shrink">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="list_scrolledwindow">
|
||||||
|
<property name="width_request">100</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">never</property>
|
||||||
|
<property name="vscrollbar_policy">automatic</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="list_treeview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="border_width">1</property>
|
||||||
|
<property name="headers_visible">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">False</property>
|
||||||
|
<property name="shrink">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkHBox" id="actions_hbox">
|
<object class="GtkHBox" id="actions_hbox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -133,7 +212,6 @@
|
||||||
<object class="GtkVSeparator" id="vseparator2">
|
<object class="GtkVSeparator" id="vseparator2">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
@ -233,7 +311,6 @@
|
||||||
<object class="GtkVSeparator" id="vseparator4">
|
<object class="GtkVSeparator" id="vseparator4">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
@ -269,6 +346,14 @@
|
||||||
<property name="position">8</property>
|
<property name="position">8</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="label_selector">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">9</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkAlignment" id="alignment2">
|
<object class="GtkAlignment" id="alignment2">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -278,7 +363,7 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">9</property>
|
<property name="position">10</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -326,7 +411,7 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="position">10</property>
|
<property name="position">11</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
@ -335,94 +420,5 @@
|
||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="GtkHPaned" id="hpaned">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="border_width">3</property>
|
|
||||||
<property name="position">495</property>
|
|
||||||
<property name="position_set">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkVBox" id="vbox108">
|
|
||||||
<property name="width_request">0</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">6</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkVBox" id="vbox109">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">6</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
|
|
||||||
<property name="width_request">200</property>
|
|
||||||
<property name="height_request">60</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="hscrollbar_policy">automatic</property>
|
|
||||||
<property name="vscrollbar_policy">automatic</property>
|
|
||||||
<property name="shadow_type">in</property>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow" id="message_scrolledwindow">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="hscrollbar_policy">never</property>
|
|
||||||
<property name="vscrollbar_policy">never</property>
|
|
||||||
<property name="shadow_type">in</property>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="resize">False</property>
|
|
||||||
<property name="shrink">False</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow" id="list_scrolledwindow">
|
|
||||||
<property name="width_request">100</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="hscrollbar_policy">never</property>
|
|
||||||
<property name="vscrollbar_policy">automatic</property>
|
|
||||||
<property name="shadow_type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkTreeView" id="list_treeview">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="border_width">1</property>
|
|
||||||
<property name="headers_visible">False</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="resize">False</property>
|
|
||||||
<property name="shrink">False</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
</object>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<object class="GtkLabel" id="label1">
|
<object class="GtkLabel" id="label1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="xalign">0</property>
|
<property name="xalign">0</property>
|
||||||
<property name="label" translatable="yes">From</property>
|
<property name="label" translatable="yes">From:</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="x_options">GTK_FILL</property>
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
<object class="GtkLabel" id="label2">
|
<object class="GtkLabel" id="label2">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="xalign">0</property>
|
<property name="xalign">0</property>
|
||||||
<property name="label" translatable="yes">Subject</property>
|
<property name="label" translatable="yes">Subject:</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="top_attach">1</property>
|
<property name="top_attach">1</property>
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy project-wide -->
|
||||||
|
<object class="GtkWindow" id="item_archiving_preferences_window">
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<signal name="destroy" handler="on_item_archiving_preferences_window_destroy"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="n_rows">4</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label8">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">expire</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="expire_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">•</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="otr_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore2</property>
|
||||||
|
<signal name="changed" handler="on_otr_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext2"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="save_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore1</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext1"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">save</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label9">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">otr</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">jid</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="jid_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">•</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkProgressBar" id="progressbar"/>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="cancel_button">
|
||||||
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_cancel_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="ok_button">
|
||||||
|
<property name="label">gtk-ok</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_ok_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore1">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">body</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">false</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">message</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">stream</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore2">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">approve</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">forbid</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">oppose</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">require</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -44,6 +44,7 @@
|
||||||
<property name="xalign">0</property>
|
<property name="xalign">0</property>
|
||||||
<property name="use_markup">True</property>
|
<property name="use_markup">True</property>
|
||||||
<property name="ellipsize">end</property>
|
<property name="ellipsize">end</property>
|
||||||
|
<property name="max_width_chars">9</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
|
|
|
@ -0,0 +1,644 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy toplevel-contextual -->
|
||||||
|
<object class="GtkWindow" id="plugins_window">
|
||||||
|
<property name="width_request">650</property>
|
||||||
|
<property name="height_request">500</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="title" translatable="yes">Plugins</property>
|
||||||
|
<property name="default_width">650</property>
|
||||||
|
<property name="default_height">500</property>
|
||||||
|
<signal name="destroy" handler="on_plugins_window_destroy"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkNotebook" id="plugins_notebook">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHPaned" id="hpaned1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="position">250</property>
|
||||||
|
<property name="position_set">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="hscrollbar_policy">automatic</property>
|
||||||
|
<property name="vscrollbar_policy">automatic</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="installed_plugins_treeview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">False</property>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="plugin_name_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">&lt;empty&gt;</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
<property name="selectable">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Version:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="plugin_version_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes"><empty></property>
|
||||||
|
<property name="selectable">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Authors:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="plugin_authors_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="label" translatable="yes"><empty></property>
|
||||||
|
<property name="wrap_mode">word-char</property>
|
||||||
|
<property name="selectable">True</property>
|
||||||
|
<property name="ellipsize">end</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label6">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Homepage:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLinkButton" id="plugin_homepage_linkbutton">
|
||||||
|
<property name="label" translatable="yes">homepage url</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="relief">none</property>
|
||||||
|
<property name="focus_on_click">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label7">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Descrition:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="plugin_description_textview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="pixels_above_lines">6</property>
|
||||||
|
<property name="editable">False</property>
|
||||||
|
<property name="wrap_mode">word</property>
|
||||||
|
<property name="left_margin">6</property>
|
||||||
|
<property name="right_margin">6</property>
|
||||||
|
<property name="indent">1</property>
|
||||||
|
<property name="buffer">textbuffer1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="uninstall_plugin_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_uninstall_plugin_button_clicked"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox11">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="image1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="stock">gtk-cancel</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="uninstall_plugin_button_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Uninstall</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="configure_plugin_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_configure_plugin_button_clicked"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox12">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="image2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="stock">gtk-preferences</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="configure_plugin_button_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Configure</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">True</property>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Installed</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHPaned" id="hpaned2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scrolledwindow2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">automatic</property>
|
||||||
|
<property name="vscrollbar_policy">automatic</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="treeview2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">False</property>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox6">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="plugin_name_label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><empty></property>
|
||||||
|
<property name="selectable">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox7">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Version:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="plugin_version_label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><empty></property>
|
||||||
|
<property name="selectable">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox8">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label8">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Authors:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="plugin_authors_label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><empty></property>
|
||||||
|
<property name="selectable">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox9">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label9">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Homepage:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLinkButton" id="plugin_homepage_linkbutton1">
|
||||||
|
<property name="label" translatable="yes">button</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="relief">none</property>
|
||||||
|
<property name="focus_on_click">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Descrition:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="plugin_description_textview1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="uninstall_plugin_button1">
|
||||||
|
<property name="label" translatable="yes">button</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="configure_plugin_button1">
|
||||||
|
<property name="label" translatable="yes">button</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">True</property>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="label2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label" translatable="yes">Available</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">15</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="close_button">
|
||||||
|
<property name="label">gtk-close</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<object class="GtkTextBuffer" id="textbuffer1">
|
||||||
|
<property name="text" translatable="yes">Plug-in decription should be displayed here. This text will be erased during PluginsWindow initialization.</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -2136,7 +2136,7 @@ $T will be replaced by auto-not-available timeout</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTable" id="table8">
|
<object class="GtkTable" id="table8">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="n_rows">2</property>
|
<property name="n_rows">4</property>
|
||||||
<property name="n_columns">2</property>
|
<property name="n_columns">2</property>
|
||||||
<property name="column_spacing">6</property>
|
<property name="column_spacing">6</property>
|
||||||
<property name="row_spacing">6</property>
|
<property name="row_spacing">6</property>
|
||||||
|
@ -2184,6 +2184,52 @@ $T will be replaced by auto-not-available timeout</property>
|
||||||
<property name="bottom_attach">2</property>
|
<property name="bottom_attach">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label26">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Video framerate</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label27">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Video size</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="video_framerate_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<signal name="changed" handler="on_video_framerate_combobox_changed"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="video_size_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<signal name="changed" handler="on_video_size_combobox_changed"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -54,8 +54,8 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="join_gc_menuitem">
|
<object class="GtkImageMenuItem" id="join_gc_menuitem">
|
||||||
<property name="label" translatable="yes">Join _Group Chat...</property>
|
<property name="label" translatable="yes">Join _Group Chat...</property>
|
||||||
<property name="use_underline">True</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image3</property>
|
<property name="image">image3</property>
|
||||||
<property name="use_stock">False</property>
|
<property name="use_stock">False</property>
|
||||||
<property name="accel_group">accelgroup1</property>
|
<property name="accel_group">accelgroup1</property>
|
||||||
|
@ -69,8 +69,8 @@
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="add_new_contact_menuitem">
|
<object class="GtkImageMenuItem" id="add_new_contact_menuitem">
|
||||||
<property name="label" translatable="yes">Add _Contact...</property>
|
<property name="label" translatable="yes">Add _Contact...</property>
|
||||||
<property name="use_underline">True</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image4</property>
|
<property name="image">image4</property>
|
||||||
<property name="use_stock">False</property>
|
<property name="use_stock">False</property>
|
||||||
<property name="accel_group">accelgroup1</property>
|
<property name="accel_group">accelgroup1</property>
|
||||||
|
@ -159,6 +159,16 @@
|
||||||
<signal name="activate" handler="on_preferences_menuitem_activate"/>
|
<signal name="activate" handler="on_preferences_menuitem_activate"/>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="plugins_menuitem">
|
||||||
|
<property name="label" translatable="yes">P_lugins</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="image">image13</property>
|
||||||
|
<property name="use_stock">False</property>
|
||||||
|
<signal name="activate" handler="on_plugins_menuitem_activate"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
@ -437,4 +447,9 @@
|
||||||
<property name="stock">gtk-properties</property>
|
<property name="stock">gtk-properties</property>
|
||||||
<property name="icon-size">1</property>
|
<property name="icon-size">1</property>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkImage" id="image13">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="stock">gtk-disconnect</property>
|
||||||
|
<property name="icon-size">1</property>
|
||||||
|
</object>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
gajim (0.13.90-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* New upstream release.
|
||||||
|
|
||||||
|
-- Yann Leboulanger <asterix@lagaule.org> Sat, 24 Jul 2010 10:25:26 +0200
|
||||||
|
|
||||||
|
gajim (0.13.4-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* New upstream release.
|
||||||
|
* Fix flood when trying to join a full MUC. Closes: #575688
|
||||||
|
|
||||||
|
-- Yann Leboulanger <asterix@lagaule.org> Fri, 02 Apr 2010 10:19:59 +0200
|
||||||
|
|
||||||
gajim (0.13.3-1) unstable; urgency=low
|
gajim (0.13.3-1) unstable; urgency=low
|
||||||
|
|
||||||
* New upstream release.
|
* New upstream release.
|
||||||
|
|
|
@ -2,21 +2,21 @@ Source: gajim
|
||||||
Section: net
|
Section: net
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Yann Leboulanger <asterix@lagaule.org>
|
Maintainer: Yann Leboulanger <asterix@lagaule.org>
|
||||||
Build-Depends: debhelper (>= 7), cdbs (>= 0.4.43), python-support (>= 0.7.1), python-dev, libgtk2.0-dev, python-gtk2-dev, gettext (>= 0.17-4), intltool (>= 0.40.1), imagemagick, python-central (>= 0.5)
|
Build-Depends: debhelper (>= 7), cdbs (>= 0.4.43), python-support (>= 0.7.1), python-dev, libgtk2.0-dev, python-gtk2-dev, gettext (>= 0.17-4), intltool (>= 0.40.1), imagemagick
|
||||||
Build-Conflicts: python2.3
|
Build-Conflicts: python2.3
|
||||||
XS-Python-Version: >= 2.4
|
XS-Python-Version: >= 2.5
|
||||||
Standards-Version: 3.8.3
|
Standards-Version: 3.8.3
|
||||||
Homepage: http://www.gajim.org
|
Homepage: http://www.gajim.org
|
||||||
Vcs-Hg: http://hg.gajim.org/gajim/
|
Vcs-Hg: http://hg.gajim.org/gajim/
|
||||||
Vcs-Browser: http://hg.gajim.org/gajim/file
|
Vcs-Browser: http://hg.gajim.org/gajim/file
|
||||||
|
|
||||||
Package: gajim
|
Package: gajim
|
||||||
Architecture: any
|
Architecture: all
|
||||||
XB-Python-Version: ${python:Versions}
|
XB-Python-Version: ${python:Versions}
|
||||||
Depends: ${misc:Depends}, ${shlibs:Depends}, ${python:Depends}, python-support (>= 0.7.1), python-glade2 (>= 2.12.0), python-gtk2 (>= 2.12.0), dnsutils
|
Depends: ${misc:Depends}, ${shlibs:Depends}, ${python:Depends}, python-support (>= 0.7.1), python-glade2 (>= 2.12.0), python-gtk2 (>= 2.12.0), dnsutils
|
||||||
Recommends: dbus, python-dbus, notification-daemon, python-gnupginterface, python-openssl, python-crypto
|
Recommends: dbus, python-dbus, notification-daemon, python-gnupginterface, python-openssl, python-crypto
|
||||||
Suggests: python-gconf, python-gnome2, nautilus-sendto, avahi-daemon, python-avahi, network-manager, libgtkspell0, aspell-en, python-gnomekeyring, gnome-keyring, python-sexy, python-kerberos (>= 1.1), texlive-latex-base, dvipng
|
Suggests: python-gconf, python-gnome2, nautilus-sendto, avahi-daemon, python-avahi, network-manager, libgtkspell0, aspell-en, python-gnomekeyring, gnome-keyring, python-sexy, python-kerberos (>= 1.1), texlive-latex-base, dvipng, python-farsight, gstreamer0.10-plugins-ugly
|
||||||
Description: Jabber client written in PyGTK
|
Description: Jabber client written in PyGTK
|
||||||
Gajim is a Jabber client. It has a tabbed user interface with normal chats,
|
Gajim is a Jabber client. It has a tabbed user interface with normal chats,
|
||||||
group chats, and has many features such as, TLS, GPG, SSL, multiple accounts,
|
group chats, and has many features such as, TLS, GPG, SSL, multiple accounts,
|
||||||
avatars, file transfers, D-Bus and Metacontacts.
|
avatars, file transfers, audio/video call, D-Bus and Metacontacts.
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
data/gajim.1
|
data/gajim.1
|
||||||
data/gajim-remote.1
|
data/gajim-remote.1
|
||||||
debian/gajim-history-manager.1
|
data/gajim-history-manager.1
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
2
|
|
|
@ -1 +1 @@
|
||||||
2.4
|
2.5-
|
||||||
|
|
|
@ -7,12 +7,11 @@ include /usr/share/cdbs/1/rules/debhelper.mk
|
||||||
include /usr/share/cdbs/1/rules/simple-patchsys.mk
|
include /usr/share/cdbs/1/rules/simple-patchsys.mk
|
||||||
include /usr/share/cdbs/1/class/autotools.mk
|
include /usr/share/cdbs/1/class/autotools.mk
|
||||||
|
|
||||||
PYTHONVER = 2.5
|
|
||||||
DEB_CONFIGURE_EXTRA_FLAGS := --prefix=/usr
|
DEB_CONFIGURE_EXTRA_FLAGS := --prefix=/usr
|
||||||
DEB_MAKE_BUILD_TARGET := all PYTHON=python$(PYTHONVER)
|
DEB_MAKE_BUILD_TARGET := all
|
||||||
DEB_MAKE_INSTALL_TARGET = install PYTHON=python$(PYTHONVER) DESTDIR=$(DEB_DESTDIR)
|
DEB_MAKE_INSTALL_TARGET = install DESTDIR=$(DEB_DESTDIR)
|
||||||
|
|
||||||
binary-install/gajim::
|
binary-install/gajim::
|
||||||
rm $(DEB_DESTDIR)/usr/share/gajim/src/common/GnuPGInterface.py*
|
rm $(DEB_DESTDIR)/usr/share/gajim/src/common/GnuPGInterface.py*
|
||||||
dh_pysupport -pgajim
|
dh_pysupport -pgajim
|
||||||
convert $(DEB_DESTDIR)/usr/share/pixmaps/gajim.png -resize 32x32 $(DEB_DESTDIR)/usr/share/pixmaps/gajim.xpm
|
convert $(DEB_DESTDIR)/usr/share/icons/hicolor/64x64/apps/gajim.png -resize 32x32 $(DEB_DESTDIR)/usr/share/pixmaps/gajim.xpm
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Control file for uscan
|
||||||
|
# Run the "uscan" command to check for upstream updates and more.
|
||||||
|
# See uscan(1) for format
|
||||||
|
|
||||||
|
# Compulsory line, this is a version 3 file
|
||||||
|
version=3
|
||||||
|
|
||||||
|
http://www.gajim.org/downloads/([\d.]*)/gajim-([\d\.]*)\.tar\.gz
|
Binary file not shown.
After Width: | Height: | Size: 828 B |
Binary file not shown.
After Width: | Height: | Size: 706 B |
Binary file not shown.
After Width: | Height: | Size: 767 B |
Binary file not shown.
After Width: | Height: | Size: 760 B |
|
@ -47,3 +47,8 @@ AC_DEFUN([AS_AC_EXPAND],
|
||||||
prefix=$prefix_save
|
prefix=$prefix_save
|
||||||
exec_prefix=$exec_prefix_save
|
exec_prefix=$exec_prefix_save
|
||||||
])
|
])
|
||||||
|
|
||||||
|
# Fix autoconf: They don't allow shell variables in AC_INIT
|
||||||
|
# So we have to define them via m4 to be accepted....
|
||||||
|
|
||||||
|
m4_include(m4/hgversion.m4)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
INCLUDES = \
|
||||||
|
$(PYTHON_INCLUDES)
|
||||||
|
|
||||||
|
gajimpluginsdir = $(gajim_pluginsdir)
|
||||||
|
nobase_dist_gajimplugins_PYTHON = \
|
||||||
|
$(srcdir)/*.py \
|
||||||
|
$(srcdir)/*/*.py \
|
||||||
|
$(srcdir)/*/*.ui
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = Makefile.in
|
|
@ -0,0 +1,102 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
'''
|
||||||
|
Acronyms expander plugin.
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 9th June 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
import gobject
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log, log_calls
|
||||||
|
|
||||||
|
class AcronymsExpanderPlugin(GajimPlugin):
|
||||||
|
name = u'Acronyms Expander'
|
||||||
|
short_name = u'acronyms_expander'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Replaces acronyms (or other strings) with given expansions/substitutes.'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('AcronymsExpanderPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = None
|
||||||
|
|
||||||
|
self.gui_extension_points = {
|
||||||
|
'chat_control_base': (self.connect_with_chat_control_base,
|
||||||
|
self.disconnect_from_chat_control_base)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.config_default_values = {
|
||||||
|
'INVOKER': (' ', _('')),
|
||||||
|
'ACRONYMS': ({'RTFM': 'Read The Friendly Manual',
|
||||||
|
'/slap': '/me slaps',
|
||||||
|
'PS-': 'plug-in system',
|
||||||
|
'G-': 'Gajim',
|
||||||
|
'GNT-': 'http://trac.gajim.org/newticket',
|
||||||
|
'GW-': 'http://trac.gajim.org/',
|
||||||
|
'GTS-': 'http://trac.gajim.org/report',
|
||||||
|
},
|
||||||
|
_('')),
|
||||||
|
}
|
||||||
|
|
||||||
|
@log_calls('AcronymsExpanderPlugin')
|
||||||
|
def textbuffer_live_acronym_expander(self, tb):
|
||||||
|
"""
|
||||||
|
@param tb gtk.TextBuffer
|
||||||
|
"""
|
||||||
|
#assert isinstance(tb,gtk.TextBuffer)
|
||||||
|
ACRONYMS = self.config['ACRONYMS']
|
||||||
|
INVOKER = self.config['INVOKER']
|
||||||
|
t = tb.get_text(tb.get_start_iter(), tb.get_end_iter())
|
||||||
|
#log.debug('%s %d'%(t, len(t)))
|
||||||
|
if t and t[-1] == INVOKER:
|
||||||
|
#log.debug('changing msg text')
|
||||||
|
base, sep, head=t[:-1].rpartition(INVOKER)
|
||||||
|
log.debug('%s | %s | %s'%(base, sep, head))
|
||||||
|
if head in ACRONYMS:
|
||||||
|
head = ACRONYMS[head]
|
||||||
|
#log.debug('head: %s'%(head))
|
||||||
|
t = ''.join((base, sep, head, INVOKER))
|
||||||
|
#log.debug("setting text: '%s'"%(t))
|
||||||
|
gobject.idle_add(tb.set_text, t)
|
||||||
|
|
||||||
|
@log_calls('AcronymsExpanderPlugin')
|
||||||
|
def connect_with_chat_control_base(self, chat_control):
|
||||||
|
d = {}
|
||||||
|
tv = chat_control.msg_textview
|
||||||
|
tb = tv.get_buffer()
|
||||||
|
h_id = tb.connect('changed', self.textbuffer_live_acronym_expander)
|
||||||
|
d['h_id'] = h_id
|
||||||
|
|
||||||
|
chat_control.acronyms_expander_plugin_data = d
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@log_calls('AcronymsExpanderPlugin')
|
||||||
|
def disconnect_from_chat_control_base(self, chat_control):
|
||||||
|
d = chat_control.acronyms_expander_plugin_data
|
||||||
|
tv = chat_control.msg_textview
|
||||||
|
tv.get_buffer().disconnect(d['h_id'])
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
from plugin import BannerTweaksPlugin
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy toplevel-contextual -->
|
||||||
|
<object class="GtkWindow" id="window1">
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="banner_tweaks_config_vbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="border_width">9</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="show_banner_image_checkbutton">
|
||||||
|
<property name="label" translatable="yes">Display status icon</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">If checked, status icon will be displayed in chat window banner.</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="on_show_banner_image_checkbutton_toggled"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="show_banner_online_msg_checkbutton">
|
||||||
|
<property name="label" translatable="yes">Display status message of contact</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">If checked, status message of contact will be displayed in chat window banner.</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="on_show_banner_online_msg_checkbutton_toggled"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="show_banner_resource_checkbutton">
|
||||||
|
<property name="label" translatable="yes">Display resource name of contact</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">If checked, resource name of contact will be displayed in chat window banner.</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="on_show_banner_resource_checkbutton_toggled"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="banner_small_fonts_checkbutton">
|
||||||
|
<property name="label" translatable="yes">Use small fonts for contact name and resource name</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">If checked, smaller font will be used to display resource name and contact name in chat window banner.</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="on_banner_small_fonts_checkbutton_toggled"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -0,0 +1,205 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
'''
|
||||||
|
Adjustable chat window banner.
|
||||||
|
|
||||||
|
Includes tweaks to make it compact.
|
||||||
|
|
||||||
|
Based on patch by pb in ticket #4133:
|
||||||
|
http://trac.gajim.org/attachment/ticket/4133/gajim-chatbanneroptions-svn10008.patch
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 30 July 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
import gobject
|
||||||
|
import message_control
|
||||||
|
from common import i18n
|
||||||
|
from common import gajim
|
||||||
|
from common import helpers
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log, log_calls
|
||||||
|
from plugins.gui import GajimPluginConfigDialog
|
||||||
|
|
||||||
|
class BannerTweaksPlugin(GajimPlugin):
|
||||||
|
name = u'Banner Tweaks'
|
||||||
|
short_name = u'banner_tweaks'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Allows user to tweak chat window banner appearance (eg. make it compact).
|
||||||
|
|
||||||
|
Based on patch by pb in ticket #4133:
|
||||||
|
http://trac.gajim.org/attachment/ticket/4133'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('BannerTweaksPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = BannerTweaksPluginConfigDialog(self)
|
||||||
|
|
||||||
|
self.gui_extension_points = {
|
||||||
|
'chat_control_base_draw_banner': (self.chat_control_base_draw_banner_called,
|
||||||
|
self.chat_control_base_draw_banner_deactivation)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.config_default_values = {
|
||||||
|
'show_banner_image': (True, _('If True, Gajim will display a status icon in the banner of chat windows.')),
|
||||||
|
'show_banner_online_msg': (True, _('If True, Gajim will display the status message of the contact in the banner of chat windows.')),
|
||||||
|
'show_banner_resource': (False, _('If True, Gajim will display the resource name of the contact in the banner of chat windows.')),
|
||||||
|
'banner_small_fonts': (False, _('If True, Gajim will use small fonts for contact name and resource name in the banner of chat windows.')),
|
||||||
|
'old_chat_avatar_height': (52, _('chat_avatar_height value before plugin was activated')),
|
||||||
|
}
|
||||||
|
|
||||||
|
@log_calls('BannerTweaksPlugin')
|
||||||
|
def activate(self):
|
||||||
|
self.config['old_chat_avatar_height'] = gajim.config.get('chat_avatar_height')
|
||||||
|
#gajim.config.set('chat_avatar_height', 28)
|
||||||
|
|
||||||
|
@log_calls('BannerTweaksPlugin')
|
||||||
|
def deactivate(self):
|
||||||
|
gajim.config.set('chat_avatar_height', self.config['old_chat_avatar_height'])
|
||||||
|
|
||||||
|
@log_calls('BannerTweaksPlugin')
|
||||||
|
def chat_control_base_draw_banner_called(self, chat_control):
|
||||||
|
if not self.config['show_banner_online_msg']:
|
||||||
|
chat_control.banner_status_label.hide()
|
||||||
|
chat_control.banner_status_label.set_no_show_all(True)
|
||||||
|
status_text = ''
|
||||||
|
chat_control.banner_status_label.set_markup(status_text)
|
||||||
|
|
||||||
|
if not self.config['show_banner_image']:
|
||||||
|
banner_status_img = chat_control.xml.get_object('banner_status_image')
|
||||||
|
banner_status_img.clear()
|
||||||
|
|
||||||
|
# TODO: part below repeats a lot of code from ChatControl.draw_banner_text()
|
||||||
|
# This could be rewritten using re module: getting markup text from
|
||||||
|
# banner_name_label and replacing some elements based on plugin config.
|
||||||
|
# Would it be faster?
|
||||||
|
if self.config['show_banner_resource'] or self.config['banner_small_fonts']:
|
||||||
|
banner_name_label = chat_control.xml.get_object('banner_name_label')
|
||||||
|
label_text = banner_name_label.get_label()
|
||||||
|
|
||||||
|
contact = chat_control.contact
|
||||||
|
jid = contact.jid
|
||||||
|
|
||||||
|
name = contact.get_shown_name()
|
||||||
|
if chat_control.resource:
|
||||||
|
name += '/' + chat_control.resource
|
||||||
|
elif contact.resource and self.config['show_banner_resource']:
|
||||||
|
name += '/' + contact.resource
|
||||||
|
|
||||||
|
if chat_control.TYPE_ID == message_control.TYPE_PM:
|
||||||
|
name = _('%(nickname)s from group chat %(room_name)s') %\
|
||||||
|
{'nickname': name, 'room_name': chat_control.room_name}
|
||||||
|
name = gobject.markup_escape_text(name)
|
||||||
|
|
||||||
|
# We know our contacts nick, but if another contact has the same nick
|
||||||
|
# in another account we need to also display the account.
|
||||||
|
# except if we are talking to two different resources of the same contact
|
||||||
|
acct_info = ''
|
||||||
|
for account in gajim.contacts.get_accounts():
|
||||||
|
if account == chat_control.account:
|
||||||
|
continue
|
||||||
|
if acct_info: # We already found a contact with same nick
|
||||||
|
break
|
||||||
|
for jid in gajim.contacts.get_jid_list(account):
|
||||||
|
other_contact_ = \
|
||||||
|
gajim.contacts.get_first_contact_from_jid(account, jid)
|
||||||
|
if other_contact_.get_shown_name() == chat_control.contact.get_shown_name():
|
||||||
|
acct_info = ' (%s)' % \
|
||||||
|
gobject.markup_escape_text(chat_control.account)
|
||||||
|
break
|
||||||
|
|
||||||
|
font_attrs, font_attrs_small = chat_control.get_font_attrs()
|
||||||
|
if self.config['banner_small_fonts']:
|
||||||
|
font_attrs = font_attrs_small
|
||||||
|
|
||||||
|
st = gajim.config.get('displayed_chat_state_notifications')
|
||||||
|
cs = contact.chatstate
|
||||||
|
if cs and st in ('composing_only', 'all'):
|
||||||
|
if contact.show == 'offline':
|
||||||
|
chatstate = ''
|
||||||
|
elif contact.composing_xep == 'XEP-0085':
|
||||||
|
if st == 'all' or cs == 'composing':
|
||||||
|
chatstate = helpers.get_uf_chatstate(cs)
|
||||||
|
else:
|
||||||
|
chatstate = ''
|
||||||
|
elif contact.composing_xep == 'XEP-0022':
|
||||||
|
if cs in ('composing', 'paused'):
|
||||||
|
# only print composing, paused
|
||||||
|
chatstate = helpers.get_uf_chatstate(cs)
|
||||||
|
else:
|
||||||
|
chatstate = ''
|
||||||
|
else:
|
||||||
|
# When does that happen ? See [7797] and [7804]
|
||||||
|
chatstate = helpers.get_uf_chatstate(cs)
|
||||||
|
|
||||||
|
label_text = '<span %s>%s</span><span %s>%s %s</span>' % \
|
||||||
|
(font_attrs, name, font_attrs_small, acct_info, chatstate)
|
||||||
|
else:
|
||||||
|
# weight="heavy" size="x-large"
|
||||||
|
label_text = '<span %s>%s</span><span %s>%s</span>' % \
|
||||||
|
(font_attrs, name, font_attrs_small, acct_info)
|
||||||
|
|
||||||
|
banner_name_label.set_markup(label_text)
|
||||||
|
|
||||||
|
@log_calls('BannerTweaksPlugin')
|
||||||
|
def chat_control_base_draw_banner_deactivation(self, chat_control):
|
||||||
|
pass
|
||||||
|
#chat_control.draw_banner()
|
||||||
|
|
||||||
|
class BannerTweaksPluginConfigDialog(GajimPluginConfigDialog):
|
||||||
|
def init(self):
|
||||||
|
self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
|
||||||
|
'config_dialog.ui')
|
||||||
|
self.xml = gtk.Builder()
|
||||||
|
self.xml.set_translation_domain(i18n.APP)
|
||||||
|
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
|
||||||
|
['banner_tweaks_config_vbox'])
|
||||||
|
self.config_vbox = self.xml.get_object('banner_tweaks_config_vbox')
|
||||||
|
self.child.pack_start(self.config_vbox)
|
||||||
|
|
||||||
|
self.show_banner_image_checkbutton = self.xml.get_object('show_banner_image_checkbutton')
|
||||||
|
self.show_banner_online_msg_checkbutton = self.xml.get_object('show_banner_online_msg_checkbutton')
|
||||||
|
self.show_banner_resource_checkbutton = self.xml.get_object('show_banner_resource_checkbutton')
|
||||||
|
self.banner_small_fonts_checkbutton = self.xml.get_object('banner_small_fonts_checkbutton')
|
||||||
|
|
||||||
|
self.xml.connect_signals(self)
|
||||||
|
|
||||||
|
def on_run(self):
|
||||||
|
self.show_banner_image_checkbutton.set_active(self.plugin.config['show_banner_image'])
|
||||||
|
self.show_banner_online_msg_checkbutton.set_active(self.plugin.config['show_banner_online_msg'])
|
||||||
|
self.show_banner_resource_checkbutton.set_active(self.plugin.config['show_banner_resource'])
|
||||||
|
self.banner_small_fonts_checkbutton.set_active(self.plugin.config['banner_small_fonts'])
|
||||||
|
|
||||||
|
def on_show_banner_image_checkbutton_toggled(self, button):
|
||||||
|
self.plugin.config['show_banner_image'] = button.get_active()
|
||||||
|
|
||||||
|
def on_show_banner_online_msg_checkbutton_toggled(self, button):
|
||||||
|
self.plugin.config['show_banner_online_msg'] = button.get_active()
|
||||||
|
|
||||||
|
def on_show_banner_resource_checkbutton_toggled(self, button):
|
||||||
|
self.plugin.config['show_banner_resource'] = button.get_active()
|
||||||
|
|
||||||
|
def on_banner_small_fonts_checkbutton_toggled(self, button):
|
||||||
|
self.plugin.config['banner_small_fonts'] = button.get_active()
|
|
@ -0,0 +1 @@
|
||||||
|
from plugin import DBusPlugin
|
|
@ -0,0 +1,738 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
## Copyright (C) 2005-2006 Yann Leboulanger <asterix@lagaule.org>
|
||||||
|
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
|
||||||
|
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
|
||||||
|
## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com>
|
||||||
|
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||||
|
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
|
||||||
|
## Copyright (C) 2007 Travis Shirk <travis@pobox.com>
|
||||||
|
## Copyright (C) 2008 Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
##
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
'''
|
||||||
|
D-BUS Support plugin.
|
||||||
|
|
||||||
|
Based on src/remote_control.py
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 8th August 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
import os
|
||||||
|
import new
|
||||||
|
|
||||||
|
import gobject
|
||||||
|
|
||||||
|
|
||||||
|
from common import dbus_support
|
||||||
|
if dbus_support.supported:
|
||||||
|
import dbus
|
||||||
|
if dbus_support:
|
||||||
|
INTERFACE = 'org.gajim.dbusplugin.RemoteInterface'
|
||||||
|
OBJ_PATH = '/org/gajim/dbusplugin/RemoteObject'
|
||||||
|
SERVICE = 'org.gajim.dbusplugin'
|
||||||
|
|
||||||
|
import dbus.service
|
||||||
|
import dbus.glib
|
||||||
|
# type mapping
|
||||||
|
|
||||||
|
# in most cases it is a utf-8 string
|
||||||
|
DBUS_STRING = dbus.String
|
||||||
|
|
||||||
|
# general type (for use in dicts, where all values should have the same type)
|
||||||
|
DBUS_BOOLEAN = dbus.Boolean
|
||||||
|
DBUS_DOUBLE = dbus.Double
|
||||||
|
DBUS_INT32 = dbus.Int32
|
||||||
|
# dictionary with string key and binary value
|
||||||
|
DBUS_DICT_SV = lambda : dbus.Dictionary({}, signature="sv")
|
||||||
|
# dictionary with string key and value
|
||||||
|
DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss")
|
||||||
|
# empty type (there is no equivalent of None on D-Bus, but historically gajim
|
||||||
|
# used 0 instead)
|
||||||
|
DBUS_NONE = lambda : dbus.Int32(0)
|
||||||
|
|
||||||
|
def get_dbus_struct(obj):
|
||||||
|
''' recursively go through all the items and replace
|
||||||
|
them with their casted dbus equivalents
|
||||||
|
'''
|
||||||
|
if obj is None:
|
||||||
|
return DBUS_NONE()
|
||||||
|
if isinstance(obj, (unicode, str)):
|
||||||
|
return DBUS_STRING(obj)
|
||||||
|
if isinstance(obj, int):
|
||||||
|
return DBUS_INT32(obj)
|
||||||
|
if isinstance(obj, float):
|
||||||
|
return DBUS_DOUBLE(obj)
|
||||||
|
if isinstance(obj, bool):
|
||||||
|
return DBUS_BOOLEAN(obj)
|
||||||
|
if isinstance(obj, (list, tuple)):
|
||||||
|
result = dbus.Array([get_dbus_struct(i) for i in obj],
|
||||||
|
signature='v')
|
||||||
|
if result == []:
|
||||||
|
return DBUS_NONE()
|
||||||
|
return result
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
result = DBUS_DICT_SV()
|
||||||
|
for key, value in obj.items():
|
||||||
|
result[DBUS_STRING(key)] = get_dbus_struct(value)
|
||||||
|
if result == {}:
|
||||||
|
return DBUS_NONE()
|
||||||
|
return result
|
||||||
|
# unknown type
|
||||||
|
return DBUS_NONE()
|
||||||
|
|
||||||
|
class SignalObject(dbus.service.Object):
|
||||||
|
''' Local object definition for /org/gajim/dbus/RemoteObject.
|
||||||
|
(This docstring is not be visible, because the clients can access only the remote object.)'''
|
||||||
|
|
||||||
|
def __init__(self, bus_name):
|
||||||
|
self.first_show = True
|
||||||
|
self.vcard_account = None
|
||||||
|
|
||||||
|
# register our dbus API
|
||||||
|
dbus.service.Object.__init__(self, bus_name, OBJ_PATH)
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def Roster(self, account_and_data):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def AccountPresence(self, status_and_account):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def ContactPresence(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def ContactAbsence(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def ContactStatus(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def NewMessage(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def Subscribe(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def Subscribed(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def Unsubscribed(self, account_and_jid):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def NewAccount(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def VcardInfo(self, account_and_vcard):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def LastStatusTime(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def OsInfo(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def GCPresence(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def GCMessage(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def RosterInfo(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@dbus.service.signal(INTERFACE, signature='av')
|
||||||
|
def NewGmail(self, account_and_array):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def raise_signal(self, signal, arg):
|
||||||
|
'''raise a signal, with a single argument of unspecified type
|
||||||
|
Instead of obj.raise_signal("Foo", bar), use obj.Foo(bar).'''
|
||||||
|
getattr(self, signal)(arg)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
|
||||||
|
def get_status(self, account):
|
||||||
|
'''Returns status (show to be exact) which is the global one
|
||||||
|
unless account is given'''
|
||||||
|
if not account:
|
||||||
|
# If user did not ask for account, returns the global status
|
||||||
|
return DBUS_STRING(helpers.get_global_show())
|
||||||
|
# return show for the given account
|
||||||
|
index = gajim.connections[account].connected
|
||||||
|
return DBUS_STRING(gajim.SHOW_LIST[index])
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
|
||||||
|
def get_status_message(self, account):
|
||||||
|
'''Returns status which is the global one
|
||||||
|
unless account is given'''
|
||||||
|
if not account:
|
||||||
|
# If user did not ask for account, returns the global status
|
||||||
|
return DBUS_STRING(str(helpers.get_global_status()))
|
||||||
|
# return show for the given account
|
||||||
|
status = gajim.connections[account].status
|
||||||
|
return DBUS_STRING(status)
|
||||||
|
|
||||||
|
def _get_account_and_contact(self, account, jid):
|
||||||
|
'''get the account (if not given) and contact instance from jid'''
|
||||||
|
connected_account = None
|
||||||
|
contact = None
|
||||||
|
accounts = gajim.contacts.get_accounts()
|
||||||
|
# if there is only one account in roster, take it as default
|
||||||
|
# if user did not ask for account
|
||||||
|
if not account and len(accounts) == 1:
|
||||||
|
account = accounts[0]
|
||||||
|
if account:
|
||||||
|
if gajim.connections[account].connected > 1: # account is connected
|
||||||
|
connected_account = account
|
||||||
|
contact = gajim.contacts.get_contact_with_highest_priority(account,
|
||||||
|
jid)
|
||||||
|
else:
|
||||||
|
for account in accounts:
|
||||||
|
contact = gajim.contacts.get_contact_with_highest_priority(account,
|
||||||
|
jid)
|
||||||
|
if contact and gajim.connections[account].connected > 1:
|
||||||
|
# account is connected
|
||||||
|
connected_account = account
|
||||||
|
break
|
||||||
|
if not contact:
|
||||||
|
contact = jid
|
||||||
|
|
||||||
|
return connected_account, contact
|
||||||
|
|
||||||
|
def _get_account_for_groupchat(self, account, room_jid):
|
||||||
|
'''get the account which is connected to groupchat (if not given)
|
||||||
|
or check if the given account is connected to the groupchat'''
|
||||||
|
connected_account = None
|
||||||
|
accounts = gajim.contacts.get_accounts()
|
||||||
|
# if there is only one account in roster, take it as default
|
||||||
|
# if user did not ask for account
|
||||||
|
if not account and len(accounts) == 1:
|
||||||
|
account = accounts[0]
|
||||||
|
if account:
|
||||||
|
if gajim.connections[account].connected > 1 and \
|
||||||
|
room_jid in gajim.gc_connected[account] and \
|
||||||
|
gajim.gc_connected[account][room_jid]:
|
||||||
|
# account and groupchat are connected
|
||||||
|
connected_account = account
|
||||||
|
else:
|
||||||
|
for account in accounts:
|
||||||
|
if gajim.connections[account].connected > 1 and \
|
||||||
|
room_jid in gajim.gc_connected[account] and \
|
||||||
|
gajim.gc_connected[account][room_jid]:
|
||||||
|
# account and groupchat are connected
|
||||||
|
connected_account = account
|
||||||
|
break
|
||||||
|
return connected_account
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
|
||||||
|
def send_file(self, file_path, jid, account):
|
||||||
|
'''send file, located at 'file_path' to 'jid', using account
|
||||||
|
(optional) 'account' '''
|
||||||
|
jid = self._get_real_jid(jid, account)
|
||||||
|
connected_account, contact = self._get_account_and_contact(account, jid)
|
||||||
|
|
||||||
|
if connected_account:
|
||||||
|
if file_path[:7] == 'file://':
|
||||||
|
file_path=file_path[7:]
|
||||||
|
if os.path.isfile(file_path): # is it file?
|
||||||
|
gajim.interface.instances['file_transfers'].send_file(
|
||||||
|
connected_account, contact, file_path)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
|
||||||
|
def _send_message(self, jid, message, keyID, account, type = 'chat',
|
||||||
|
subject = None):
|
||||||
|
'''can be called from send_chat_message (default when send_message)
|
||||||
|
or send_single_message'''
|
||||||
|
if not jid or not message:
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
if not keyID:
|
||||||
|
keyID = ''
|
||||||
|
|
||||||
|
connected_account, contact = self._get_account_and_contact(account, jid)
|
||||||
|
if connected_account:
|
||||||
|
connection = gajim.connections[connected_account]
|
||||||
|
connection.send_message(jid, message, keyID, type, subject)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='b')
|
||||||
|
def send_chat_message(self, jid, message, keyID, account):
|
||||||
|
'''Send chat 'message' to 'jid', using account (optional) 'account'.
|
||||||
|
if keyID is specified, encrypt the message with the pgp key '''
|
||||||
|
jid = self._get_real_jid(jid, account)
|
||||||
|
return self._send_message(jid, message, keyID, account)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='sssss', out_signature='b')
|
||||||
|
def send_single_message(self, jid, subject, message, keyID, account):
|
||||||
|
'''Send single 'message' to 'jid', using account (optional) 'account'.
|
||||||
|
if keyID is specified, encrypt the message with the pgp key '''
|
||||||
|
jid = self._get_real_jid(jid, account)
|
||||||
|
return self._send_message(jid, message, keyID, account, type, subject)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
|
||||||
|
def send_groupchat_message(self, room_jid, message, account):
|
||||||
|
'''Send 'message' to groupchat 'room_jid',
|
||||||
|
using account (optional) 'account'.'''
|
||||||
|
if not room_jid or not message:
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
connected_account = self._get_account_for_groupchat(account, room_jid)
|
||||||
|
if connected_account:
|
||||||
|
connection = gajim.connections[connected_account]
|
||||||
|
connection.send_gc_message(room_jid, message)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
|
||||||
|
def open_chat(self, jid, account):
|
||||||
|
'''Shows the tabbed window for new message to 'jid', using account
|
||||||
|
(optional) 'account' '''
|
||||||
|
if not jid:
|
||||||
|
raise MissingArgument
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
jid = self._get_real_jid(jid, account)
|
||||||
|
try:
|
||||||
|
jid = helpers.parse_jid(jid)
|
||||||
|
except:
|
||||||
|
# Jid is not conform, ignore it
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
|
||||||
|
if account:
|
||||||
|
accounts = [account]
|
||||||
|
else:
|
||||||
|
accounts = gajim.connections.keys()
|
||||||
|
if len(accounts) == 1:
|
||||||
|
account = accounts[0]
|
||||||
|
connected_account = None
|
||||||
|
first_connected_acct = None
|
||||||
|
for acct in accounts:
|
||||||
|
if gajim.connections[acct].connected > 1: # account is online
|
||||||
|
contact = gajim.contacts.get_first_contact_from_jid(acct, jid)
|
||||||
|
if gajim.interface.msg_win_mgr.has_window(jid, acct):
|
||||||
|
connected_account = acct
|
||||||
|
break
|
||||||
|
# jid is in roster
|
||||||
|
elif contact:
|
||||||
|
connected_account = acct
|
||||||
|
break
|
||||||
|
# we send the message to jid not in roster, because account is
|
||||||
|
# specified, or there is only one account
|
||||||
|
elif account:
|
||||||
|
connected_account = acct
|
||||||
|
elif first_connected_acct is None:
|
||||||
|
first_connected_acct = acct
|
||||||
|
|
||||||
|
# if jid is not a conntact, open-chat with first connected account
|
||||||
|
if connected_account is None and first_connected_acct:
|
||||||
|
connected_account = first_connected_acct
|
||||||
|
|
||||||
|
if connected_account:
|
||||||
|
gajim.interface.new_chat_from_jid(connected_account, jid)
|
||||||
|
# preserve the 'steal focus preservation'
|
||||||
|
win = gajim.interface.msg_win_mgr.get_window(jid,
|
||||||
|
connected_account).window
|
||||||
|
if win.get_property('visible'):
|
||||||
|
win.window.focus()
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
|
||||||
|
def change_status(self, status, message, account):
|
||||||
|
''' change_status(status, message, account). account is optional -
|
||||||
|
if not specified status is changed for all accounts. '''
|
||||||
|
if status not in ('offline', 'online', 'chat',
|
||||||
|
'away', 'xa', 'dnd', 'invisible'):
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
if account:
|
||||||
|
gobject.idle_add(gajim.interface.roster.send_status, account,
|
||||||
|
status, message)
|
||||||
|
else:
|
||||||
|
# account not specified, so change the status of all accounts
|
||||||
|
for acc in gajim.contacts.get_accounts():
|
||||||
|
if not gajim.config.get_per('accounts', acc,
|
||||||
|
'sync_with_global_status'):
|
||||||
|
continue
|
||||||
|
gobject.idle_add(gajim.interface.roster.send_status, acc,
|
||||||
|
status, message)
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='')
|
||||||
|
def show_next_pending_event(self):
|
||||||
|
'''Show the window(s) with next pending event in tabbed/group chats.'''
|
||||||
|
if gajim.events.get_nb_events():
|
||||||
|
gajim.interface.systray.handle_first_event()
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{sv}')
|
||||||
|
def contact_info(self, jid):
|
||||||
|
'''get vcard info for a contact. Return cached value of the vcard.
|
||||||
|
'''
|
||||||
|
if not isinstance(jid, unicode):
|
||||||
|
jid = unicode(jid)
|
||||||
|
if not jid:
|
||||||
|
raise MissingArgument
|
||||||
|
return DBUS_DICT_SV()
|
||||||
|
jid = self._get_real_jid(jid)
|
||||||
|
|
||||||
|
cached_vcard = gajim.connections.values()[0].get_cached_vcard(jid)
|
||||||
|
if cached_vcard:
|
||||||
|
return get_dbus_struct(cached_vcard)
|
||||||
|
|
||||||
|
# return empty dict
|
||||||
|
return DBUS_DICT_SV()
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='as')
|
||||||
|
def list_accounts(self):
|
||||||
|
'''list register accounts'''
|
||||||
|
result = gajim.contacts.get_accounts()
|
||||||
|
result_array = dbus.Array([], signature='s')
|
||||||
|
if result and len(result) > 0:
|
||||||
|
for account in result:
|
||||||
|
result_array.append(DBUS_STRING(account))
|
||||||
|
return result_array
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{ss}')
|
||||||
|
def account_info(self, account):
|
||||||
|
'''show info on account: resource, jid, nick, prio, message'''
|
||||||
|
result = DBUS_DICT_SS()
|
||||||
|
if gajim.connections.has_key(account):
|
||||||
|
# account is valid
|
||||||
|
con = gajim.connections[account]
|
||||||
|
index = con.connected
|
||||||
|
result['status'] = DBUS_STRING(gajim.SHOW_LIST[index])
|
||||||
|
result['name'] = DBUS_STRING(con.name)
|
||||||
|
result['jid'] = DBUS_STRING(gajim.get_jid_from_account(con.name))
|
||||||
|
result['message'] = DBUS_STRING(con.status)
|
||||||
|
result['priority'] = DBUS_STRING(unicode(con.priority))
|
||||||
|
result['resource'] = DBUS_STRING(unicode(gajim.config.get_per(
|
||||||
|
'accounts', con.name, 'resource')))
|
||||||
|
return result
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='aa{sv}')
|
||||||
|
def list_contacts(self, account):
|
||||||
|
'''list all contacts in the roster. If the first argument is specified,
|
||||||
|
then return the contacts for the specified account'''
|
||||||
|
result = dbus.Array([], signature='aa{sv}')
|
||||||
|
accounts = gajim.contacts.get_accounts()
|
||||||
|
if len(accounts) == 0:
|
||||||
|
return result
|
||||||
|
if account:
|
||||||
|
accounts_to_search = [account]
|
||||||
|
else:
|
||||||
|
accounts_to_search = accounts
|
||||||
|
for acct in accounts_to_search:
|
||||||
|
if acct in accounts:
|
||||||
|
for jid in gajim.contacts.get_jid_list(acct):
|
||||||
|
item = self._contacts_as_dbus_structure(
|
||||||
|
gajim.contacts.get_contacts(acct, jid))
|
||||||
|
if item:
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='')
|
||||||
|
def toggle_roster_appearance(self):
|
||||||
|
''' shows/hides the roster window '''
|
||||||
|
win = gajim.interface.roster.window
|
||||||
|
if win.get_property('visible'):
|
||||||
|
gobject.idle_add(win.hide)
|
||||||
|
else:
|
||||||
|
win.present()
|
||||||
|
# preserve the 'steal focus preservation'
|
||||||
|
if self._is_first():
|
||||||
|
win.window.focus()
|
||||||
|
else:
|
||||||
|
win.window.focus(long(time()))
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='')
|
||||||
|
def toggle_ipython(self):
|
||||||
|
''' shows/hides the ipython window '''
|
||||||
|
win = gajim.ipython_window
|
||||||
|
if win:
|
||||||
|
if win.window.is_visible():
|
||||||
|
gobject.idle_add(win.hide)
|
||||||
|
else:
|
||||||
|
win.show_all()
|
||||||
|
win.present()
|
||||||
|
else:
|
||||||
|
gajim.interface.create_ipython_window()
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='a{ss}')
|
||||||
|
def prefs_list(self):
|
||||||
|
prefs_dict = DBUS_DICT_SS()
|
||||||
|
def get_prefs(data, name, path, value):
|
||||||
|
if value is None:
|
||||||
|
return
|
||||||
|
key = ''
|
||||||
|
if path is not None:
|
||||||
|
for node in path:
|
||||||
|
key += node + '#'
|
||||||
|
key += name
|
||||||
|
prefs_dict[DBUS_STRING(key)] = DBUS_STRING(value[1])
|
||||||
|
gajim.config.foreach(get_prefs)
|
||||||
|
return prefs_dict
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='b')
|
||||||
|
def prefs_store(self):
|
||||||
|
try:
|
||||||
|
gajim.interface.save_config()
|
||||||
|
except Exception, e:
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
|
||||||
|
def prefs_del(self, key):
|
||||||
|
if not key:
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
key_path = key.split('#', 2)
|
||||||
|
if len(key_path) != 3:
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
if key_path[2] == '*':
|
||||||
|
gajim.config.del_per(key_path[0], key_path[1])
|
||||||
|
else:
|
||||||
|
gajim.config.del_per(key_path[0], key_path[1], key_path[2])
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
|
||||||
|
def prefs_put(self, key):
|
||||||
|
if not key:
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
key_path = key.split('#', 2)
|
||||||
|
if len(key_path) < 3:
|
||||||
|
subname, value = key.split('=', 1)
|
||||||
|
gajim.config.set(subname, value)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
subname, value = key_path[2].split('=', 1)
|
||||||
|
gajim.config.set_per(key_path[0], key_path[1], subname, value)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
|
||||||
|
def add_contact(self, jid, account):
|
||||||
|
if account:
|
||||||
|
if account in gajim.connections and \
|
||||||
|
gajim.connections[account].connected > 1:
|
||||||
|
# if given account is active, use it
|
||||||
|
AddNewContactWindow(account = account, jid = jid)
|
||||||
|
else:
|
||||||
|
# wrong account
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
else:
|
||||||
|
# if account is not given, show account combobox
|
||||||
|
AddNewContactWindow(account = None, jid = jid)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
|
||||||
|
def remove_contact(self, jid, account):
|
||||||
|
jid = self._get_real_jid(jid, account)
|
||||||
|
accounts = gajim.contacts.get_accounts()
|
||||||
|
|
||||||
|
# if there is only one account in roster, take it as default
|
||||||
|
if account:
|
||||||
|
accounts = [account]
|
||||||
|
contact_exists = False
|
||||||
|
for account in accounts:
|
||||||
|
contacts = gajim.contacts.get_contacts(account, jid)
|
||||||
|
if contacts:
|
||||||
|
gajim.connections[account].unsubscribe(jid)
|
||||||
|
for contact in contacts:
|
||||||
|
gajim.interface.roster.remove_contact(contact, account)
|
||||||
|
gajim.contacts.remove_jid(account, jid)
|
||||||
|
contact_exists = True
|
||||||
|
return DBUS_BOOLEAN(contact_exists)
|
||||||
|
|
||||||
|
def _is_first(self):
|
||||||
|
if self.first_show:
|
||||||
|
self.first_show = False
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _get_real_jid(self, jid, account = None):
|
||||||
|
'''get the real jid from the given one: removes xmpp: or get jid from nick
|
||||||
|
if account is specified, search only in this account
|
||||||
|
'''
|
||||||
|
if account:
|
||||||
|
accounts = [account]
|
||||||
|
else:
|
||||||
|
accounts = gajim.connections.keys()
|
||||||
|
if jid.startswith('xmpp:'):
|
||||||
|
return jid[5:] # len('xmpp:') = 5
|
||||||
|
nick_in_roster = None # Is jid a nick ?
|
||||||
|
for account in accounts:
|
||||||
|
# Does jid exists in roster of one account ?
|
||||||
|
if gajim.contacts.get_contacts(account, jid):
|
||||||
|
return jid
|
||||||
|
if not nick_in_roster:
|
||||||
|
# look in all contact if one has jid as nick
|
||||||
|
for jid_ in gajim.contacts.get_jid_list(account):
|
||||||
|
c = gajim.contacts.get_contacts(account, jid_)
|
||||||
|
if c[0].name == jid:
|
||||||
|
nick_in_roster = jid_
|
||||||
|
break
|
||||||
|
if nick_in_roster:
|
||||||
|
# We have not found jid in roster, but we found is as a nick
|
||||||
|
return nick_in_roster
|
||||||
|
# We have not found it as jid nor as nick, probably a not in roster jid
|
||||||
|
return jid
|
||||||
|
|
||||||
|
def _contacts_as_dbus_structure(self, contacts):
|
||||||
|
''' get info from list of Contact objects and create dbus dict '''
|
||||||
|
if not contacts:
|
||||||
|
return None
|
||||||
|
prim_contact = None # primary contact
|
||||||
|
for contact in contacts:
|
||||||
|
if prim_contact is None or contact.priority > prim_contact.priority:
|
||||||
|
prim_contact = contact
|
||||||
|
contact_dict = DBUS_DICT_SV()
|
||||||
|
contact_dict['name'] = DBUS_STRING(prim_contact.name)
|
||||||
|
contact_dict['show'] = DBUS_STRING(prim_contact.show)
|
||||||
|
contact_dict['jid'] = DBUS_STRING(prim_contact.jid)
|
||||||
|
if prim_contact.keyID:
|
||||||
|
keyID = None
|
||||||
|
if len(prim_contact.keyID) == 8:
|
||||||
|
keyID = prim_contact.keyID
|
||||||
|
elif len(prim_contact.keyID) == 16:
|
||||||
|
keyID = prim_contact.keyID[8:]
|
||||||
|
if keyID:
|
||||||
|
contact_dict['openpgp'] = keyID
|
||||||
|
contact_dict['resources'] = dbus.Array([], signature='(sis)')
|
||||||
|
for contact in contacts:
|
||||||
|
resource_props = dbus.Struct((DBUS_STRING(contact.resource),
|
||||||
|
dbus.Int32(contact.priority), DBUS_STRING(contact.status)))
|
||||||
|
contact_dict['resources'].append(resource_props)
|
||||||
|
contact_dict['groups'] = dbus.Array([], signature='(s)')
|
||||||
|
for group in prim_contact.groups:
|
||||||
|
contact_dict['groups'].append((DBUS_STRING(group),))
|
||||||
|
return contact_dict
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='s')
|
||||||
|
def get_unread_msgs_number(self):
|
||||||
|
return DBUS_STRING(str(gajim.events.get_nb_events()))
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
|
||||||
|
def start_chat(self, account):
|
||||||
|
if not account:
|
||||||
|
# error is shown in gajim-remote check_arguments(..)
|
||||||
|
return DBUS_BOOLEAN(False)
|
||||||
|
NewChatDialog(account)
|
||||||
|
return DBUS_BOOLEAN(True)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='')
|
||||||
|
def send_xml(self, xml, account):
|
||||||
|
if account:
|
||||||
|
gajim.connections[account].send_stanza(xml)
|
||||||
|
else:
|
||||||
|
for acc in gajim.contacts.get_accounts():
|
||||||
|
gajim.connections[acc].send_stanza(xml)
|
||||||
|
|
||||||
|
@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='')
|
||||||
|
def join_room(self, room_jid, nick, password, account):
|
||||||
|
if not account:
|
||||||
|
# get the first connected account
|
||||||
|
accounts = gajim.connections.keys()
|
||||||
|
for acct in accounts:
|
||||||
|
if gajim.account_is_connected(acct):
|
||||||
|
account = acct
|
||||||
|
break
|
||||||
|
if not account:
|
||||||
|
return
|
||||||
|
if not nick:
|
||||||
|
nick = ''
|
||||||
|
gajim.interface.instances[account]['join_gc'] = \
|
||||||
|
JoinGroupchatWindow(account, room_jid, nick)
|
||||||
|
else:
|
||||||
|
gajim.interface.join_gc_room(account, room_jid, nick, password)
|
||||||
|
|
||||||
|
from common import gajim
|
||||||
|
from common import helpers
|
||||||
|
from time import time
|
||||||
|
from dialogs import AddNewContactWindow, NewChatDialog, JoinGroupchatWindow
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log_calls, log
|
||||||
|
from common import ged
|
||||||
|
|
||||||
|
class DBusPlugin(GajimPlugin):
|
||||||
|
name = u'D-Bus Support'
|
||||||
|
short_name = u'dbus'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''D-Bus support. Based on remote_control module from
|
||||||
|
Gajim core but uses new events handling system.'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('DBusPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = None
|
||||||
|
#self.gui_extension_points = {}
|
||||||
|
#self.config_default_values = {}
|
||||||
|
|
||||||
|
self.events_names = ['Roster', 'AccountPresence', 'ContactPresence',
|
||||||
|
'ContactAbsence', 'ContactStatus', 'NewMessage',
|
||||||
|
'Subscribe', 'Subscribed', 'Unsubscribed',
|
||||||
|
'NewAccount', 'VcardInfo', 'LastStatusTime',
|
||||||
|
'OsInfo', 'GCPresence', 'GCMessage', 'RosterInfo',
|
||||||
|
'NewGmail']
|
||||||
|
|
||||||
|
self.signal_object = None
|
||||||
|
|
||||||
|
self.events_handlers = {}
|
||||||
|
self._set_handling_methods()
|
||||||
|
|
||||||
|
@log_calls('DBusPlugin')
|
||||||
|
def activate(self):
|
||||||
|
session_bus = dbus_support.session_bus.SessionBus()
|
||||||
|
|
||||||
|
bus_name = dbus.service.BusName(SERVICE, bus=session_bus)
|
||||||
|
self.signal_object = SignalObject(bus_name)
|
||||||
|
|
||||||
|
@log_calls('DBusPlugin')
|
||||||
|
def deactivate(self):
|
||||||
|
self.signal_object.remove_from_connection()
|
||||||
|
self.signal_object = None
|
||||||
|
|
||||||
|
@log_calls('DBusPlugin')
|
||||||
|
def _set_handling_methods(self):
|
||||||
|
for event_name in self.events_names:
|
||||||
|
setattr(self, event_name,
|
||||||
|
new.instancemethod(
|
||||||
|
self._generate_handling_method(event_name),
|
||||||
|
self,
|
||||||
|
DBusPlugin))
|
||||||
|
self.events_handlers[event_name] = (ged.POSTCORE,
|
||||||
|
getattr(self, event_name))
|
||||||
|
|
||||||
|
def _generate_handling_method(self, event_name):
|
||||||
|
def handler(self, arg):
|
||||||
|
#print "Handler of event %s called"%(event_name)
|
||||||
|
if self.signal_object:
|
||||||
|
getattr(self.signal_object, event_name)(get_dbus_struct(arg))
|
||||||
|
|
||||||
|
return handler
|
|
@ -0,0 +1 @@
|
||||||
|
from plugin import EventsDumpPlugin
|
|
@ -0,0 +1,129 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
'''
|
||||||
|
Events Dump plugin.
|
||||||
|
|
||||||
|
Dumps info about selected events to console.
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 10th August 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import new
|
||||||
|
from pprint import pformat
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log_calls, log
|
||||||
|
from common import ged
|
||||||
|
|
||||||
|
class EventsDumpPlugin(GajimPlugin):
|
||||||
|
name = u'Events Dump'
|
||||||
|
short_name = u'events_dump'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Dumps info about selected events to console.'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('EventsDumpPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = None
|
||||||
|
#self.gui_extension_points = {}
|
||||||
|
#self.config_default_values = {}
|
||||||
|
events_from_old_dbus_support = [
|
||||||
|
'Roster', 'AccountPresence', 'ContactPresence',
|
||||||
|
'ContactAbsence', 'ContactStatus', 'NewMessage',
|
||||||
|
'Subscribe', 'Subscribed', 'Unsubscribed',
|
||||||
|
'NewAccount', 'VcardInfo', 'LastStatusTime',
|
||||||
|
'OsInfo', 'GCPresence', 'GCMessage', 'RosterInfo',
|
||||||
|
'NewGmail']
|
||||||
|
|
||||||
|
events_from_src_gajim = [
|
||||||
|
'ROSTER', 'WARNING', 'ERROR',
|
||||||
|
'INFORMATION', 'ERROR_ANSWER', 'STATUS',
|
||||||
|
'NOTIFY', 'MSGERROR', 'MSGSENT', 'MSGNOTSENT',
|
||||||
|
'SUBSCRIBED', 'UNSUBSCRIBED', 'SUBSCRIBE',
|
||||||
|
'AGENT_ERROR_INFO', 'AGENT_ERROR_ITEMS',
|
||||||
|
'AGENT_REMOVED', 'REGISTER_AGENT_INFO',
|
||||||
|
'AGENT_INFO_ITEMS', 'AGENT_INFO_INFO',
|
||||||
|
'QUIT', 'NEW_ACC_CONNECTED',
|
||||||
|
'NEW_ACC_NOT_CONNECTED', 'ACC_OK', 'ACC_NOT_OK',
|
||||||
|
'MYVCARD', 'VCARD', 'LAST_STATUS_TIME', 'OS_INFO',
|
||||||
|
'GC_NOTIFY', 'GC_MSG', 'GC_SUBJECT', 'GC_CONFIG',
|
||||||
|
'GC_CONFIG_CHANGE', 'GC_INVITATION',
|
||||||
|
'GC_AFFILIATION', 'GC_PASSWORD_REQUIRED',
|
||||||
|
'BAD_PASSPHRASE', 'ROSTER_INFO', 'BOOKMARKS',
|
||||||
|
'CON_TYPE', 'CONNECTION_LOST', 'FILE_REQUEST',
|
||||||
|
'GMAIL_NOTIFY', 'FILE_REQUEST_ERROR',
|
||||||
|
'FILE_SEND_ERROR', 'STANZA_ARRIVED', 'STANZA_SENT',
|
||||||
|
'HTTP_AUTH', 'VCARD_PUBLISHED',
|
||||||
|
'VCARD_NOT_PUBLISHED', 'ASK_NEW_NICK', 'SIGNED_IN',
|
||||||
|
'METACONTACTS', 'ATOM_ENTRY', 'FAILED_DECRYPT',
|
||||||
|
'PRIVACY_LISTS_RECEIVED', 'PRIVACY_LIST_RECEIVED',
|
||||||
|
'PRIVACY_LISTS_ACTIVE_DEFAULT',
|
||||||
|
'PRIVACY_LIST_REMOVED', 'ZC_NAME_CONFLICT',
|
||||||
|
'PING_SENT', 'PING_REPLY', 'PING_ERROR',
|
||||||
|
'SEARCH_FORM', 'SEARCH_RESULT',
|
||||||
|
'RESOURCE_CONFLICT', 'PEP_CONFIG',
|
||||||
|
'UNIQUE_ROOM_ID_UNSUPPORTED',
|
||||||
|
'UNIQUE_ROOM_ID_SUPPORTED', 'SESSION_NEG',
|
||||||
|
'GPG_PASSWORD_REQUIRED', 'SSL_ERROR',
|
||||||
|
'FINGERPRINT_ERROR', 'PLAIN_CONNECTION',
|
||||||
|
'PUBSUB_NODE_REMOVED', 'PUBSUB_NODE_NOT_REMOVED']
|
||||||
|
|
||||||
|
network_events_from_core = ['raw-message-received',
|
||||||
|
'raw-iq-received',
|
||||||
|
'raw-pres-received']
|
||||||
|
|
||||||
|
network_events_generated_in_nec = [
|
||||||
|
'customized-message-received',
|
||||||
|
'more-customized-message-received',
|
||||||
|
'modify-only-message-received',
|
||||||
|
'enriched-chat-message-received']
|
||||||
|
|
||||||
|
self.events_names = []
|
||||||
|
self.events_names += network_events_from_core
|
||||||
|
self.events_names += network_events_generated_in_nec
|
||||||
|
|
||||||
|
self.events_handlers = {}
|
||||||
|
self._set_handling_methods()
|
||||||
|
|
||||||
|
@log_calls('EventsDumpPlugin')
|
||||||
|
def activate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('EventsDumpPlugin')
|
||||||
|
def deactivate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('EventsDumpPlugin')
|
||||||
|
def _set_handling_methods(self):
|
||||||
|
for event_name in self.events_names:
|
||||||
|
setattr(self, event_name,
|
||||||
|
new.instancemethod(
|
||||||
|
self._generate_handling_method(event_name),
|
||||||
|
self,
|
||||||
|
EventsDumpPlugin))
|
||||||
|
self.events_handlers[event_name] = (ged.POSTCORE,
|
||||||
|
getattr(self, event_name))
|
||||||
|
|
||||||
|
def _generate_handling_method(self, event_name):
|
||||||
|
def handler(self, *args):
|
||||||
|
print "Event '%s' occured. Arguments: %s\n\n===\n"%(event_name, pformat(args))
|
||||||
|
|
||||||
|
return handler
|
|
@ -0,0 +1 @@
|
||||||
|
from plugin import GoogleTranslationPlugin
|
|
@ -0,0 +1,118 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
'''
|
||||||
|
Google Translation plugin.
|
||||||
|
|
||||||
|
Translates (currently only incoming) messages using Google Translate.
|
||||||
|
|
||||||
|
:note: consider this as proof-of-concept
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 25th August 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import re
|
||||||
|
import urllib2
|
||||||
|
import new
|
||||||
|
from pprint import pformat
|
||||||
|
|
||||||
|
from common import helpers
|
||||||
|
from common import gajim
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log_calls, log
|
||||||
|
from common import ged
|
||||||
|
from common import nec
|
||||||
|
|
||||||
|
class GoogleTranslationPlugin(GajimPlugin):
|
||||||
|
name = u'Google Translation'
|
||||||
|
short_name = u'google_translation'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Translates (currently only incoming) messages using Google Translate.'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('GoogleTranslationPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = None
|
||||||
|
#self.gui_extension_points = {}
|
||||||
|
self.config_default_values = {'from_lang' : (u'en', _(u'Language of text to be translated')),
|
||||||
|
'to_lang' : (u'fr', _(u'Language to which translation will be made')),
|
||||||
|
'user_agent' : (u'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080213 Firefox/2.0.0.11',
|
||||||
|
_(u'User Agent data to be used with urllib2 when connecting to Google Translate service'))}
|
||||||
|
|
||||||
|
#self.events_handlers = {}
|
||||||
|
|
||||||
|
self.events = [GoogleTranslateMessageReceivedEvent]
|
||||||
|
|
||||||
|
self.translated_text_re = \
|
||||||
|
re.compile(r'google.language.callbacks.id100\(\'22\',{"translatedText":"(?P<text>[^"]*)"}, 200, null, 200\)')
|
||||||
|
|
||||||
|
@log_calls('GoogleTranslationPlugin')
|
||||||
|
def translate_text(self, text, from_lang, to_lang):
|
||||||
|
text = self.prepare_text_for_url(text)
|
||||||
|
headers = { 'User-Agent' : self.config['user_agent'] }
|
||||||
|
translation_url = u'http://www.google.com/uds/Gtranslate?callback=google.language.callbacks.id100&context=22&q=%(text)s&langpair=%(from_lang)s%%7C%(to_lang)s&key=notsupplied&v=1.0'%locals()
|
||||||
|
|
||||||
|
request = urllib2.Request(translation_url, headers=headers)
|
||||||
|
response = urllib2.urlopen(request)
|
||||||
|
results = response.read()
|
||||||
|
|
||||||
|
translated_text = self.translated_text_re.search(results).group('text')
|
||||||
|
|
||||||
|
return translated_text
|
||||||
|
|
||||||
|
@log_calls('GoogleTranslationPlugin')
|
||||||
|
def prepare_text_for_url(self, text):
|
||||||
|
'''
|
||||||
|
Converts text so it can be used within URL as query to Google Translate.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# There should be more replacements for plugin to work in any case:
|
||||||
|
char_replacements = { ' ' : '%20',
|
||||||
|
'+' : '%2B'}
|
||||||
|
|
||||||
|
for char, replacement in char_replacements.iteritems():
|
||||||
|
text = text.replace(char, replacement)
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
@log_calls('GoogleTranslationPlugin')
|
||||||
|
def activate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('GoogleTranslationPlugin')
|
||||||
|
def deactivate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class GoogleTranslateMessageReceivedEvent(nec.NetworkIncomingEvent):
|
||||||
|
name = 'google-translate-message-received'
|
||||||
|
base_network_events = ['raw-message-received']
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
msg_type = self.base_event.xmpp_msg.attrs.get('type', None)
|
||||||
|
if msg_type == u'chat':
|
||||||
|
msg_text = "".join(self.base_event.xmpp_msg.kids[0].data)
|
||||||
|
if msg_text:
|
||||||
|
from_lang = self.plugin.config['from_lang']
|
||||||
|
to_lang = self.plugin.config['to_lang']
|
||||||
|
self.base_event.xmpp_msg.kids[0].setData(
|
||||||
|
self.plugin.translate_text(msg_text, from_lang, to_lang))
|
||||||
|
|
||||||
|
return False # We only want to modify old event, not emit another,
|
||||||
|
# so we return False here.
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
from length_notifier import LengthNotifierPlugin
|
|
@ -0,0 +1,152 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy toplevel-contextual -->
|
||||||
|
<object class="GtkWindow" id="window1">
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="length_notifier_config_table">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="border_width">9</property>
|
||||||
|
<property name="n_rows">3</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<property name="column_spacing">7</property>
|
||||||
|
<property name="row_spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Message length at which notification is invoked.</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Message length:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options">GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Background color of text entry field in chat window when notification is invoked.</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Notification color:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options">GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). Use comma (without space) as separator. If empty plugin is used with every JID. </property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">JabberIDs to include:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options">GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="jids_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). Use comma (without space) as separator. If empty plugin is used with every JID. </property>
|
||||||
|
<signal name="editing_done" handler="on_jids_entry_editing_done"/>
|
||||||
|
<signal name="changed" handler="on_jids_entry_changed"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
<property name="y_options">GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkColorButton" id="notification_colorbutton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Background color of text entry field in chat window when notification is invoked.</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="title" translatable="yes">Pick a color for notification</property>
|
||||||
|
<property name="color">#000000000000</property>
|
||||||
|
<signal name="color_set" handler="on_notification_colorbutton_color_set"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options"></property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="message_length_spinbutton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Message length at which notification is invoked.</property>
|
||||||
|
<property name="width_chars">6</property>
|
||||||
|
<property name="snap_to_ticks">True</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value_changed" handler="on_message_length_spinbutton_value_changed"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="x_options">GTK_FILL</property>
|
||||||
|
<property name="y_options">GTK_FILL</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -0,0 +1,161 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
'''
|
||||||
|
Message length notifier plugin.
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 1st June 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
from common import i18n
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log, log_calls
|
||||||
|
from plugins.gui import GajimPluginConfigDialog
|
||||||
|
|
||||||
|
class LengthNotifierPlugin(GajimPlugin):
|
||||||
|
name = u'Message Length Notifier'
|
||||||
|
short_name = u'length_notifier'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Highlights message entry field in chat window when given length of message is exceeded.'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = LengthNotifierPluginConfigDialog(self)
|
||||||
|
|
||||||
|
self.gui_extension_points = {
|
||||||
|
'chat_control' : (self.connect_with_chat_control,
|
||||||
|
self.disconnect_from_chat_control)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.config_default_values = {'MESSAGE_WARNING_LENGTH' : (140, _('Message length at which notification is invoked.')),
|
||||||
|
'WARNING_COLOR' : ('#F0DB3E', _('Background color of text entry field in chat window when notification is invoked.')),
|
||||||
|
'JIDS' : ([], _('JabberIDs that plugin should be used with (eg. restrict only to one microblogging bot). If empty plugin is used with every JID. [not implemented]'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPlugin')
|
||||||
|
def textview_length_warning(self, tb, chat_control):
|
||||||
|
tv = chat_control.msg_textview
|
||||||
|
d = chat_control.length_notifier_plugin_data
|
||||||
|
t = tb.get_text(tb.get_start_iter(), tb.get_end_iter())
|
||||||
|
if t:
|
||||||
|
len_t = len(t)
|
||||||
|
#print("len_t: %d"%(len_t))
|
||||||
|
if len_t>self.config['MESSAGE_WARNING_LENGTH']:
|
||||||
|
if not d['prev_color']:
|
||||||
|
d['prev_color'] = tv.style.copy().base[gtk.STATE_NORMAL]
|
||||||
|
tv.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.config['WARNING_COLOR']))
|
||||||
|
elif d['prev_color']:
|
||||||
|
tv.modify_base(gtk.STATE_NORMAL, d['prev_color'])
|
||||||
|
d['prev_color'] = None
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPlugin')
|
||||||
|
def connect_with_chat_control(self, chat_control):
|
||||||
|
jid = chat_control.contact.jid
|
||||||
|
if self.jid_is_ok(jid):
|
||||||
|
d = {'prev_color' : None}
|
||||||
|
tv = chat_control.msg_textview
|
||||||
|
tb = tv.get_buffer()
|
||||||
|
h_id = tb.connect('changed', self.textview_length_warning, chat_control)
|
||||||
|
d['h_id'] = h_id
|
||||||
|
|
||||||
|
t = tb.get_text(tb.get_start_iter(), tb.get_end_iter())
|
||||||
|
if t:
|
||||||
|
len_t = len(t)
|
||||||
|
if len_t>self.config['MESSAGE_WARNING_LENGTH']:
|
||||||
|
d['prev_color'] = tv.style.copy().base[gtk.STATE_NORMAL]
|
||||||
|
tv.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.config['WARNING_COLOR']))
|
||||||
|
|
||||||
|
chat_control.length_notifier_plugin_data = d
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPlugin')
|
||||||
|
def disconnect_from_chat_control(self, chat_control):
|
||||||
|
try:
|
||||||
|
d = chat_control.length_notifier_plugin_data
|
||||||
|
tv = chat_control.msg_textview
|
||||||
|
tv.get_buffer().disconnect(d['h_id'])
|
||||||
|
if d['prev_color']:
|
||||||
|
tv.modify_base(gtk.STATE_NORMAL, d['prev_color'])
|
||||||
|
except AttributeError, error:
|
||||||
|
pass
|
||||||
|
#log.debug('Length Notifier Plugin was (probably) never connected with this chat window.\n Error: %s' % (error))
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPlugin')
|
||||||
|
def jid_is_ok(self, jid):
|
||||||
|
if jid in self.config['JIDS'] or not self.config['JIDS']:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
class LengthNotifierPluginConfigDialog(GajimPluginConfigDialog):
|
||||||
|
def init(self):
|
||||||
|
self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
|
||||||
|
'config_dialog.ui')
|
||||||
|
self.xml = gtk.Builder()
|
||||||
|
self.xml.set_translation_domain(i18n.APP)
|
||||||
|
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
|
||||||
|
['length_notifier_config_table'])
|
||||||
|
self.config_table = self.xml.get_object('length_notifier_config_table')
|
||||||
|
self.child.pack_start(self.config_table)
|
||||||
|
|
||||||
|
self.message_length_spinbutton = self.xml.get_object(
|
||||||
|
'message_length_spinbutton')
|
||||||
|
self.message_length_spinbutton.get_adjustment().set_all(140, 0, 500, 1,
|
||||||
|
10, 0)
|
||||||
|
self.notification_colorbutton = self.xml.get_object(
|
||||||
|
'notification_colorbutton')
|
||||||
|
self.jids_entry = self.xml.get_object('jids_entry')
|
||||||
|
|
||||||
|
self.xml.connect_signals(self)
|
||||||
|
|
||||||
|
def on_run(self):
|
||||||
|
self.message_length_spinbutton.set_value(self.plugin.config['MESSAGE_WARNING_LENGTH'])
|
||||||
|
self.notification_colorbutton.set_color(gtk.gdk.color_parse(self.plugin.config['WARNING_COLOR']))
|
||||||
|
#self.jids_entry.set_text(self.plugin.config['JIDS'])
|
||||||
|
self.jids_entry.set_text(','.join(self.plugin.config['JIDS']))
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPluginConfigDialog')
|
||||||
|
def on_message_length_spinbutton_value_changed(self, spinbutton):
|
||||||
|
self.plugin.config['MESSAGE_WARNING_LENGTH'] = spinbutton.get_value()
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPluginConfigDialog')
|
||||||
|
def on_notification_colorbutton_color_set(self, colorbutton):
|
||||||
|
self.plugin.config['WARNING_COLOR'] = colorbutton.get_color().to_string()
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPluginConfigDialog')
|
||||||
|
def on_jids_entry_changed(self, entry):
|
||||||
|
text = entry.get_text()
|
||||||
|
if len(text)>0:
|
||||||
|
self.plugin.config['JIDS'] = entry.get_text().split(',')
|
||||||
|
else:
|
||||||
|
self.plugin.config['JIDS'] = []
|
||||||
|
|
||||||
|
@log_calls('LengthNotifierPluginConfigDialog')
|
||||||
|
def on_jids_entry_editing_done(self, entry):
|
||||||
|
pass
|
|
@ -0,0 +1 @@
|
||||||
|
from plugin import NewEventsExamplePlugin
|
|
@ -0,0 +1,147 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
'''
|
||||||
|
New Events Example plugin.
|
||||||
|
|
||||||
|
Demonstrates how to use Network Events Controller to generate new events
|
||||||
|
based on existing one.
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 15th August 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import new
|
||||||
|
from pprint import pformat
|
||||||
|
|
||||||
|
from common import helpers
|
||||||
|
from common import gajim
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log_calls, log
|
||||||
|
from common import ged
|
||||||
|
from common import nec
|
||||||
|
|
||||||
|
class NewEventsExamplePlugin(GajimPlugin):
|
||||||
|
name = u'New Events Example'
|
||||||
|
short_name = u'new_events_example'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Shows how to generate new network events based on existing one using Network Events Controller.'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('NewEventsExamplePlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = None
|
||||||
|
#self.gui_extension_points = {}
|
||||||
|
#self.config_default_values = {}
|
||||||
|
|
||||||
|
self.events_handlers = {'raw-message-received' :
|
||||||
|
(ged.POSTCORE,
|
||||||
|
self.raw_message_received),
|
||||||
|
'customized-message-received' :
|
||||||
|
(ged.POSTCORE,
|
||||||
|
self.customized_message_received),
|
||||||
|
'enriched-chat-message-received' :
|
||||||
|
(ged.POSTCORE,
|
||||||
|
self.enriched_chat_message_received)}
|
||||||
|
|
||||||
|
self.events = [CustomizedMessageReceivedEvent,
|
||||||
|
MoreCustomizedMessageReceivedEvent,
|
||||||
|
ModifyOnlyMessageReceivedEvent,
|
||||||
|
EnrichedChatMessageReceivedEvent]
|
||||||
|
|
||||||
|
def enriched_chat_message_received(self, event_object):
|
||||||
|
pass
|
||||||
|
#print "Event '%s' occured. Event object: %s\n\n===\n"%(event_object.name,
|
||||||
|
#event_object)
|
||||||
|
|
||||||
|
def raw_message_received(self, event_object):
|
||||||
|
pass
|
||||||
|
#print "Event '%s' occured. Event object: %s\n\n===\n"%(event_object.name,
|
||||||
|
#event_object)
|
||||||
|
|
||||||
|
def customized_message_received(self, event_object):
|
||||||
|
pass
|
||||||
|
#print "Event '%s' occured. Event object: %s\n\n===\n"%(event_object.name,
|
||||||
|
#event_object
|
||||||
|
|
||||||
|
@log_calls('NewEventsExamplePlugin')
|
||||||
|
def activate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('NewEventsExamplePlugin')
|
||||||
|
def deactivate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CustomizedMessageReceivedEvent(nec.NetworkIncomingEvent):
|
||||||
|
name = 'customized-message-received'
|
||||||
|
base_network_events = ['raw-message-received']
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
class MoreCustomizedMessageReceivedEvent(nec.NetworkIncomingEvent):
|
||||||
|
'''
|
||||||
|
Shows chain of custom created events.
|
||||||
|
|
||||||
|
This one is based on custom 'customized-messsage-received'.
|
||||||
|
'''
|
||||||
|
name = 'more-customized-message-received'
|
||||||
|
base_network_events = ['customized-message-received']
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
class ModifyOnlyMessageReceivedEvent(nec.NetworkIncomingEvent):
|
||||||
|
name = 'modify-only-message-received'
|
||||||
|
base_network_events = ['raw-message-received']
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
msg_type = self.base_event.xmpp_msg.attrs.get('type', None)
|
||||||
|
if msg_type == u'chat':
|
||||||
|
msg_text = "".join(self.base_event.xmpp_msg.kids[0].data)
|
||||||
|
self.base_event.xmpp_msg.kids[0].setData(
|
||||||
|
u'%s [MODIFIED BY CUSTOM NETWORK EVENT]'%(msg_text))
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
class EnrichedChatMessageReceivedEvent(nec.NetworkIncomingEvent):
|
||||||
|
'''
|
||||||
|
Generates more friendly (in use by handlers) network event for
|
||||||
|
received chat message.
|
||||||
|
'''
|
||||||
|
name = 'enriched-chat-message-received'
|
||||||
|
base_network_events = ['raw-message-received']
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
msg_type = self.base_event.xmpp_msg.attrs.get('type', None)
|
||||||
|
if msg_type == u'chat':
|
||||||
|
self.xmpp_msg = self.base_event.xmpp_msg
|
||||||
|
self.conn = self.base_event.conn
|
||||||
|
self.from_jid = helpers.get_full_jid_from_iq(self.xmpp_msg)
|
||||||
|
self.from_jid_without_resource = gajim.get_jid_without_resource(self.from_jid)
|
||||||
|
self.account = self.base_event.account
|
||||||
|
self.from_nickname = gajim.get_contact_name_from_jid(
|
||||||
|
self.account,
|
||||||
|
self.from_jid_without_resource)
|
||||||
|
self.msg_text = "".join(self.xmpp_msg.kids[0].data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
__all__ = ['RosterButtonsPlugin']
|
||||||
|
|
||||||
|
from plugin import RosterButtonsPlugin
|
|
@ -0,0 +1,86 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
'''
|
||||||
|
Roster buttons plug-in.
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 14th June 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
from common import i18n
|
||||||
|
from common import gajim
|
||||||
|
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log, log_calls
|
||||||
|
|
||||||
|
class RosterButtonsPlugin(GajimPlugin):
|
||||||
|
name = u'Roster Buttons'
|
||||||
|
short_name = u'roster_buttons'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Adds quick action buttons to roster window.'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('RosterButtonsPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.GTK_BUILDER_FILE_PATH = self.local_file_path('roster_buttons.ui')
|
||||||
|
self.roster_vbox = gajim.interface.roster.xml.get_object('roster_vbox2')
|
||||||
|
self.show_offline_contacts_menuitem = gajim.interface.roster.xml.get_object('show_offline_contacts_menuitem')
|
||||||
|
|
||||||
|
self.config_dialog = None
|
||||||
|
|
||||||
|
@log_calls('RosterButtonsPlugin')
|
||||||
|
def activate(self):
|
||||||
|
self.xml = gtk.Builder()
|
||||||
|
self.xml.set_translation_domain(i18n.APP)
|
||||||
|
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
|
||||||
|
['roster_buttons_buttonbox'])
|
||||||
|
self.buttonbox = self.xml.get_object('roster_buttons_buttonbox')
|
||||||
|
|
||||||
|
self.roster_vbox.pack_start(self.buttonbox, expand=False)
|
||||||
|
self.roster_vbox.reorder_child(self.buttonbox, 0)
|
||||||
|
self.xml.connect_signals(self)
|
||||||
|
|
||||||
|
@log_calls('RosterButtonsPlugin')
|
||||||
|
def deactivate(self):
|
||||||
|
self.roster_vbox.remove(self.buttonbox)
|
||||||
|
|
||||||
|
self.buttonbox = None
|
||||||
|
self.xml = None
|
||||||
|
|
||||||
|
@log_calls('RosterButtonsPlugin')
|
||||||
|
def on_roster_button_1_clicked(self, button):
|
||||||
|
#gajim.interface.roster.on_show_offline_contacts_menuitem_activate(None)
|
||||||
|
self.show_offline_contacts_menuitem.set_active(not self.show_offline_contacts_menuitem.get_active())
|
||||||
|
|
||||||
|
@log_calls('RosterButtonsPlugin')
|
||||||
|
def on_roster_button_2_clicked(self, button):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('RosterButtonsPlugin')
|
||||||
|
def on_roster_button_3_clicked(self, button):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('RosterButtonsPlugin')
|
||||||
|
def on_roster_button_4_clicked(self, button):
|
||||||
|
pass
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy toplevel-contextual -->
|
||||||
|
<object class="GtkWindow" id="window1">
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="roster_buttons_buttonbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
<property name="layout_style">spread</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="roster_button_1">
|
||||||
|
<property name="label" translatable="yes">1</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_roster_button_1_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="roster_button_2">
|
||||||
|
<property name="label" translatable="yes">2</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_roster_button_2_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="roster_button_3">
|
||||||
|
<property name="label" translatable="yes">3</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_roster_button_3_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="roster_button_4">
|
||||||
|
<property name="label" translatable="yes">4</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_roster_button_4_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -0,0 +1,772 @@
|
||||||
|
"""
|
||||||
|
A python version of the main functions to use Snarl
|
||||||
|
(http://www.fullphat.net/snarl)
|
||||||
|
|
||||||
|
Version 1.0
|
||||||
|
|
||||||
|
This module can be used in two ways. One is the normal way
|
||||||
|
the other snarl interfaces work. This means you can call snShowMessage
|
||||||
|
and get an ID back for manipulations.
|
||||||
|
|
||||||
|
The other way is there is a class this module exposes called SnarlMessage.
|
||||||
|
This allows you to keep track of the message as a python object. If you
|
||||||
|
use the send without specifying False as the argument it will set the ID
|
||||||
|
to what the return of the last SendMessage was. This is of course only
|
||||||
|
useful for the SHOW message.
|
||||||
|
|
||||||
|
Requires one of:
|
||||||
|
pywin32 extensions from http://pywin32.sourceforge.net
|
||||||
|
ctypes (included in Python 2.5, downloadable for earlier versions)
|
||||||
|
|
||||||
|
Creator: Sam Listopad II (samlii@users.sourceforge.net)
|
||||||
|
|
||||||
|
Copyright 2006-2008 Samuel Listopad II
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
use this file except in compliance with the License. You may obtain a copy
|
||||||
|
of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
|
||||||
|
by applicable law or agreed to in writing, software distributed under the
|
||||||
|
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||||
|
OF ANY KIND, either express or implied. See the License for the specific
|
||||||
|
language governing permissions and limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import array, struct
|
||||||
|
|
||||||
|
def LOWORD(dword):
|
||||||
|
"""Return the low WORD of the passed in integer"""
|
||||||
|
return dword & 0x0000ffff
|
||||||
|
#get the hi word
|
||||||
|
def HIWORD(dword):
|
||||||
|
"""Return the high WORD of the passed in integer"""
|
||||||
|
return dword >> 16
|
||||||
|
|
||||||
|
class Win32FuncException(Exception):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return repr(self.value)
|
||||||
|
|
||||||
|
class Win32Funcs:
|
||||||
|
"""Just a little class to hide the details of finding and using the
|
||||||
|
correct win32 functions. The functions may throw a UnicodeEncodeError if
|
||||||
|
there is not a unicode version and it is sent a unicode string that cannot
|
||||||
|
be converted to ASCII."""
|
||||||
|
WM_USER = 0x400
|
||||||
|
WM_COPYDATA = 0x4a
|
||||||
|
#Type of String the functions are expecting.
|
||||||
|
#Used like function(myWin32Funcs.strType(param)).
|
||||||
|
__strType = str
|
||||||
|
#FindWindow function to use
|
||||||
|
__FindWindow = None
|
||||||
|
#FindWindow function to use
|
||||||
|
__FindWindowEx = None
|
||||||
|
#SendMessage function to use
|
||||||
|
__SendMessage = None
|
||||||
|
#SendMessageTimeout function to use
|
||||||
|
__SendMessageTimeout = None
|
||||||
|
#IsWindow function to use
|
||||||
|
__IsWindow = None
|
||||||
|
#RegisterWindowMessage to use
|
||||||
|
__RegisterWindowMessage = None
|
||||||
|
#GetWindowText to use
|
||||||
|
__GetWindowText = None
|
||||||
|
|
||||||
|
def FindWindow(self, lpClassName, lpWindowName):
|
||||||
|
"""Wraps the windows API call of FindWindow"""
|
||||||
|
if lpClassName is not None:
|
||||||
|
lpClassName = self.__strType(lpClassName)
|
||||||
|
if lpWindowName is not None:
|
||||||
|
lpWindowName = self.__strType(lpWindowName)
|
||||||
|
return self.__FindWindow(lpClassName, lpWindowName)
|
||||||
|
|
||||||
|
def FindWindowEx(self, hwndParent, hwndChildAfter, lpClassName, lpWindowName):
|
||||||
|
"""Wraps the windows API call of FindWindow"""
|
||||||
|
if lpClassName is not None:
|
||||||
|
lpClassName = self.__strType(lpClassName)
|
||||||
|
if lpWindowName is not None:
|
||||||
|
lpWindowName = self.__strType(lpWindowName)
|
||||||
|
return self.__FindWindowEx(hwndParent, hwndChildAfter, lpClassName, lpWindowName)
|
||||||
|
|
||||||
|
def SendMessage(self, hWnd, Msg, wParam, lParam):
|
||||||
|
"""Wraps the windows API call of SendMessage"""
|
||||||
|
return self.__SendMessage(hWnd, Msg, wParam, lParam)
|
||||||
|
|
||||||
|
def SendMessageTimeout(self, hWnd, Msg,
|
||||||
|
wParam, lParam, fuFlags,
|
||||||
|
uTimeout, lpdwResult = None):
|
||||||
|
"""Wraps the windows API call of SendMessageTimeout"""
|
||||||
|
idToRet = None
|
||||||
|
try:
|
||||||
|
idFromMsg = array.array('I', [0])
|
||||||
|
result = idFromMsg.buffer_info()[0]
|
||||||
|
response = self.__SendMessageTimeout(hWnd, Msg, wParam,
|
||||||
|
lParam, fuFlags,
|
||||||
|
uTimeout, result)
|
||||||
|
if response == 0:
|
||||||
|
raise Win32FuncException, "SendMessageTimeout TimedOut"
|
||||||
|
|
||||||
|
idToRet = idFromMsg[0]
|
||||||
|
except TypeError:
|
||||||
|
idToRet = self.__SendMessageTimeout(hWnd, Msg, wParam,
|
||||||
|
lParam, fuFlags,
|
||||||
|
uTimeout)
|
||||||
|
|
||||||
|
if lpdwResult is not None and lpdwResult.typecode == 'I':
|
||||||
|
lpdwResult[0] = idToRet
|
||||||
|
|
||||||
|
return idToRet
|
||||||
|
|
||||||
|
def IsWindow(self, hWnd):
|
||||||
|
"""Wraps the windows API call of IsWindow"""
|
||||||
|
return self.__IsWindow(hWnd)
|
||||||
|
|
||||||
|
def RegisterWindowMessage(self, lpString):
|
||||||
|
"""Wraps the windows API call of RegisterWindowMessage"""
|
||||||
|
return self.__RegisterWindowMessage(self.__strType(lpString))
|
||||||
|
|
||||||
|
def GetWindowText(self, hWnd, lpString = None, nMaxCount = None):
|
||||||
|
"""Wraps the windows API call of SendMessageTimeout"""
|
||||||
|
text = ''
|
||||||
|
if hWnd == 0:
|
||||||
|
return text
|
||||||
|
|
||||||
|
if nMaxCount is None:
|
||||||
|
nMaxCount = 1025
|
||||||
|
|
||||||
|
try:
|
||||||
|
arrayType = 'c'
|
||||||
|
if self.__strType == unicode:
|
||||||
|
arrayType = 'u'
|
||||||
|
path_string = array.array(arrayType, self.__strType('\x00') * nMaxCount)
|
||||||
|
path_buffer = path_string.buffer_info()[0]
|
||||||
|
result = self.__GetWindowText(hWnd,
|
||||||
|
path_buffer,
|
||||||
|
nMaxCount)
|
||||||
|
if result > 0:
|
||||||
|
if self.__strType == unicode:
|
||||||
|
text = path_string[0:result].tounicode()
|
||||||
|
else:
|
||||||
|
text = path_string[0:result].tostring()
|
||||||
|
except TypeError:
|
||||||
|
text = self.__GetWindowText(hWnd)
|
||||||
|
|
||||||
|
if lpString is not None and lpString.typecode == 'c':
|
||||||
|
lpdwResult[0:len(text)] = array.array('c', str(text));
|
||||||
|
|
||||||
|
if lpString is not None and lpString.typecode == 'u':
|
||||||
|
lpdwResult[0:len(text)] = array.array('u', unicode(text));
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Load up my needed functions"""
|
||||||
|
# First see if they already have win32gui imported. If so use it.
|
||||||
|
# This has to be checked first since the auto check looks for ctypes
|
||||||
|
# first.
|
||||||
|
try:
|
||||||
|
self.__FindWindow = win32gui.FindWindow
|
||||||
|
self.__FindWindowEx = win32gui.FindWindowEx
|
||||||
|
self.__GetWindowText = win32gui.GetWindowText
|
||||||
|
self.__IsWindow = win32gui.IsWindow
|
||||||
|
self.__SendMessage = win32gui.SendMessage
|
||||||
|
self.__SendMessageTimeout = win32gui.SendMessageTimeout
|
||||||
|
self.__RegisterWindowMessage = win32gui.RegisterWindowMessage
|
||||||
|
self.__strType = unicode
|
||||||
|
|
||||||
|
#Something threw a NameError, most likely the win32gui lines
|
||||||
|
#so do auto check
|
||||||
|
except NameError:
|
||||||
|
try:
|
||||||
|
from ctypes import windll
|
||||||
|
self.__FindWindow = windll.user32.FindWindowW
|
||||||
|
self.__FindWindowEx = windll.user32.FindWindowExW
|
||||||
|
self.__GetWindowText = windll.user32.GetWindowTextW
|
||||||
|
self.__IsWindow = windll.user32.IsWindow
|
||||||
|
self.__SendMessage = windll.user32.SendMessageW
|
||||||
|
self.__SendMessageTimeout = windll.user32.SendMessageTimeoutW
|
||||||
|
self.__RegisterWindowMessage = windll.user32.RegisterWindowMessageW
|
||||||
|
self.__strType = unicode
|
||||||
|
|
||||||
|
#FindWindowW wasn't found, look for FindWindowA
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
self.__FindWindow = windll.user32.FindWindowA
|
||||||
|
self.__FindWindowEx = windll.user32.FindWindowExA
|
||||||
|
self.__GetWindowText = windll.user32.GetWindowTextA
|
||||||
|
self.__IsWindow = windll.user32.IsWindow
|
||||||
|
self.__SendMessage = windll.user32.SendMessageA
|
||||||
|
self.__SendMessageTimeout = windll.user32.SendMessageTimeoutA
|
||||||
|
self.__RegisterWindowMessage = windll.user32.RegisterWindowMessageA
|
||||||
|
# Couldn't find either so Die and tell user why.
|
||||||
|
except AttributeError:
|
||||||
|
import sys
|
||||||
|
sys.stderr.write("Your Windows TM setup seems to be corrupt."+
|
||||||
|
" No FindWindow found in user32.\n")
|
||||||
|
sys.stderr.flush()
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
import win32gui
|
||||||
|
self.__FindWindow = win32gui.FindWindow
|
||||||
|
self.__FindWindowEx = win32gui.FindWindowEx
|
||||||
|
self.__GetWindowText = win32gui.GetWindowText
|
||||||
|
self.__IsWindow = win32gui.IsWindow
|
||||||
|
self.__SendMessage = win32gui.SendMessage
|
||||||
|
self.__SendMessageTimeout = win32gui.SendMessageTimeout
|
||||||
|
self.__RegisterWindowMessage = win32gui.RegisterWindowMessage
|
||||||
|
self.__strType = unicode
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
import sys
|
||||||
|
sys.stderr.write("You need to have either"+
|
||||||
|
" ctypes or pywin32 installed.\n")
|
||||||
|
sys.stderr.flush()
|
||||||
|
#sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
myWin32Funcs = Win32Funcs()
|
||||||
|
|
||||||
|
|
||||||
|
SHOW = 1
|
||||||
|
HIDE = 2
|
||||||
|
UPDATE = 3
|
||||||
|
IS_VISIBLE = 4
|
||||||
|
GET_VERSION = 5
|
||||||
|
REGISTER_CONFIG_WINDOW = 6
|
||||||
|
REVOKE_CONFIG_WINDOW = 7
|
||||||
|
REGISTER_ALERT = 8
|
||||||
|
REVOKE_ALERT = 9
|
||||||
|
REGISTER_CONFIG_WINDOW_2 = 10
|
||||||
|
GET_VERSION_EX = 11
|
||||||
|
SET_TIMEOUT = 12
|
||||||
|
|
||||||
|
EX_SHOW = 32
|
||||||
|
|
||||||
|
GLOBAL_MESSAGE = "SnarlGlobalMessage"
|
||||||
|
GLOBAL_MSG = "SnarlGlobalEvent"
|
||||||
|
|
||||||
|
#Messages That may be received from Snarl
|
||||||
|
SNARL_LAUNCHED = 1
|
||||||
|
SNARL_QUIT = 2
|
||||||
|
SNARL_ASK_APPLET_VER = 3
|
||||||
|
SNARL_SHOW_APP_UI = 4
|
||||||
|
|
||||||
|
SNARL_NOTIFICATION_CLICKED = 32 #notification was right-clicked by user
|
||||||
|
SNARL_NOTIFICATION_CANCELLED = SNARL_NOTIFICATION_CLICKED #Name clarified
|
||||||
|
SNARL_NOTIFICATION_TIMED_OUT = 33
|
||||||
|
SNARL_NOTIFICATION_ACK = 34 #notification was left-clicked by user
|
||||||
|
|
||||||
|
#Snarl Test Message
|
||||||
|
WM_SNARLTEST = myWin32Funcs.WM_USER + 237
|
||||||
|
|
||||||
|
M_ABORTED = 0x80000007L
|
||||||
|
M_ACCESS_DENIED = 0x80000009L
|
||||||
|
M_ALREADY_EXISTS = 0x8000000CL
|
||||||
|
M_BAD_HANDLE = 0x80000006L
|
||||||
|
M_BAD_POINTER = 0x80000005L
|
||||||
|
M_FAILED = 0x80000008L
|
||||||
|
M_INVALID_ARGS = 0x80000003L
|
||||||
|
M_NO_INTERFACE = 0x80000004L
|
||||||
|
M_NOT_FOUND = 0x8000000BL
|
||||||
|
M_NOT_IMPLEMENTED = 0x80000001L
|
||||||
|
M_OK = 0x00000000L
|
||||||
|
M_OUT_OF_MEMORY = 0x80000002L
|
||||||
|
M_TIMED_OUT = 0x8000000AL
|
||||||
|
|
||||||
|
ErrorCodeRev = {
|
||||||
|
0x80000007L : "M_ABORTED",
|
||||||
|
0x80000009L : "M_ACCESS_DENIED",
|
||||||
|
0x8000000CL : "M_ALREADY_EXISTS",
|
||||||
|
0x80000006L : "M_BAD_HANDLE",
|
||||||
|
0x80000005L : "M_BAD_POINTER",
|
||||||
|
0x80000008L : "M_FAILED",
|
||||||
|
0x80000003L : "M_INVALID_ARGS",
|
||||||
|
0x80000004L : "M_NO_INTERFACE",
|
||||||
|
0x8000000BL : "M_NOT_FOUND",
|
||||||
|
0x80000001L : "M_NOT_IMPLEMENTED",
|
||||||
|
0x00000000L : "M_OK",
|
||||||
|
0x80000002L : "M_OUT_OF_MEMORY",
|
||||||
|
0x8000000AL : "M_TIMED_OUT"
|
||||||
|
}
|
||||||
|
|
||||||
|
class SnarlMessage(object):
|
||||||
|
"""The main Snarl interface object.
|
||||||
|
|
||||||
|
ID = Snarl Message ID for most operations. See SDK for more info
|
||||||
|
as to other values to put here.
|
||||||
|
type = Snarl Message Type. Valid values are : SHOW, HIDE, UPDATE,
|
||||||
|
IS_VISIBLE, GET_VERSION, REGISTER_CONFIG_WINDOW, REVOKE_CONFIG_WINDOW
|
||||||
|
all which are constants in the PySnarl module.
|
||||||
|
timeout = Timeout in seconds for the Snarl Message
|
||||||
|
data = Snarl Message data. This is dependant upon message type. See SDK
|
||||||
|
title = Snarl Message title.
|
||||||
|
text = Snarl Message text.
|
||||||
|
icon = Path to the icon to display in the Snarl Message.
|
||||||
|
"""
|
||||||
|
__msgType = 0
|
||||||
|
__msgID = 0
|
||||||
|
__msgTimeout = 0
|
||||||
|
__msgData = 0
|
||||||
|
__msgTitle = ""
|
||||||
|
__msgText = ""
|
||||||
|
__msgIcon = ""
|
||||||
|
__msgClass = ""
|
||||||
|
__msgExtra = ""
|
||||||
|
__msgExtra2 = ""
|
||||||
|
__msgRsvd1 = 0
|
||||||
|
__msgRsvd2 = 0
|
||||||
|
__msgHWnd = 0
|
||||||
|
|
||||||
|
lastKnownHWnd = 0
|
||||||
|
|
||||||
|
def getType(self):
|
||||||
|
"""Type Attribute getter."""
|
||||||
|
return self.__msgType
|
||||||
|
def setType(self, value):
|
||||||
|
"""Type Attribute setter."""
|
||||||
|
if( isinstance(value, (int, long)) ):
|
||||||
|
self.__msgType = value
|
||||||
|
type = property(getType, setType, doc="The Snarl Message Type")
|
||||||
|
|
||||||
|
def getID(self):
|
||||||
|
"""ID Attribute getter."""
|
||||||
|
return self.__msgID
|
||||||
|
def setID(self, value):
|
||||||
|
"""ID Attribute setter."""
|
||||||
|
if( isinstance(value, (int, long)) ):
|
||||||
|
self.__msgID = value
|
||||||
|
ID = property(getID, setID, doc="The Snarl Message ID")
|
||||||
|
|
||||||
|
def getTimeout(self):
|
||||||
|
"""Timeout Attribute getter."""
|
||||||
|
return self.__msgTimeout
|
||||||
|
def updateTimeout(self, value):
|
||||||
|
"""Timeout Attribute setter."""
|
||||||
|
if( isinstance(value, (int, long)) ):
|
||||||
|
self.__msgTimeout = value
|
||||||
|
timeout = property(getTimeout, updateTimeout,
|
||||||
|
doc="The Snarl Message Timeout")
|
||||||
|
|
||||||
|
def getData(self):
|
||||||
|
"""Data Attribute getter."""
|
||||||
|
return self.__msgData
|
||||||
|
def setData(self, value):
|
||||||
|
"""Data Attribute setter."""
|
||||||
|
if( isinstance(value, (int, long)) ):
|
||||||
|
self.__msgData = value
|
||||||
|
data = property(getData, setData, doc="The Snarl Message Data")
|
||||||
|
|
||||||
|
def getTitle(self):
|
||||||
|
"""Title Attribute getter."""
|
||||||
|
return self.__msgTitle
|
||||||
|
def setTitle(self, value):
|
||||||
|
"""Title Attribute setter."""
|
||||||
|
if( isinstance(value, basestring) ):
|
||||||
|
self.__msgTitle = value
|
||||||
|
title = property(getTitle, setTitle, doc="The Snarl Message Title")
|
||||||
|
|
||||||
|
def getText(self):
|
||||||
|
"""Text Attribute getter."""
|
||||||
|
return self.__msgText
|
||||||
|
def setText(self, value):
|
||||||
|
"""Text Attribute setter."""
|
||||||
|
if( isinstance(value, basestring) ):
|
||||||
|
self.__msgText = value
|
||||||
|
text = property(getText, setText, doc="The Snarl Message Text")
|
||||||
|
|
||||||
|
def getIcon(self):
|
||||||
|
"""Icon Attribute getter."""
|
||||||
|
return self.__msgIcon
|
||||||
|
def setIcon(self, value):
|
||||||
|
"""Icon Attribute setter."""
|
||||||
|
if( isinstance(value, basestring) ):
|
||||||
|
self.__msgIcon = value
|
||||||
|
icon = property(getIcon, setIcon, doc="The Snarl Message Icon")
|
||||||
|
|
||||||
|
def getClass(self):
|
||||||
|
"""Class Attribute getter."""
|
||||||
|
return self.__msgClass
|
||||||
|
def setClass(self, value):
|
||||||
|
"""Class Attribute setter."""
|
||||||
|
if( isinstance(value, basestring) ):
|
||||||
|
self.__msgClass = value
|
||||||
|
msgclass = property(getClass, setClass, doc="The Snarl Message Class")
|
||||||
|
|
||||||
|
def getExtra(self):
|
||||||
|
"""Extra Attribute getter."""
|
||||||
|
return self.__msgExtra
|
||||||
|
def setExtra(self, value):
|
||||||
|
"""Extra Attribute setter."""
|
||||||
|
if( isinstance(value, basestring) ):
|
||||||
|
self.__msgExtra = value
|
||||||
|
extra = property(getExtra, setExtra, doc="Extra Info for the Snarl Message")
|
||||||
|
|
||||||
|
def getExtra2(self):
|
||||||
|
"""Extra2 Attribute getter."""
|
||||||
|
return self.__msgExtra2
|
||||||
|
def setExtra2(self, value):
|
||||||
|
"""Extra2 Attribute setter."""
|
||||||
|
if( isinstance(value, basestring) ):
|
||||||
|
self.__msgExtra2 = value
|
||||||
|
extra2 = property(getExtra2, setExtra2,
|
||||||
|
doc="More Extra Info for the Snarl Message")
|
||||||
|
|
||||||
|
def getRsvd1(self):
|
||||||
|
"""Rsvd1 Attribute getter."""
|
||||||
|
return self.__msgRsvd1
|
||||||
|
def setRsvd1(self, value):
|
||||||
|
"""Rsvd1 Attribute setter."""
|
||||||
|
if( isinstance(value, (int, long)) ):
|
||||||
|
self.__msgRsvd1 = value
|
||||||
|
rsvd1 = property(getRsvd1, setRsvd1, doc="The Snarl Message Field Rsvd1")
|
||||||
|
|
||||||
|
def getRsvd2(self):
|
||||||
|
"""Rsvd2 Attribute getter."""
|
||||||
|
return self.__msgRsvd2
|
||||||
|
def setRsvd2(self, value):
|
||||||
|
"""Rsvd2 Attribute setter."""
|
||||||
|
if( isinstance(value, (int, long)) ):
|
||||||
|
self.__msgRsvd2 = value
|
||||||
|
rsvd2 = property(getRsvd2, setRsvd2, doc="The Snarl Message Field Rsvd2")
|
||||||
|
|
||||||
|
def getHwnd(self):
|
||||||
|
"""hWnd Attribute getter."""
|
||||||
|
return self.__msgHWnd
|
||||||
|
def setHwnd(self, value):
|
||||||
|
"""hWnd Attribute setter."""
|
||||||
|
if( isinstance(value, (int, long)) ):
|
||||||
|
self.__msgHWnd = value
|
||||||
|
|
||||||
|
hWnd = property(getHwnd, setHwnd, doc="The hWnd of the window this message is being sent from")
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, title="", text="", icon="", msg_type=1, msg_id=0):
|
||||||
|
self.__msgTimeout = 0
|
||||||
|
self.__msgData = 0
|
||||||
|
self.__msgClass = ""
|
||||||
|
self.__msgExtra = ""
|
||||||
|
self.__msgExtra2 = ""
|
||||||
|
self.__msgRsvd1 = 0
|
||||||
|
self.__msgRsvd2 = 0
|
||||||
|
self.__msgType = msg_type
|
||||||
|
self.__msgText = text
|
||||||
|
self.__msgTitle = title
|
||||||
|
self.__msgIcon = icon
|
||||||
|
self.__msgID = msg_id
|
||||||
|
|
||||||
|
def createCopyStruct(self):
|
||||||
|
"""Creates the struct to send as the copyData in the message."""
|
||||||
|
return struct.pack("ILLL1024s1024s1024s1024s1024s1024sLL",
|
||||||
|
self.__msgType,
|
||||||
|
self.__msgID,
|
||||||
|
self.__msgTimeout,
|
||||||
|
self.__msgData,
|
||||||
|
self.__msgTitle.encode('utf-8'),
|
||||||
|
self.__msgText.encode('utf-8'),
|
||||||
|
self.__msgIcon.encode('utf-8'),
|
||||||
|
self.__msgClass.encode('utf-8'),
|
||||||
|
self.__msgExtra.encode('utf-8'),
|
||||||
|
self.__msgExtra2.encode('utf-8'),
|
||||||
|
self.__msgRsvd1,
|
||||||
|
self.__msgRsvd2
|
||||||
|
)
|
||||||
|
__lpData = None
|
||||||
|
__cds = None
|
||||||
|
|
||||||
|
def packData(self, dwData):
|
||||||
|
"""This packs the data in the necessary format for a
|
||||||
|
WM_COPYDATA message."""
|
||||||
|
self.__lpData = None
|
||||||
|
self.__cds = None
|
||||||
|
item = self.createCopyStruct()
|
||||||
|
self.__lpData = array.array('c', item)
|
||||||
|
lpData_ad = self.__lpData.buffer_info()[0]
|
||||||
|
cbData = self.__lpData.buffer_info()[1]
|
||||||
|
self.__cds = array.array('c',
|
||||||
|
struct.pack("IIP",
|
||||||
|
dwData,
|
||||||
|
cbData,
|
||||||
|
lpData_ad)
|
||||||
|
)
|
||||||
|
cds_ad = self.__cds.buffer_info()[0]
|
||||||
|
return cds_ad
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Reset this SnarlMessage to the default state."""
|
||||||
|
self.__msgType = 0
|
||||||
|
self.__msgID = 0
|
||||||
|
self.__msgTimeout = 0
|
||||||
|
self.__msgData = 0
|
||||||
|
self.__msgTitle = ""
|
||||||
|
self.__msgText = ""
|
||||||
|
self.__msgIcon = ""
|
||||||
|
self.__msgClass = ""
|
||||||
|
self.__msgExtra = ""
|
||||||
|
self.__msgExtra2 = ""
|
||||||
|
self.__msgRsvd1 = 0
|
||||||
|
self.__msgRsvd2 = 0
|
||||||
|
|
||||||
|
|
||||||
|
def send(self, setid=True):
|
||||||
|
"""Send this SnarlMessage to the Snarl window.
|
||||||
|
Args:
|
||||||
|
setid - Boolean defining whether or not to set the ID
|
||||||
|
of this SnarlMessage to the return value of
|
||||||
|
the SendMessage call. Default is True to
|
||||||
|
make simple case of SHOW easy.
|
||||||
|
"""
|
||||||
|
hwnd = myWin32Funcs.FindWindow(None, "Snarl")
|
||||||
|
if myWin32Funcs.IsWindow(hwnd):
|
||||||
|
if self.type == REGISTER_CONFIG_WINDOW or self.type == REGISTER_CONFIG_WINDOW_2:
|
||||||
|
self.hWnd = self.data
|
||||||
|
try:
|
||||||
|
response = myWin32Funcs.SendMessageTimeout(hwnd,
|
||||||
|
myWin32Funcs.WM_COPYDATA,
|
||||||
|
self.hWnd, self.packData(2),
|
||||||
|
2, 500)
|
||||||
|
except Win32FuncException:
|
||||||
|
return False
|
||||||
|
|
||||||
|
idFromMsg = response
|
||||||
|
if setid:
|
||||||
|
self.ID = idFromMsg
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return idFromMsg
|
||||||
|
print "No snarl window found"
|
||||||
|
return False
|
||||||
|
|
||||||
|
def hide(self):
|
||||||
|
"""Hide this message. Type will revert to type before calling hide
|
||||||
|
to allow for better reuse of object."""
|
||||||
|
oldType = self.__msgType
|
||||||
|
self.__msgType = HIDE
|
||||||
|
retVal = bool(self.send(False))
|
||||||
|
self.__msgType = oldType
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
def isVisible(self):
|
||||||
|
"""Is this message visible. Type will revert to type before calling
|
||||||
|
hide to allow for better reuse of object."""
|
||||||
|
oldType = self.__msgType
|
||||||
|
self.__msgType = IS_VISIBLE
|
||||||
|
retVal = bool(self.send(False))
|
||||||
|
self.__msgType = oldType
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
def update(self, title=None, text=None, icon=None):
|
||||||
|
"""Update this message with given title and text. Type will revert
|
||||||
|
to type before calling hide to allow for better reuse of object."""
|
||||||
|
oldType = self.__msgType
|
||||||
|
self.__msgType = UPDATE
|
||||||
|
if text:
|
||||||
|
self.__msgText = text
|
||||||
|
if title:
|
||||||
|
self.__msgTitle = title
|
||||||
|
if icon:
|
||||||
|
self.__msgIcon = icon
|
||||||
|
retVal = self.send(False)
|
||||||
|
self.__msgType = oldType
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
def setTimeout(self, timeout):
|
||||||
|
"""Set the timeout in seconds of the message"""
|
||||||
|
oldType = self.__msgType
|
||||||
|
oldData = self.__msgData
|
||||||
|
self.__msgType = SET_TIMEOUT
|
||||||
|
#self.timeout = timeout
|
||||||
|
#self.__msgData = self.__msgTimeout
|
||||||
|
self.__msgData = timeout
|
||||||
|
retVal = self.send(False)
|
||||||
|
self.__msgType = oldType
|
||||||
|
self.__msgData = oldData
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
def show(self, timeout=None, title=None,
|
||||||
|
text=None, icon=None,
|
||||||
|
replyWindow=None, replyMsg=None, msgclass=None, soundPath=None):
|
||||||
|
"""Show a message"""
|
||||||
|
oldType = self.__msgType
|
||||||
|
oldTimeout = self.__msgTimeout
|
||||||
|
self.__msgType = SHOW
|
||||||
|
if text:
|
||||||
|
self.__msgText = text
|
||||||
|
if title:
|
||||||
|
self.__msgTitle = title
|
||||||
|
if timeout:
|
||||||
|
self.__msgTimeout = timeout
|
||||||
|
if icon:
|
||||||
|
self.__msgIcon = icon
|
||||||
|
if replyWindow:
|
||||||
|
self.__msgID = replyMsg
|
||||||
|
if replyMsg:
|
||||||
|
self.__msgData = replyWindow
|
||||||
|
if soundPath:
|
||||||
|
self.__msgExtra = soundPath
|
||||||
|
if msgclass:
|
||||||
|
self.__msgClass = msgclass
|
||||||
|
|
||||||
|
if ((self.__msgClass and self.__msgClass != "") or
|
||||||
|
(self.__msgExtra and self.__msgExtra != "")):
|
||||||
|
self.__msgType = EX_SHOW
|
||||||
|
|
||||||
|
|
||||||
|
retVal = bool(self.send())
|
||||||
|
self.__msgType = oldType
|
||||||
|
self.__msgTimeout = oldTimeout
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
|
||||||
|
def snGetVersion():
|
||||||
|
""" Get the version of Snarl that is running as a tuple. (Major, Minor)
|
||||||
|
|
||||||
|
If Snarl is not running or there was an error it will
|
||||||
|
return False."""
|
||||||
|
msg = SnarlMessage(msg_type=GET_VERSION)
|
||||||
|
version = msg.send(False)
|
||||||
|
if not version:
|
||||||
|
return False
|
||||||
|
return (HIWORD(version), LOWORD(version))
|
||||||
|
|
||||||
|
def snGetVersionEx():
|
||||||
|
""" Get the internal version of Snarl that is running.
|
||||||
|
|
||||||
|
If Snarl is not running or there was an error it will
|
||||||
|
return False."""
|
||||||
|
sm = SnarlMessage(msg_type=GET_VERSION_EX)
|
||||||
|
verNum = sm.send(False)
|
||||||
|
if not verNum:
|
||||||
|
return False
|
||||||
|
return verNum
|
||||||
|
|
||||||
|
def snGetGlobalMessage():
|
||||||
|
"""Get the Snarl global message id from windows."""
|
||||||
|
return myWin32Funcs.RegisterWindowMessage(GLOBAL_MSG)
|
||||||
|
|
||||||
|
def snShowMessage(title, text, timeout=0, iconPath="",
|
||||||
|
replyWindow=0, replyMsg=0):
|
||||||
|
"""Show a message using Snarl and return its ID. See SDK for arguments."""
|
||||||
|
sm = SnarlMessage( title, text, iconPath, msg_id=replyMsg)
|
||||||
|
sm.data = replyWindow
|
||||||
|
if sm.show(timeout):
|
||||||
|
return sm.ID
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def snShowMessageEx(msgClass, title, text, timeout=0, iconPath="",
|
||||||
|
replyWindow=0, replyMsg=0, soundFile=None, hWndFrom=None):
|
||||||
|
"""Show a message using Snarl and return its ID. See SDK for arguments.
|
||||||
|
One added argument is hWndFrom that allows one to make the messages appear
|
||||||
|
to come from a specific window. This window should be the one you registered
|
||||||
|
earlier with RegisterConfig"""
|
||||||
|
sm = SnarlMessage( title, text, iconPath, msg_id=replyMsg)
|
||||||
|
sm.data = replyWindow
|
||||||
|
if hWndFrom is not None:
|
||||||
|
sm.hWnd = hWndFrom
|
||||||
|
else:
|
||||||
|
sm.hWnd = SnarlMessage.lastKnownHWnd
|
||||||
|
if sm.show(timeout, msgclass=msgClass, soundPath=soundFile):
|
||||||
|
return sm.ID
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def snUpdateMessage(msgId, msgTitle, msgText, icon=None):
|
||||||
|
"""Update a message"""
|
||||||
|
sm = SnarlMessage(msg_id=msgId)
|
||||||
|
if icon:
|
||||||
|
sm.icon = icon
|
||||||
|
return sm.update(msgTitle, msgText)
|
||||||
|
|
||||||
|
def snHideMessage(msgId):
|
||||||
|
"""Hide a message"""
|
||||||
|
return SnarlMessage(msg_id=msgId).hide()
|
||||||
|
|
||||||
|
def snSetTimeout(msgId, timeout):
|
||||||
|
"""Update the timeout of a message already shown."""
|
||||||
|
sm = SnarlMessage(msg_id=msgId)
|
||||||
|
return sm.setTimeout(timeout)
|
||||||
|
|
||||||
|
def snIsMessageVisible(msgId):
|
||||||
|
"""Returns True if the message is visible False otherwise."""
|
||||||
|
return SnarlMessage(msg_id=msgId).isVisible()
|
||||||
|
|
||||||
|
def snRegisterConfig(replyWnd, appName, replyMsg):
|
||||||
|
"""Register a config window. See SDK for more info."""
|
||||||
|
global lastRegisteredSnarlMsg
|
||||||
|
sm = SnarlMessage(msg_type=REGISTER_CONFIG_WINDOW,
|
||||||
|
title=appName,
|
||||||
|
msg_id=replyMsg)
|
||||||
|
sm.data = replyWnd
|
||||||
|
SnarlMessage.lastKnownHWnd = replyWnd
|
||||||
|
|
||||||
|
return sm.send(False)
|
||||||
|
|
||||||
|
def snRegisterConfig2(replyWnd, appName, replyMsg, icon):
|
||||||
|
"""Register a config window. See SDK for more info."""
|
||||||
|
global lastRegisteredSnarlMsg
|
||||||
|
sm = SnarlMessage(msg_type=REGISTER_CONFIG_WINDOW_2,
|
||||||
|
title=appName,
|
||||||
|
msg_id=replyMsg,
|
||||||
|
icon=icon)
|
||||||
|
sm.data = replyWnd
|
||||||
|
SnarlMessage.lastKnownHWnd = replyWnd
|
||||||
|
return sm.send(False)
|
||||||
|
|
||||||
|
def snRegisterAlert(appName, classStr) :
|
||||||
|
"""Register an alert for an already registered config. See SDK for more info."""
|
||||||
|
sm = SnarlMessage(msg_type=REGISTER_ALERT,
|
||||||
|
title=appName,
|
||||||
|
text=classStr)
|
||||||
|
return sm.send(False)
|
||||||
|
|
||||||
|
def snRevokeConfig(replyWnd):
|
||||||
|
"""Revoke a config window"""
|
||||||
|
sm = SnarlMessage(msg_type=REVOKE_CONFIG_WINDOW)
|
||||||
|
sm.data = replyWnd
|
||||||
|
if replyWnd == SnarlMessage.lastKnownHWnd:
|
||||||
|
SnarlMessage.lastKnownHWnd = 0
|
||||||
|
return sm.send(False)
|
||||||
|
|
||||||
|
def snGetSnarlWindow():
|
||||||
|
"""Returns the hWnd of the snarl window"""
|
||||||
|
return myWin32Funcs.FindWindow(None, "Snarl")
|
||||||
|
|
||||||
|
def snGetAppPath():
|
||||||
|
"""Returns the application path of the currently running snarl window"""
|
||||||
|
app_path = None
|
||||||
|
snarl_handle = snGetSnarlWindow()
|
||||||
|
if snarl_handle != 0:
|
||||||
|
pathwin_handle = myWin32Funcs.FindWindowEx(snarl_handle,
|
||||||
|
0,
|
||||||
|
"static",
|
||||||
|
None)
|
||||||
|
if pathwin_handle != 0:
|
||||||
|
try:
|
||||||
|
result = myWin32Funcs.GetWindowText(pathwin_handle)
|
||||||
|
app_path = result
|
||||||
|
except Win32FuncException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
return app_path
|
||||||
|
|
||||||
|
def snGetIconsPath():
|
||||||
|
"""Returns the path to the icons of the program"""
|
||||||
|
s = snGetAppPath()
|
||||||
|
if s is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return s + "etc\\icons\\"
|
||||||
|
|
||||||
|
def snSendTestMessage(data=None):
|
||||||
|
"""Sends a test message to Snarl. Used to make sure the
|
||||||
|
api is connecting"""
|
||||||
|
param = 0
|
||||||
|
command = 0
|
||||||
|
if data:
|
||||||
|
param = struct.pack("I", data)
|
||||||
|
command = 1
|
||||||
|
myWin32Funcs.SendMessage(snGetSnarlWindow(), WM_SNARLTEST, command, param)
|
|
@ -0,0 +1 @@
|
||||||
|
from plugin import SnarlNotificationsPlugin
|
|
@ -0,0 +1,90 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published
|
||||||
|
## by the Free Software Foundation; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
'''
|
||||||
|
Events notifications using Snarl
|
||||||
|
|
||||||
|
Fancy events notifications under Windows using Snarl infrastructure.
|
||||||
|
|
||||||
|
:note: plugin is at proof-of-concept state.
|
||||||
|
|
||||||
|
:author: Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:since: 15th August 2008
|
||||||
|
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import new
|
||||||
|
from pprint import pformat
|
||||||
|
|
||||||
|
#import PySnarl
|
||||||
|
|
||||||
|
from common import gajim
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log_calls, log
|
||||||
|
from common import ged
|
||||||
|
|
||||||
|
class SnarlNotificationsPlugin(GajimPlugin):
|
||||||
|
name = u'Snarl Notifications'
|
||||||
|
short_name = u'snarl_notifications'
|
||||||
|
version = u'0.1'
|
||||||
|
description = u'''Shows events notification using Snarl (http://www.fullphat.net/) under Windows. Snarl needs to be installed in system.
|
||||||
|
PySnarl bindings are used (http://code.google.com/p/pysnarl/).'''
|
||||||
|
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
|
||||||
|
homepage = u'http://blog.bilinski.it'
|
||||||
|
|
||||||
|
@log_calls('SnarlNotificationsPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.config_dialog = None
|
||||||
|
#self.gui_extension_points = {}
|
||||||
|
#self.config_default_values = {}
|
||||||
|
|
||||||
|
self.events_handlers = {'NewMessage' : (ged.POSTCORE, self.newMessage)}
|
||||||
|
|
||||||
|
@log_calls('SnarlNotificationsPlugin')
|
||||||
|
def activate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('SnarlNotificationsPlugin')
|
||||||
|
def deactivate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_calls('SnarlNotificationsPlugin')
|
||||||
|
def newMessage(self, args):
|
||||||
|
event_name = "NewMessage"
|
||||||
|
data = args
|
||||||
|
account = data[0]
|
||||||
|
jid = data[1][0]
|
||||||
|
jid_without_resource = gajim.get_jid_without_resource(jid)
|
||||||
|
msg = data[1][1]
|
||||||
|
msg_type = data[1][4]
|
||||||
|
if msg_type == 'chat':
|
||||||
|
nickname = gajim.get_contact_name_from_jid(account,
|
||||||
|
jid_without_resource)
|
||||||
|
elif msg_type == 'pm':
|
||||||
|
nickname = gajim.get_resource_from_jid(jid)
|
||||||
|
|
||||||
|
print "Event '%s' occured. Arguments: %s\n\n===\n"%(event_name, pformat(args))
|
||||||
|
print "Event '%s' occured. Arguments: \naccount = %s\njid = %s\nmsg = %s\nnickname = %s"%(
|
||||||
|
event_name, account, jid, msg, nickname)
|
||||||
|
|
||||||
|
|
||||||
|
#if PySnarl.snGetVersion() != False:
|
||||||
|
#(major, minor) = PySnarl.snGetVersion()
|
||||||
|
#print "Found Snarl version",str(major)+"."+str(minor),"running."
|
||||||
|
#PySnarl.snShowMessage(nickname, msg[:20]+'...')
|
||||||
|
#else:
|
||||||
|
#print "Sorry Snarl does not appear to be running"
|
2623
po/be@latin.po
2623
po/be@latin.po
File diff suppressed because it is too large
Load Diff
2740
po/en_GB.po
2740
po/en_GB.po
File diff suppressed because it is too large
Load Diff
2615
po/pt_BR.po
2615
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
2589
po/sr@Latn.po
2589
po/sr@Latn.po
File diff suppressed because it is too large
Load Diff
2615
po/zh_CN.po
2615
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,8 @@ nobase_dist_gajimsrc_PYTHON = \
|
||||||
$(srcdir)/common/xmpp/*.py \
|
$(srcdir)/common/xmpp/*.py \
|
||||||
$(srcdir)/common/zeroconf/*.py \
|
$(srcdir)/common/zeroconf/*.py \
|
||||||
$(srcdir)/command_system/*.py \
|
$(srcdir)/command_system/*.py \
|
||||||
$(srcdir)/command_system/implementation/*.py
|
$(srcdir)/command_system/implementation/*.py \
|
||||||
|
$(srcdir)/plugins/*.py
|
||||||
|
|
||||||
dist-hook:
|
dist-hook:
|
||||||
rm -f $(distdir)/ipython_view.py
|
rm -f $(distdir)/ipython_view.py
|
||||||
|
|
|
@ -64,13 +64,12 @@ class CommandWindow:
|
||||||
self.window.connect('delete-event',
|
self.window.connect('delete-event',
|
||||||
self.on_adhoc_commands_window_delete_event)
|
self.on_adhoc_commands_window_delete_event)
|
||||||
for name in ('restart_button', 'back_button', 'forward_button',
|
for name in ('restart_button', 'back_button', 'forward_button',
|
||||||
'execute_button', 'close_button', 'stages_notebook',
|
'execute_button', 'finish_button', 'close_button', 'stages_notebook',
|
||||||
'retrieving_commands_stage_vbox',
|
'retrieving_commands_stage_vbox', 'command_list_stage_vbox',
|
||||||
'command_list_stage_vbox', 'command_list_vbox',
|
'command_list_vbox', 'sending_form_stage_vbox',
|
||||||
'sending_form_stage_vbox', 'sending_form_progressbar',
|
'sending_form_progressbar', 'notes_label', 'no_commands_stage_vbox',
|
||||||
'notes_label', 'no_commands_stage_vbox', 'error_stage_vbox',
|
'error_stage_vbox', 'error_description_label'):
|
||||||
'error_description_label'):
|
setattr(self, name, self.xml.get_object(name))
|
||||||
self.__dict__[name] = self.xml.get_object(name)
|
|
||||||
|
|
||||||
self.initiate()
|
self.initiate()
|
||||||
|
|
||||||
|
@ -100,6 +99,7 @@ class CommandWindow:
|
||||||
self.stage1()
|
self.stage1()
|
||||||
|
|
||||||
# displaying the window
|
# displaying the window
|
||||||
|
self.window.set_title('Ad-hoc Commands - Gajim')
|
||||||
self.xml.connect_signals(self)
|
self.xml.connect_signals(self)
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
|
|
||||||
|
@ -121,6 +121,9 @@ class CommandWindow:
|
||||||
def stage_close_button_clicked(self, *anything):
|
def stage_close_button_clicked(self, *anything):
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
def stage_restart_button_clicked(self, *anything):
|
||||||
|
assert False
|
||||||
|
|
||||||
def stage_adhoc_commands_window_delete_event(self, *anything):
|
def stage_adhoc_commands_window_delete_event(self, *anything):
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
@ -137,9 +140,15 @@ class CommandWindow:
|
||||||
def on_execute_button_clicked(self, *anything):
|
def on_execute_button_clicked(self, *anything):
|
||||||
return self.stage_execute_button_clicked(*anything)
|
return self.stage_execute_button_clicked(*anything)
|
||||||
|
|
||||||
|
def on_finish_button_clicked(self, *anything):
|
||||||
|
return self.stage_finish_button_clicked(*anything)
|
||||||
|
|
||||||
def on_close_button_clicked(self, *anything):
|
def on_close_button_clicked(self, *anything):
|
||||||
return self.stage_close_button_clicked(*anything)
|
return self.stage_close_button_clicked(*anything)
|
||||||
|
|
||||||
|
def on_restart_button_clicked(self, *anything):
|
||||||
|
return self.stage_restart_button_clicked(*anything)
|
||||||
|
|
||||||
def on_adhoc_commands_window_destroy(self, *anything):
|
def on_adhoc_commands_window_destroy(self, *anything):
|
||||||
# TODO: do all actions that are needed to remove this object from memory
|
# TODO: do all actions that are needed to remove this object from memory
|
||||||
self.remove_pulsing()
|
self.remove_pulsing()
|
||||||
|
@ -169,15 +178,17 @@ class CommandWindow:
|
||||||
self.back_button.set_sensitive(False)
|
self.back_button.set_sensitive(False)
|
||||||
self.forward_button.set_sensitive(False)
|
self.forward_button.set_sensitive(False)
|
||||||
self.execute_button.set_sensitive(False)
|
self.execute_button.set_sensitive(False)
|
||||||
|
self.finish_button.set_sensitive(False)
|
||||||
|
|
||||||
# request command list
|
# request command list
|
||||||
self.request_command_list()
|
self.request_command_list()
|
||||||
self.setup_pulsing(
|
self.setup_pulsing(
|
||||||
self.xml.get_object('retrieving_commands_progressbar'))
|
self.xml.get_object('retrieving_commands_progressbar'))
|
||||||
|
|
||||||
# setup the callbacks
|
# setup the callbacks
|
||||||
self.stage_finish = self.stage1_finish
|
self.stage_finish = self.stage1_finish
|
||||||
self.stage_close_button_clicked = self.stage1_close_button_clicked
|
self.stage_close_button_clicked = self.stage1_close_button_clicked
|
||||||
|
self.stage_restart_button_clicked = self.stage1_restart_button_clicked
|
||||||
self.stage_adhoc_commands_window_delete_event = \
|
self.stage_adhoc_commands_window_delete_event = \
|
||||||
self.stage1_adhoc_commands_window_delete_event
|
self.stage1_adhoc_commands_window_delete_event
|
||||||
|
|
||||||
|
@ -187,9 +198,13 @@ class CommandWindow:
|
||||||
def stage1_close_button_clicked(self, widget):
|
def stage1_close_button_clicked(self, widget):
|
||||||
# cancelling in this stage is not critical, so we don't
|
# cancelling in this stage is not critical, so we don't
|
||||||
# show any popups to user
|
# show any popups to user
|
||||||
self.stage1_finish()
|
self.stage_finish()
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
|
def stage1_restart_button_clicked(self, widget):
|
||||||
|
self.stage_finish()
|
||||||
|
self.restart()
|
||||||
|
|
||||||
def stage1_adhoc_commands_window_delete_event(self, widget):
|
def stage1_adhoc_commands_window_delete_event(self, widget):
|
||||||
self.stage1_finish()
|
self.stage1_finish()
|
||||||
return True
|
return True
|
||||||
|
@ -214,6 +229,7 @@ class CommandWindow:
|
||||||
self.back_button.set_sensitive(False)
|
self.back_button.set_sensitive(False)
|
||||||
self.forward_button.set_sensitive(True)
|
self.forward_button.set_sensitive(True)
|
||||||
self.execute_button.set_sensitive(False)
|
self.execute_button.set_sensitive(False)
|
||||||
|
self.finish_button.set_sensitive(False)
|
||||||
|
|
||||||
# build the commands list radiobuttons
|
# build the commands list radiobuttons
|
||||||
first_radio = None
|
first_radio = None
|
||||||
|
@ -229,6 +245,7 @@ class CommandWindow:
|
||||||
|
|
||||||
self.stage_finish = self.stage2_finish
|
self.stage_finish = self.stage2_finish
|
||||||
self.stage_close_button_clicked = self.stage2_close_button_clicked
|
self.stage_close_button_clicked = self.stage2_close_button_clicked
|
||||||
|
self.stage_restart_button_clicked = self.stage2_restart_button_clicked
|
||||||
self.stage_forward_button_clicked = self.stage2_forward_button_clicked
|
self.stage_forward_button_clicked = self.stage2_forward_button_clicked
|
||||||
self.stage_adhoc_commands_window_delete_event = self.do_nothing
|
self.stage_adhoc_commands_window_delete_event = self.do_nothing
|
||||||
|
|
||||||
|
@ -244,6 +261,10 @@ class CommandWindow:
|
||||||
self.stage_finish()
|
self.stage_finish()
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
|
def stage2_restart_button_clicked(self, widget):
|
||||||
|
self.stage_finish()
|
||||||
|
self.restart()
|
||||||
|
|
||||||
def stage2_forward_button_clicked(self, widget):
|
def stage2_forward_button_clicked(self, widget):
|
||||||
self.stage3()
|
self.stage3()
|
||||||
|
|
||||||
|
@ -266,10 +287,12 @@ class CommandWindow:
|
||||||
self.stages_notebook.page_num(
|
self.stages_notebook.page_num(
|
||||||
self.sending_form_stage_vbox))
|
self.sending_form_stage_vbox))
|
||||||
|
|
||||||
|
self.restart_button.set_sensitive(True)
|
||||||
self.close_button.set_sensitive(True)
|
self.close_button.set_sensitive(True)
|
||||||
self.back_button.set_sensitive(False)
|
self.back_button.set_sensitive(False)
|
||||||
self.forward_button.set_sensitive(False)
|
self.forward_button.set_sensitive(False)
|
||||||
self.execute_button.set_sensitive(False)
|
self.execute_button.set_sensitive(False)
|
||||||
|
self.finish_button.set_sensitive(False)
|
||||||
|
|
||||||
self.stage3_submit_form()
|
self.stage3_submit_form()
|
||||||
|
|
||||||
|
@ -277,13 +300,31 @@ class CommandWindow:
|
||||||
self.stage_back_button_clicked = self.stage3_back_button_clicked
|
self.stage_back_button_clicked = self.stage3_back_button_clicked
|
||||||
self.stage_forward_button_clicked = self.stage3_forward_button_clicked
|
self.stage_forward_button_clicked = self.stage3_forward_button_clicked
|
||||||
self.stage_execute_button_clicked = self.stage3_execute_button_clicked
|
self.stage_execute_button_clicked = self.stage3_execute_button_clicked
|
||||||
|
self.stage_finish_button_clicked = self.stage3_finish_button_clicked
|
||||||
self.stage_close_button_clicked = self.stage3_close_button_clicked
|
self.stage_close_button_clicked = self.stage3_close_button_clicked
|
||||||
|
self.stage_restart_button_clicked = self.stage3_restart_button_clicked
|
||||||
self.stage_adhoc_commands_window_delete_event = \
|
self.stage_adhoc_commands_window_delete_event = \
|
||||||
self.stage3_close_button_clicked
|
self.stage3_close_button_clicked
|
||||||
|
|
||||||
def stage3_finish(self):
|
def stage3_finish(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def stage3_can_close(self, cb):
|
||||||
|
if self.form_status == 'completed':
|
||||||
|
cb()
|
||||||
|
return
|
||||||
|
|
||||||
|
def on_yes(button):
|
||||||
|
self.send_cancel()
|
||||||
|
dialog.destroy()
|
||||||
|
cb()
|
||||||
|
|
||||||
|
dialog = dialogs.HigDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT \
|
||||||
|
| gtk.DIALOG_MODAL, gtk.BUTTONS_YES_NO, _('Cancel confirmation'),
|
||||||
|
_('You are in process of executing command. Do you really want to '
|
||||||
|
'cancel it?'), on_response_yes=on_yes)
|
||||||
|
dialog.popup()
|
||||||
|
|
||||||
def stage3_close_button_clicked(self, widget):
|
def stage3_close_button_clicked(self, widget):
|
||||||
"""
|
"""
|
||||||
We are in the middle of executing command. Ask user if he really want to
|
We are in the middle of executing command. Ask user if he really want to
|
||||||
|
@ -291,26 +332,23 @@ class CommandWindow:
|
||||||
"""
|
"""
|
||||||
# this works also as a handler for window_delete_event, so we have to
|
# this works also as a handler for window_delete_event, so we have to
|
||||||
# return appropriate values
|
# return appropriate values
|
||||||
if self.form_status == 'completed':
|
|
||||||
if widget != self.window:
|
|
||||||
self.window.destroy()
|
|
||||||
return False
|
|
||||||
|
|
||||||
if self.allow_stage3_close:
|
if self.allow_stage3_close:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def on_yes(button):
|
def on_ok():
|
||||||
self.send_cancel()
|
|
||||||
self.allow_stage3_close = True
|
self.allow_stage3_close = True
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
dialog = dialogs.HigDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT \
|
self.stage3_can_close(on_ok)
|
||||||
| gtk.DIALOG_MODAL, gtk.BUTTONS_YES_NO, _('Cancel confirmation'),
|
|
||||||
_('You are in process of executing command. Do you really want to '
|
|
||||||
'cancel it?'), on_response_yes=on_yes)
|
|
||||||
dialog.popup()
|
|
||||||
return True # Block event, don't close window
|
return True # Block event, don't close window
|
||||||
|
|
||||||
|
def stage3_restart_button_clicked(self, widget):
|
||||||
|
def on_ok():
|
||||||
|
self.restart()
|
||||||
|
|
||||||
|
self.stage3_can_close(on_ok)
|
||||||
|
|
||||||
def stage3_back_button_clicked(self, widget):
|
def stage3_back_button_clicked(self, widget):
|
||||||
self.stage3_submit_form('prev')
|
self.stage3_submit_form('prev')
|
||||||
|
|
||||||
|
@ -320,9 +358,19 @@ class CommandWindow:
|
||||||
def stage3_execute_button_clicked(self, widget):
|
def stage3_execute_button_clicked(self, widget):
|
||||||
self.stage3_submit_form('execute')
|
self.stage3_submit_form('execute')
|
||||||
|
|
||||||
|
def stage3_finish_button_clicked(self, widget):
|
||||||
|
self.stage3_submit_form('complete')
|
||||||
|
|
||||||
def stage3_submit_form(self, action='execute'):
|
def stage3_submit_form(self, action='execute'):
|
||||||
self.data_form_widget.set_sensitive(False)
|
self.data_form_widget.set_sensitive(False)
|
||||||
|
|
||||||
if self.data_form_widget.get_data_form():
|
if self.data_form_widget.get_data_form():
|
||||||
|
df = self.data_form_widget.get_data_form()
|
||||||
|
if not df.is_valid():
|
||||||
|
dialogs.ErrorDialog(_('Invalid Form'),
|
||||||
|
_('The form is not filled correctly.'))
|
||||||
|
self.data_form_widget.set_sensitive(True)
|
||||||
|
return
|
||||||
self.data_form_widget.data_form.type = 'submit'
|
self.data_form_widget.data_form.type = 'submit'
|
||||||
else:
|
else:
|
||||||
self.data_form_widget.hide()
|
self.data_form_widget.hide()
|
||||||
|
@ -331,6 +379,7 @@ class CommandWindow:
|
||||||
self.back_button.set_sensitive(False)
|
self.back_button.set_sensitive(False)
|
||||||
self.forward_button.set_sensitive(False)
|
self.forward_button.set_sensitive(False)
|
||||||
self.execute_button.set_sensitive(False)
|
self.execute_button.set_sensitive(False)
|
||||||
|
self.finish_button.set_sensitive(False)
|
||||||
|
|
||||||
self.sending_form_progressbar.show()
|
self.sending_form_progressbar.show()
|
||||||
self.setup_pulsing(self.sending_form_progressbar)
|
self.setup_pulsing(self.sending_form_progressbar)
|
||||||
|
@ -379,18 +428,21 @@ class CommandWindow:
|
||||||
self.forward_button.set_sensitive(
|
self.forward_button.set_sensitive(
|
||||||
actions.getTag('next') is not None)
|
actions.getTag('next') is not None)
|
||||||
self.execute_button.set_sensitive(True)
|
self.execute_button.set_sensitive(True)
|
||||||
|
self.finish_button.set_sensitive(actions.getTag('complete') is not \
|
||||||
|
None)
|
||||||
else:
|
else:
|
||||||
self.close_button.set_sensitive(True)
|
self.close_button.set_sensitive(True)
|
||||||
self.back_button.set_sensitive(False)
|
self.back_button.set_sensitive(False)
|
||||||
self.forward_button.set_sensitive(False)
|
self.forward_button.set_sensitive(False)
|
||||||
self.execute_button.set_sensitive(True)
|
self.execute_button.set_sensitive(True)
|
||||||
|
self.finish_button.set_sensitive(False)
|
||||||
|
|
||||||
if self.form_status == 'completed':
|
if self.form_status == 'completed':
|
||||||
self.close_button.set_sensitive(True)
|
self.close_button.set_sensitive(True)
|
||||||
self.restart_button.set_sensitive(True)
|
|
||||||
self.back_button.hide()
|
self.back_button.hide()
|
||||||
self.forward_button.hide()
|
self.forward_button.hide()
|
||||||
self.execute_button.hide()
|
self.execute_button.hide()
|
||||||
|
self.finish_button.hide()
|
||||||
self.close_button.show()
|
self.close_button.show()
|
||||||
self.stage_adhoc_commands_window_delete_event = \
|
self.stage_adhoc_commands_window_delete_event = \
|
||||||
self.stage3_close_button_clicked
|
self.stage3_close_button_clicked
|
||||||
|
@ -404,7 +456,7 @@ class CommandWindow:
|
||||||
self.notes_label.set_no_show_all(True)
|
self.notes_label.set_no_show_all(True)
|
||||||
self.notes_label.hide()
|
self.notes_label.hide()
|
||||||
|
|
||||||
def on_restart_button_clicked(self, widget):
|
def restart(self):
|
||||||
self.commandnode = None
|
self.commandnode = None
|
||||||
self.initiate()
|
self.initiate()
|
||||||
|
|
||||||
|
@ -423,14 +475,19 @@ class CommandWindow:
|
||||||
self.back_button.set_sensitive(False)
|
self.back_button.set_sensitive(False)
|
||||||
self.forward_button.set_sensitive(False)
|
self.forward_button.set_sensitive(False)
|
||||||
self.execute_button.set_sensitive(False)
|
self.execute_button.set_sensitive(False)
|
||||||
|
self.finish_button.set_sensitive(False)
|
||||||
|
|
||||||
self.stage_finish = self.do_nothing
|
self.stage_finish = self.do_nothing
|
||||||
self.stage_close_button_clicked = self.stage4_close_button_clicked
|
self.stage_close_button_clicked = self.stage4_close_button_clicked
|
||||||
|
self.stage_restart_button_clicked = self.stage4_restart_button_clicked
|
||||||
self.stage_adhoc_commands_window_delete_event = self.do_nothing
|
self.stage_adhoc_commands_window_delete_event = self.do_nothing
|
||||||
|
|
||||||
def stage4_close_button_clicked(self, widget):
|
def stage4_close_button_clicked(self, widget):
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
|
def stage4_restart_button_clicked(self, widget):
|
||||||
|
self.restart()
|
||||||
|
|
||||||
def on_check_commands_2_button_clicked(self, widget):
|
def on_check_commands_2_button_clicked(self, widget):
|
||||||
self.stage1()
|
self.stage1()
|
||||||
|
|
||||||
|
@ -468,16 +525,21 @@ class CommandWindow:
|
||||||
self.back_button.hide()
|
self.back_button.hide()
|
||||||
self.forward_button.hide()
|
self.forward_button.hide()
|
||||||
self.execute_button.hide()
|
self.execute_button.hide()
|
||||||
|
self.finish_button.hide()
|
||||||
|
|
||||||
self.error_description_label.set_text(error)
|
self.error_description_label.set_text(error)
|
||||||
|
|
||||||
self.stage_finish = self.do_nothing
|
self.stage_finish = self.do_nothing
|
||||||
self.stage_close_button_clicked = self.stage5_close_button_clicked
|
self.stage_close_button_clicked = self.stage5_close_button_clicked
|
||||||
|
self.stage_restart_button_clicked = self.stage5_restart_button_clicked
|
||||||
self.stage_adhoc_commands_window_delete_event = self.do_nothing
|
self.stage_adhoc_commands_window_delete_event = self.do_nothing
|
||||||
|
|
||||||
def stage5_close_button_clicked(self, widget):
|
def stage5_close_button_clicked(self, widget):
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
|
def stage5_restart_button_clicked(self, widget):
|
||||||
|
self.restart()
|
||||||
|
|
||||||
# helpers to handle pulsing in progressbar
|
# helpers to handle pulsing in progressbar
|
||||||
def setup_pulsing(self, progressbar):
|
def setup_pulsing(self, progressbar):
|
||||||
"""
|
"""
|
||||||
|
@ -554,7 +616,7 @@ class CommandWindow:
|
||||||
cmdnode.setAttr('sessionid', self.sessionid)
|
cmdnode.setAttr('sessionid', self.sessionid)
|
||||||
|
|
||||||
if self.data_form_widget.data_form:
|
if self.data_form_widget.data_form:
|
||||||
cmdnode.addChild(node=self.data_form_widget.data_form)
|
cmdnode.addChild(node=self.data_form_widget.data_form.get_purged())
|
||||||
|
|
||||||
def callback(response):
|
def callback(response):
|
||||||
# FIXME: move to connection_handlers.py
|
# FIXME: move to connection_handlers.py
|
||||||
|
|
|
@ -53,15 +53,16 @@ class AtomWindow:
|
||||||
"""
|
"""
|
||||||
Create new window... only if we have anything to show
|
Create new window... only if we have anything to show
|
||||||
"""
|
"""
|
||||||
assert len(self.__class__.entries)>0
|
assert len(self.__class__.entries)
|
||||||
|
|
||||||
self.entry = None # the entry actually displayed
|
self.entry = None # the entry actually displayed
|
||||||
|
|
||||||
self.xml = gtkgui_helpers.get_gtk_builder('atom_entry_window.ui')
|
self.xml = gtkgui_helpers.get_gtk_builder('atom_entry_window.ui')
|
||||||
self.window = self.xml.get_object('atom_entry_window')
|
self.window = self.xml.get_object('atom_entry_window')
|
||||||
for name in ('new_entry_label', 'feed_title_label', 'feed_title_eventbox',
|
for name in ('new_entry_label', 'feed_title_label',
|
||||||
'feed_tagline_label', 'entry_title_label', 'entry_title_eventbox',
|
'feed_title_eventbox', 'feed_tagline_label', 'entry_title_label',
|
||||||
'last_modified_label', 'close_button', 'next_button'):
|
'entry_title_eventbox', 'last_modified_label', 'close_button',
|
||||||
|
'next_button'):
|
||||||
self.__dict__[name] = self.xml.get_object(name)
|
self.__dict__[name] = self.xml.get_object(name)
|
||||||
|
|
||||||
self.displayNextEntry()
|
self.displayNextEntry()
|
||||||
|
@ -83,23 +84,26 @@ class AtomWindow:
|
||||||
# fill the fields
|
# fill the fields
|
||||||
if newentry.feed_link is not None:
|
if newentry.feed_link is not None:
|
||||||
self.feed_title_label.set_markup(
|
self.feed_title_label.set_markup(
|
||||||
u'<span foreground="blue" underline="single">%s</span>' % \
|
u'<span foreground="blue" underline="single">%s</span>' % \
|
||||||
gobject.markup_escape_text(newentry.feed_title))
|
gobject.markup_escape_text(newentry.feed_title))
|
||||||
else:
|
else:
|
||||||
self.feed_title_label.set_markup(
|
self.feed_title_label.set_markup(
|
||||||
gobject.markup_escape_text(newentry.feed_title))
|
gobject.markup_escape_text(newentry.feed_title))
|
||||||
|
|
||||||
self.feed_tagline_label.set_markup(
|
self.feed_tagline_label.set_markup(
|
||||||
u'<small>%s</small>' % \
|
u'<small>%s</small>' % \
|
||||||
gobject.markup_escape_text(newentry.feed_tagline))
|
gobject.markup_escape_text(newentry.feed_tagline))
|
||||||
|
|
||||||
if newentry.uri is not None:
|
if newentry.title:
|
||||||
self.entry_title_label.set_markup(
|
if newentry.uri is not None:
|
||||||
|
self.entry_title_label.set_markup(
|
||||||
u'<span foreground="blue" underline="single">%s</span>' % \
|
u'<span foreground="blue" underline="single">%s</span>' % \
|
||||||
gobject.markup_escape_text(newentry.title))
|
gobject.markup_escape_text(newentry.title))
|
||||||
else:
|
else:
|
||||||
self.entry_title_label.set_markup(
|
self.entry_title_label.set_markup(
|
||||||
gobject.markup_escape_text(newentry.title))
|
gobject.markup_escape_text(newentry.title))
|
||||||
|
else:
|
||||||
|
self.entry_title_label.set_markup('')
|
||||||
|
|
||||||
self.last_modified_label.set_text(newentry.updated)
|
self.last_modified_label.set_text(newentry.updated)
|
||||||
|
|
||||||
|
@ -114,11 +118,11 @@ class AtomWindow:
|
||||||
changed
|
changed
|
||||||
"""
|
"""
|
||||||
count = len(self.__class__.entries)
|
count = len(self.__class__.entries)
|
||||||
if count>0:
|
if count:
|
||||||
self.new_entry_label.set_text(i18n.ngettext(
|
self.new_entry_label.set_text(i18n.ngettext(
|
||||||
'You have received new entries (and %d not displayed):',
|
'You have received new entries (and %d not displayed):',
|
||||||
'You have received new entries (and %d not displayed):', count,
|
'You have received new entries (and %d not displayed):', count,
|
||||||
count, count))
|
count, count))
|
||||||
self.next_button.set_sensitive(True)
|
self.next_button.set_sensitive(True)
|
||||||
else:
|
else:
|
||||||
self.new_entry_label.set_text(_('You have received new entry:'))
|
self.new_entry_label.set_text(_('You have received new entry:'))
|
||||||
|
@ -131,7 +135,7 @@ class AtomWindow:
|
||||||
def on_next_button_clicked(self, widget):
|
def on_next_button_clicked(self, widget):
|
||||||
self.displayNextEntry()
|
self.displayNextEntry()
|
||||||
|
|
||||||
def on_entry_title_button_press_event(self, widget, event):
|
def on_entry_title_eventbox_button_press_event(self, widget, event):
|
||||||
#FIXME: make it using special gtk2.10 widget
|
#FIXME: make it using special gtk2.10 widget
|
||||||
if event.button == 1: # left click
|
if event.button == 1: # left click
|
||||||
uri = self.entry.uri
|
uri = self.entry.uri
|
||||||
|
@ -139,7 +143,7 @@ class AtomWindow:
|
||||||
helpers.launch_browser_mailer('url', uri)
|
helpers.launch_browser_mailer('url', uri)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def on_feed_title_button_press_event(self, widget, event):
|
def on_feed_title_eventbox_button_press_event(self, widget, event):
|
||||||
#FIXME: make it using special gtk2.10 widget
|
#FIXME: make it using special gtk2.10 widget
|
||||||
if event.button == 1: # left click
|
if event.button == 1: # left click
|
||||||
uri = self.entry.feed_uri
|
uri = self.entry.feed_uri
|
||||||
|
|
|
@ -46,6 +46,7 @@ from common import exceptions
|
||||||
from message_control import MessageControl
|
from message_control import MessageControl
|
||||||
from conversation_textview import ConversationTextview
|
from conversation_textview import ConversationTextview
|
||||||
from message_textview import MessageTextView
|
from message_textview import MessageTextView
|
||||||
|
from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession
|
||||||
from common.contacts import GC_Contact
|
from common.contacts import GC_Contact
|
||||||
from common.logger import constants
|
from common.logger import constants
|
||||||
from common.pep import MOODS, ACTIVITIES
|
from common.pep import MOODS, ACTIVITIES
|
||||||
|
@ -95,8 +96,14 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
keymap = gtk.gdk.keymap_get_default()
|
keymap = gtk.gdk.keymap_get_default()
|
||||||
keycode_c = keymap.get_entries_for_keyval(gtk.keysyms.c)[0][0]
|
try:
|
||||||
keycode_ins = keymap.get_entries_for_keyval(gtk.keysyms.Insert)[0][0]
|
keycode_c = keymap.get_entries_for_keyval(gtk.keysyms.c)[0][0]
|
||||||
|
except TypeError:
|
||||||
|
keycode_c = 54
|
||||||
|
try:
|
||||||
|
keycode_ins = keymap.get_entries_for_keyval(gtk.keysyms.Insert)[0][0]
|
||||||
|
except TypeError:
|
||||||
|
keycode_ins = 118
|
||||||
def make_href(self, match):
|
def make_href(self, match):
|
||||||
url_color = gajim.config.get('urlmsgcolor')
|
url_color = gajim.config.get('urlmsgcolor')
|
||||||
url = match.group()
|
url = match.group()
|
||||||
|
@ -149,6 +156,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
"""
|
"""
|
||||||
self.draw_banner_text()
|
self.draw_banner_text()
|
||||||
self._update_banner_state_image()
|
self._update_banner_state_image()
|
||||||
|
gajim.plugin_manager.gui_extension_point('chat_control_base_draw_banner',
|
||||||
|
self)
|
||||||
|
|
||||||
def draw_banner_text(self):
|
def draw_banner_text(self):
|
||||||
"""
|
"""
|
||||||
|
@ -232,6 +241,29 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
def status_url_clicked(self, widget, url):
|
def status_url_clicked(self, widget, url):
|
||||||
helpers.launch_browser_mailer('url', url)
|
helpers.launch_browser_mailer('url', url)
|
||||||
|
|
||||||
|
def setup_seclabel(self, combo):
|
||||||
|
self.seclabel_combo = combo
|
||||||
|
self.seclabel_combo.hide()
|
||||||
|
self.seclabel_combo.set_no_show_all(True)
|
||||||
|
lb = gtk.ListStore(str)
|
||||||
|
self.seclabel_combo.set_model(lb)
|
||||||
|
cell = gtk.CellRendererText()
|
||||||
|
cell.set_property('xpad', 5) # padding for status text
|
||||||
|
self.seclabel_combo.pack_start(cell, True)
|
||||||
|
# text to show is in in first column of liststore
|
||||||
|
self.seclabel_combo.add_attribute(cell, 'text', 0)
|
||||||
|
if gajim.connections[self.account].seclabel_supported:
|
||||||
|
gajim.connections[self.account].seclabel_catalogue(self.contact.jid, self.on_seclabels_ready)
|
||||||
|
|
||||||
|
def on_seclabels_ready(self):
|
||||||
|
lb = self.seclabel_combo.get_model()
|
||||||
|
lb.clear()
|
||||||
|
for label in gajim.connections[self.account].seclabel_catalogues[self.contact.jid][2]:
|
||||||
|
lb.append([label])
|
||||||
|
self.seclabel_combo.set_active(0)
|
||||||
|
self.seclabel_combo.set_no_show_all(False)
|
||||||
|
self.seclabel_combo.show_all()
|
||||||
|
|
||||||
def __init__(self, type_id, parent_win, widget_name, contact, acct,
|
def __init__(self, type_id, parent_win, widget_name, contact, acct,
|
||||||
resource=None):
|
resource=None):
|
||||||
# Undo needs this variable to know if space has been pressed.
|
# Undo needs this variable to know if space has been pressed.
|
||||||
|
@ -380,6 +412,14 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
self.command_hits = []
|
self.command_hits = []
|
||||||
self.last_key_tabs = False
|
self.last_key_tabs = False
|
||||||
|
|
||||||
|
# PluginSystem: adding GUI extension point for ChatControlBase
|
||||||
|
# instance object (also subclasses, eg. ChatControl or GroupchatControl)
|
||||||
|
gajim.plugin_manager.gui_extension_point('chat_control_base', self)
|
||||||
|
|
||||||
|
# This is bascially a very nasty hack to surpass the inability
|
||||||
|
# to properly use the super, because of the old code.
|
||||||
|
CommandTools.__init__(self)
|
||||||
|
|
||||||
def set_speller(self):
|
def set_speller(self):
|
||||||
# now set the one the user selected
|
# now set the one the user selected
|
||||||
per_type = 'contacts'
|
per_type = 'contacts'
|
||||||
|
@ -415,6 +455,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
i += 1
|
i += 1
|
||||||
menu.show_all()
|
menu.show_all()
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
# PluginSystem: removing GUI extension points connected with ChatControlBase
|
||||||
|
# instance object
|
||||||
|
gajim.plugin_manager.remove_gui_extension_point('chat_control_base', self)
|
||||||
|
gajim.plugin_manager.remove_gui_extension_point('chat_control_base_draw_banner', self)
|
||||||
|
|
||||||
def on_msg_textview_populate_popup(self, textview, menu):
|
def on_msg_textview_populate_popup(self, textview, menu):
|
||||||
"""
|
"""
|
||||||
Override the default context menu and we prepend an option to switch
|
Override the default context menu and we prepend an option to switch
|
||||||
|
@ -721,6 +767,16 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
self.drag_entered_conv = True
|
self.drag_entered_conv = True
|
||||||
self.conv_textview.tv.set_editable(True)
|
self.conv_textview.tv.set_editable(True)
|
||||||
|
|
||||||
|
def get_seclabel(self):
|
||||||
|
label = None
|
||||||
|
if self.seclabel_combo is not None:
|
||||||
|
idx = self.seclabel_combo.get_active()
|
||||||
|
if idx != -1:
|
||||||
|
cat = gajim.connections[self.account].seclabel_catalogues[self.contact.jid]
|
||||||
|
lname = cat[2][idx]
|
||||||
|
label = cat[1][lname]
|
||||||
|
return label
|
||||||
|
|
||||||
def send_message(self, message, keyID='', type_='chat', chatstate=None,
|
def send_message(self, message, keyID='', type_='chat', chatstate=None,
|
||||||
msg_id=None, composing_xep=None, resource=None, xhtml=None,
|
msg_id=None, composing_xep=None, resource=None, xhtml=None,
|
||||||
callback=None, callback_args=[], process_commands=True):
|
callback=None, callback_args=[], process_commands=True):
|
||||||
|
@ -733,9 +789,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
if process_commands and self.process_as_command(message):
|
if process_commands and self.process_as_command(message):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
label = self.get_seclabel()
|
||||||
MessageControl.send_message(self, message, keyID, type_=type_,
|
MessageControl.send_message(self, message, keyID, type_=type_,
|
||||||
chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep,
|
chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep,
|
||||||
resource=resource, user_nick=self.user_nick, xhtml=xhtml,
|
resource=resource, user_nick=self.user_nick, xhtml=xhtml,
|
||||||
|
label=label,
|
||||||
callback=callback, callback_args=callback_args)
|
callback=callback, callback_args=callback_args)
|
||||||
|
|
||||||
# Record message history
|
# Record message history
|
||||||
|
@ -769,7 +827,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
other_tags_for_name=[], other_tags_for_time=[],
|
other_tags_for_name=[], other_tags_for_time=[],
|
||||||
other_tags_for_text=[], count_as_new=True, subject=None,
|
other_tags_for_text=[], count_as_new=True, subject=None,
|
||||||
old_kind=None, xhtml=None, simple=False, xep0184_id=None,
|
old_kind=None, xhtml=None, simple=False, xep0184_id=None,
|
||||||
graphics=True):
|
graphics=True, displaymarking=None):
|
||||||
"""
|
"""
|
||||||
Print 'chat' type messages
|
Print 'chat' type messages
|
||||||
"""
|
"""
|
||||||
|
@ -781,7 +839,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||||
end = True
|
end = True
|
||||||
textview.print_conversation_line(text, jid, kind, name, tim,
|
textview.print_conversation_line(text, jid, kind, name, tim,
|
||||||
other_tags_for_name, other_tags_for_time, other_tags_for_text,
|
other_tags_for_name, other_tags_for_time, other_tags_for_text,
|
||||||
subject, old_kind, xhtml, simple=simple, graphics=graphics)
|
subject, old_kind, xhtml, simple=simple, graphics=graphics,
|
||||||
|
displaymarking=displaymarking)
|
||||||
|
|
||||||
if xep0184_id is not None:
|
if xep0184_id is not None:
|
||||||
textview.show_xep0184_warning(xep0184_id)
|
textview.show_xep0184_warning(xep0184_id)
|
||||||
|
@ -1413,6 +1472,15 @@ class ChatControl(ChatControlBase):
|
||||||
id_ = widget.connect('released', self.on_num_button_released)
|
id_ = widget.connect('released', self.on_num_button_released)
|
||||||
self.handlers[id_] = widget
|
self.handlers[id_] = widget
|
||||||
|
|
||||||
|
self.dtmf_window = self.xml.get_object('dtmf_window')
|
||||||
|
id_ = self.dtmf_window.connect('focus-out-event',
|
||||||
|
self.on_dtmf_window_focus_out_event)
|
||||||
|
self.handlers[id_] = self.dtmf_window
|
||||||
|
|
||||||
|
widget = self.xml.get_object('dtmf_button')
|
||||||
|
id_ = widget.connect('clicked', self.on_dtmf_button_clicked)
|
||||||
|
self.handlers[id_] = widget
|
||||||
|
|
||||||
widget = self.xml.get_object('mic_hscale')
|
widget = self.xml.get_object('mic_hscale')
|
||||||
id_ = widget.connect('value_changed', self.on_mic_hscale_value_changed)
|
id_ = widget.connect('value_changed', self.on_mic_hscale_value_changed)
|
||||||
self.handlers[id_] = widget
|
self.handlers[id_] = widget
|
||||||
|
@ -1429,6 +1497,7 @@ class ChatControl(ChatControlBase):
|
||||||
session = gajim.connections[self.account].find_controlless_session(
|
session = gajim.connections[self.account].find_controlless_session(
|
||||||
self.contact.jid, resource)
|
self.contact.jid, resource)
|
||||||
|
|
||||||
|
self.setup_seclabel(self.xml.get_object('label_selector'))
|
||||||
if session:
|
if session:
|
||||||
session.control = self
|
session.control = self
|
||||||
self.session = session
|
self.session = session
|
||||||
|
@ -1533,6 +1602,10 @@ class ChatControl(ChatControlBase):
|
||||||
else:
|
else:
|
||||||
img.hide()
|
img.hide()
|
||||||
|
|
||||||
|
# PluginSystem: adding GUI extension point for this ChatControl
|
||||||
|
# instance object
|
||||||
|
gajim.plugin_manager.gui_extension_point('chat_control', self)
|
||||||
|
|
||||||
def _update_jingle(self, jingle_type):
|
def _update_jingle(self, jingle_type):
|
||||||
if jingle_type not in ('audio', 'video'):
|
if jingle_type not in ('audio', 'video'):
|
||||||
return
|
return
|
||||||
|
@ -1558,7 +1631,7 @@ class ChatControl(ChatControlBase):
|
||||||
|
|
||||||
def update_audio(self):
|
def update_audio(self):
|
||||||
self._update_jingle('audio')
|
self._update_jingle('audio')
|
||||||
vbox = self.xml.get_object('audio_vbox')
|
hbox = self.xml.get_object('audio_buttons_hbox')
|
||||||
if self.audio_state == self.JINGLE_STATE_CONNECTED:
|
if self.audio_state == self.JINGLE_STATE_CONNECTED:
|
||||||
# Set volume from config
|
# Set volume from config
|
||||||
input_vol = gajim.config.get('audio_input_volume')
|
input_vol = gajim.config.get('audio_input_volume')
|
||||||
|
@ -1568,11 +1641,11 @@ class ChatControl(ChatControlBase):
|
||||||
self.xml.get_object('mic_hscale').set_value(input_vol)
|
self.xml.get_object('mic_hscale').set_value(input_vol)
|
||||||
self.xml.get_object('sound_hscale').set_value(output_vol)
|
self.xml.get_object('sound_hscale').set_value(output_vol)
|
||||||
# Show vbox
|
# Show vbox
|
||||||
vbox.set_no_show_all(False)
|
hbox.set_no_show_all(False)
|
||||||
vbox.show_all()
|
hbox.show_all()
|
||||||
elif not self.audio_sid:
|
elif not self.audio_sid:
|
||||||
vbox.set_no_show_all(True)
|
hbox.set_no_show_all(True)
|
||||||
vbox.hide()
|
hbox.hide()
|
||||||
|
|
||||||
def update_video(self):
|
def update_video(self):
|
||||||
self._update_jingle('video')
|
self._update_jingle('video')
|
||||||
|
@ -1646,19 +1719,21 @@ class ChatControl(ChatControlBase):
|
||||||
def on_num_button_released(self, released):
|
def on_num_button_released(self, released):
|
||||||
self._get_audio_content()._stop_dtmf()
|
self._get_audio_content()._stop_dtmf()
|
||||||
|
|
||||||
def on_mic_hscale_value_changed(self, widget):
|
def on_dtmf_button_clicked(self, widget):
|
||||||
value = widget.get_value()
|
self.dtmf_window.show_all()
|
||||||
|
|
||||||
|
def on_dtmf_window_focus_out_event(self, widget, event):
|
||||||
|
self.dtmf_window.hide()
|
||||||
|
|
||||||
|
def on_mic_hscale_value_changed(self, widget, value):
|
||||||
self._get_audio_content().set_mic_volume(value / 100)
|
self._get_audio_content().set_mic_volume(value / 100)
|
||||||
# Save volume to config
|
# Save volume to config
|
||||||
# FIXME: Putting it here is maybe not the right thing to do?
|
|
||||||
gajim.config.set('audio_input_volume', value)
|
gajim.config.set('audio_input_volume', value)
|
||||||
|
|
||||||
|
|
||||||
def on_sound_hscale_value_changed(self, widget):
|
def on_sound_hscale_value_changed(self, widget, value):
|
||||||
value = widget.get_value()
|
|
||||||
self._get_audio_content().set_out_volume(value / 100)
|
self._get_audio_content().set_out_volume(value / 100)
|
||||||
# Save volume to config
|
# Save volume to config
|
||||||
# FIXME: Putting it here is maybe not the right thing to do?
|
|
||||||
gajim.config.set('audio_output_volume', value)
|
gajim.config.set('audio_output_volume', value)
|
||||||
|
|
||||||
def on_avatar_eventbox_enter_notify_event(self, widget, event):
|
def on_avatar_eventbox_enter_notify_event(self, widget, event):
|
||||||
|
@ -2048,20 +2123,23 @@ class ChatControl(ChatControlBase):
|
||||||
gobject.source_remove(self.possible_inactive_timeout_id)
|
gobject.source_remove(self.possible_inactive_timeout_id)
|
||||||
self._schedule_activity_timers()
|
self._schedule_activity_timers()
|
||||||
|
|
||||||
def _on_sent(id_, contact, message, encrypted, xhtml):
|
def _on_sent(id_, contact, message, encrypted, xhtml, label):
|
||||||
if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts',
|
if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts',
|
||||||
self.account, 'request_receipt'):
|
self.account, 'request_receipt'):
|
||||||
xep0184_id = id_
|
xep0184_id = id_
|
||||||
else:
|
else:
|
||||||
xep0184_id = None
|
xep0184_id = None
|
||||||
|
if label:
|
||||||
|
displaymarking = label.getTag('displaymarking')
|
||||||
|
else:
|
||||||
|
displaymarking = None
|
||||||
self.print_conversation(message, self.contact.jid, encrypted=encrypted,
|
self.print_conversation(message, self.contact.jid, encrypted=encrypted,
|
||||||
xep0184_id=xep0184_id, xhtml=xhtml)
|
xep0184_id=xep0184_id, xhtml=xhtml, displaymarking=displaymarking)
|
||||||
|
|
||||||
ChatControlBase.send_message(self, message, keyID, type_='chat',
|
ChatControlBase.send_message(self, message, keyID, type_='chat',
|
||||||
chatstate=chatstate_to_send, composing_xep=composing_xep,
|
chatstate=chatstate_to_send, composing_xep=composing_xep,
|
||||||
xhtml=xhtml, callback=_on_sent,
|
xhtml=xhtml, callback=_on_sent,
|
||||||
callback_args=[contact, message, encrypted, xhtml],
|
callback_args=[contact, message, encrypted, xhtml, self.get_seclabel()],
|
||||||
process_commands=process_commands)
|
process_commands=process_commands)
|
||||||
|
|
||||||
def check_for_possible_paused_chatstate(self, arg):
|
def check_for_possible_paused_chatstate(self, arg):
|
||||||
|
@ -2125,6 +2203,18 @@ class ChatControl(ChatControlBase):
|
||||||
msg = _('Session negotiation cancelled')
|
msg = _('Session negotiation cancelled')
|
||||||
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
|
def print_archiving_session_details(self):
|
||||||
|
"""
|
||||||
|
Print esession settings to textview
|
||||||
|
"""
|
||||||
|
archiving = bool(self.session) and isinstance(self.session,
|
||||||
|
ArchivingStanzaSession) and self.session.archiving
|
||||||
|
if archiving:
|
||||||
|
msg = _('This session WILL be archived on server')
|
||||||
|
else:
|
||||||
|
msg = _('This session WILL NOT be archived on server')
|
||||||
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
def print_esession_details(self):
|
def print_esession_details(self):
|
||||||
"""
|
"""
|
||||||
Print esession settings to textview
|
Print esession settings to textview
|
||||||
|
@ -2149,8 +2239,15 @@ class ChatControl(ChatControlBase):
|
||||||
self._show_lock_image(e2e_is_active, 'E2E', e2e_is_active, self.session and \
|
self._show_lock_image(e2e_is_active, 'E2E', e2e_is_active, self.session and \
|
||||||
self.session.is_loggable(), self.session and self.session.verified_identity)
|
self.session.is_loggable(), self.session and self.session.verified_identity)
|
||||||
|
|
||||||
|
def print_session_details(self):
|
||||||
|
if isinstance(self.session, EncryptedStanzaSession):
|
||||||
|
self.print_esession_details()
|
||||||
|
elif isinstance(self.session, ArchivingStanzaSession):
|
||||||
|
self.print_archiving_session_details()
|
||||||
|
|
||||||
def print_conversation(self, text, frm='', tim=None, encrypted=False,
|
def print_conversation(self, text, frm='', tim=None, encrypted=False,
|
||||||
subject=None, xhtml=None, simple=False, xep0184_id=None):
|
subject=None, xhtml=None, simple=False, xep0184_id=None,
|
||||||
|
displaymarking=None):
|
||||||
"""
|
"""
|
||||||
Print a line in the conversation
|
Print a line in the conversation
|
||||||
|
|
||||||
|
@ -2213,7 +2310,7 @@ class ChatControl(ChatControlBase):
|
||||||
xhtml = '<body xmlns="%s">%s</body>' % (NS_XHTML, xhtml)
|
xhtml = '<body xmlns="%s">%s</body>' % (NS_XHTML, xhtml)
|
||||||
ChatControlBase.print_conversation_line(self, text, kind, name, tim,
|
ChatControlBase.print_conversation_line(self, text, kind, name, tim,
|
||||||
subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml,
|
subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml,
|
||||||
simple=simple, xep0184_id=xep0184_id)
|
simple=simple, xep0184_id=xep0184_id, displaymarking=displaymarking)
|
||||||
if text.startswith('/me ') or text.startswith('/me\n'):
|
if text.startswith('/me ') or text.startswith('/me\n'):
|
||||||
self.old_msg_kind = None
|
self.old_msg_kind = None
|
||||||
else:
|
else:
|
||||||
|
@ -2397,7 +2494,13 @@ class ChatControl(ChatControlBase):
|
||||||
self.reset_kbd_mouse_timeout_vars()
|
self.reset_kbd_mouse_timeout_vars()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
# Send 'gone' chatstate
|
# PluginSystem: calling shutdown of super class (ChatControlBase) to let it remove
|
||||||
|
# it's GUI extension points
|
||||||
|
super(ChatControl, self).shutdown()
|
||||||
|
# PluginSystem: removing GUI extension points connected with ChatControl
|
||||||
|
# instance object
|
||||||
|
gajim.plugin_manager.remove_gui_extension_point('chat_control', self) # Send 'gone' chatstate
|
||||||
|
|
||||||
self.send_chatstate('gone', self.contact)
|
self.send_chatstate('gone', self.contact)
|
||||||
self.contact.chatstate = None
|
self.contact.chatstate = None
|
||||||
self.contact.our_chatstate = None
|
self.contact.our_chatstate = None
|
||||||
|
@ -2574,6 +2677,9 @@ class ChatControl(ChatControlBase):
|
||||||
if want_e2e and not self.no_autonegotiation \
|
if want_e2e and not self.no_autonegotiation \
|
||||||
and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION):
|
and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION):
|
||||||
self.begin_e2e_negotiation()
|
self.begin_e2e_negotiation()
|
||||||
|
elif (not self.session or not self.session.status) and \
|
||||||
|
gajim.connections[self.account].archiving_supported:
|
||||||
|
self.begin_archiving_negotiation()
|
||||||
else:
|
else:
|
||||||
self.send_chatstate('active', self.contact)
|
self.send_chatstate('active', self.contact)
|
||||||
|
|
||||||
|
@ -2660,8 +2766,12 @@ class ChatControl(ChatControlBase):
|
||||||
kind = 'info'
|
kind = 'info'
|
||||||
else:
|
else:
|
||||||
kind = 'print_queue'
|
kind = 'print_queue'
|
||||||
|
dm = None
|
||||||
|
if len(data) > 10:
|
||||||
|
dm = data[10]
|
||||||
self.print_conversation(data[0], kind, tim = data[3],
|
self.print_conversation(data[0], kind, tim = data[3],
|
||||||
encrypted = data[4], subject = data[1], xhtml = data[7])
|
encrypted = data[4], subject = data[1], xhtml = data[7],
|
||||||
|
displaymarking=dm)
|
||||||
if len(data) > 6 and isinstance(data[6], int):
|
if len(data) > 6 and isinstance(data[6], int):
|
||||||
message_ids.append(data[6])
|
message_ids.append(data[6])
|
||||||
|
|
||||||
|
@ -2813,7 +2923,7 @@ class ChatControl(ChatControlBase):
|
||||||
else:
|
else:
|
||||||
self.begin_e2e_negotiation()
|
self.begin_e2e_negotiation()
|
||||||
|
|
||||||
def begin_e2e_negotiation(self):
|
def begin_negotiation(self):
|
||||||
self.no_autonegotiation = True
|
self.no_autonegotiation = True
|
||||||
|
|
||||||
if not self.session:
|
if not self.session:
|
||||||
|
@ -2821,8 +2931,14 @@ class ChatControl(ChatControlBase):
|
||||||
new_sess = gajim.connections[self.account].make_new_session(fjid, type_=self.type_id)
|
new_sess = gajim.connections[self.account].make_new_session(fjid, type_=self.type_id)
|
||||||
self.set_session(new_sess)
|
self.set_session(new_sess)
|
||||||
|
|
||||||
|
def begin_e2e_negotiation(self):
|
||||||
|
self.begin_negotiation()
|
||||||
self.session.negotiate_e2e(False)
|
self.session.negotiate_e2e(False)
|
||||||
|
|
||||||
|
def begin_archiving_negotiation(self):
|
||||||
|
self.begin_negotiation()
|
||||||
|
self.session.negotiate_archiving()
|
||||||
|
|
||||||
def got_connected(self):
|
def got_connected(self):
|
||||||
ChatControlBase.got_connected(self)
|
ChatControlBase.got_connected(self)
|
||||||
# Refreshing contact
|
# Refreshing contact
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
# Copyright (c) 2010, Alexander Cherniuk (ts33kr@gmail.com)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Backbone of the command system. Provides smart and controllable
|
||||||
|
dispatching mechanism with an auto-discovery functionality. In addition
|
||||||
|
to automatic discovery and dispatching, also features manual control
|
||||||
|
over the process.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from types import NoneType
|
||||||
|
from tools import remove
|
||||||
|
|
||||||
|
COMMANDS = {}
|
||||||
|
CONTAINERS = {}
|
||||||
|
|
||||||
|
def add_host(host):
|
||||||
|
CONTAINERS[host] = []
|
||||||
|
|
||||||
|
def remove_host(host):
|
||||||
|
remove(CONTAINERS, host)
|
||||||
|
|
||||||
|
def add_container(container):
|
||||||
|
for host in container.HOSTS:
|
||||||
|
CONTAINERS[host].append(container)
|
||||||
|
|
||||||
|
def remove_container(container):
|
||||||
|
for host in container.HOSTS:
|
||||||
|
remove(CONTAINERS[host], container)
|
||||||
|
|
||||||
|
def add_commands(container):
|
||||||
|
commands = COMMANDS.setdefault(container, {})
|
||||||
|
for command in traverse_commands(container):
|
||||||
|
for name in command.names:
|
||||||
|
commands[name] = command
|
||||||
|
|
||||||
|
def remove_commands(container):
|
||||||
|
remove(COMMANDS, container)
|
||||||
|
|
||||||
|
def traverse_commands(container):
|
||||||
|
for name in dir(container):
|
||||||
|
attribute = getattr(container, name)
|
||||||
|
if is_command(attribute):
|
||||||
|
yield attribute
|
||||||
|
|
||||||
|
def is_command(attribute):
|
||||||
|
from framework import Command
|
||||||
|
return isinstance(attribute, Command)
|
||||||
|
|
||||||
|
def is_root(namespace):
|
||||||
|
metaclass = namespace.get("__metaclass__", NoneType)
|
||||||
|
return issubclass(metaclass, Dispatchable)
|
||||||
|
|
||||||
|
def get_command(host, name):
|
||||||
|
for container in CONTAINERS[host]:
|
||||||
|
command = COMMANDS[container].get(name)
|
||||||
|
if command:
|
||||||
|
return command
|
||||||
|
|
||||||
|
def list_commands(host):
|
||||||
|
for container in CONTAINERS[host]:
|
||||||
|
commands = COMMANDS[container]
|
||||||
|
for name, command in commands.iteritems():
|
||||||
|
yield name, command
|
||||||
|
|
||||||
|
class Dispatchable(type):
|
||||||
|
|
||||||
|
def __init__(self, name, bases, namespace):
|
||||||
|
parents = super(Dispatchable, self)
|
||||||
|
parents.__init__(name, bases, namespace)
|
||||||
|
if not is_root(namespace):
|
||||||
|
self.dispatch()
|
||||||
|
|
||||||
|
def dispatch(self):
|
||||||
|
if self.AUTOMATIC:
|
||||||
|
self.enable()
|
||||||
|
|
||||||
|
class Host(Dispatchable):
|
||||||
|
|
||||||
|
def enable(self):
|
||||||
|
add_host(self)
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
remove_host(self)
|
||||||
|
|
||||||
|
class Container(Dispatchable):
|
||||||
|
|
||||||
|
def enable(self):
|
||||||
|
add_container(self)
|
||||||
|
add_commands(self)
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
remove_commands(self)
|
||||||
|
remove_container(self)
|
|
@ -1,90 +0,0 @@
|
||||||
# Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
"""
|
|
||||||
The backbone of the command system. Provides automatic dispatching which
|
|
||||||
does not require explicit registering commands or containers and remains
|
|
||||||
active even after everything is done, so new commands can be added
|
|
||||||
during the runtime.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from types import NoneType
|
|
||||||
|
|
||||||
class Dispatcher(type):
|
|
||||||
|
|
||||||
containers = {}
|
|
||||||
commands = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def register_host(klass, host):
|
|
||||||
klass.containers[host] = []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def register_container(klass, container):
|
|
||||||
for host in container.HOSTS:
|
|
||||||
klass.containers[host].append(container)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def register_commands(klass, container):
|
|
||||||
klass.commands[container] = {}
|
|
||||||
for command in klass.traverse_commands(container):
|
|
||||||
for name in command.names:
|
|
||||||
klass.commands[container][name] = command
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_command(klass, host, name):
|
|
||||||
for container in klass.containers[host]:
|
|
||||||
command = klass.commands[container].get(name)
|
|
||||||
if command:
|
|
||||||
return command
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def list_commands(klass, host):
|
|
||||||
for container in klass.containers[host]:
|
|
||||||
commands = klass.commands[container]
|
|
||||||
for name, command in commands.iteritems():
|
|
||||||
yield name, command
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def traverse_commands(klass, container):
|
|
||||||
for name in dir(container):
|
|
||||||
attribute = getattr(container, name)
|
|
||||||
if klass.is_command(attribute):
|
|
||||||
yield attribute
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_root(ns):
|
|
||||||
meta = ns.get('__metaclass__', NoneType)
|
|
||||||
return issubclass(meta, Dispatcher)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_command(attribute):
|
|
||||||
name = attribute.__class__.__name__
|
|
||||||
return name == 'Command'
|
|
||||||
|
|
||||||
class HostDispatcher(Dispatcher):
|
|
||||||
|
|
||||||
def __init__(klass, name, bases, ns):
|
|
||||||
if not Dispatcher.is_root(ns):
|
|
||||||
HostDispatcher.register_host(klass)
|
|
||||||
super(HostDispatcher, klass).__init__(name, bases, ns)
|
|
||||||
|
|
||||||
class ContainerDispatcher(Dispatcher):
|
|
||||||
|
|
||||||
def __init__(klass, name, bases, ns):
|
|
||||||
if not Dispatcher.is_root(ns):
|
|
||||||
ContainerDispatcher.register_container(klass)
|
|
||||||
ContainerDispatcher.register_commands(klass)
|
|
||||||
super(ContainerDispatcher, klass).__init__(name, bases, ns)
|
|
|
@ -21,9 +21,10 @@ declarative way.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
from inspect import getargspec
|
from inspect import getargspec, getdoc
|
||||||
|
|
||||||
from dispatching import Dispatcher, HostDispatcher, ContainerDispatcher
|
from dispatcher import Host, Container
|
||||||
|
from dispatcher import get_command, list_commands
|
||||||
from mapping import parse_arguments, adapt_arguments
|
from mapping import parse_arguments, adapt_arguments
|
||||||
from errors import DefinitionError, CommandError, NoCommandError
|
from errors import DefinitionError, CommandError, NoCommandError
|
||||||
|
|
||||||
|
@ -32,8 +33,12 @@ class CommandHost(object):
|
||||||
Command host is a hub between numerous command processors and
|
Command host is a hub between numerous command processors and
|
||||||
command containers. Aimed to participate in a dispatching process in
|
command containers. Aimed to participate in a dispatching process in
|
||||||
order to provide clean and transparent architecture.
|
order to provide clean and transparent architecture.
|
||||||
|
|
||||||
|
The AUTOMATIC class variable, which must be defined by a command
|
||||||
|
host, specifies whether the command host should be automatically
|
||||||
|
dispatched and enabled by the dispatcher or not.
|
||||||
"""
|
"""
|
||||||
__metaclass__ = HostDispatcher
|
__metaclass__ = Host
|
||||||
|
|
||||||
class CommandContainer(object):
|
class CommandContainer(object):
|
||||||
"""
|
"""
|
||||||
|
@ -41,11 +46,15 @@ class CommandContainer(object):
|
||||||
allowing them to be dispatched and proccessed correctly. Each
|
allowing them to be dispatched and proccessed correctly. Each
|
||||||
command container may be bound to a one or more command hosts.
|
command container may be bound to a one or more command hosts.
|
||||||
|
|
||||||
Bounding is controlled by the HOSTS variable, which must be defined
|
The AUTOMATIC class variable, which must be defined by a command
|
||||||
in the body of the command container. This variable should contain a
|
processor, specifies whether the command processor should be
|
||||||
list of hosts to bound to, as a tuple or list.
|
automatically dispatched and enabled by the dispatcher or not.
|
||||||
|
|
||||||
|
Bounding is controlled by the HOSTS class variable, which must be
|
||||||
|
defined by the command container. This variable should contain a
|
||||||
|
sequence of hosts to bound to, as a tuple or list.
|
||||||
"""
|
"""
|
||||||
__metaclass__ = ContainerDispatcher
|
__metaclass__ = Container
|
||||||
|
|
||||||
class CommandProcessor(object):
|
class CommandProcessor(object):
|
||||||
"""
|
"""
|
||||||
|
@ -126,24 +135,18 @@ class CommandProcessor(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_command(self, name):
|
def get_command(self, name):
|
||||||
command = Dispatcher.get_command(self.COMMAND_HOST, name)
|
command = get_command(self.COMMAND_HOST, name)
|
||||||
if not command:
|
if not command:
|
||||||
raise NoCommandError("Command does not exist", name=name)
|
raise NoCommandError("Command does not exist", name=name)
|
||||||
return command
|
return command
|
||||||
|
|
||||||
def list_commands(self):
|
def list_commands(self):
|
||||||
commands = Dispatcher.list_commands(self.COMMAND_HOST)
|
commands = list_commands(self.COMMAND_HOST)
|
||||||
commands = dict(commands)
|
commands = dict(commands)
|
||||||
return sorted(set(commands.itervalues()))
|
return sorted(set(commands.itervalues()))
|
||||||
|
|
||||||
class Command(object):
|
class Command(object):
|
||||||
|
|
||||||
# These two regular expression patterns control how command
|
|
||||||
# documentation will be formatted to be transformed to a normal,
|
|
||||||
# readable state.
|
|
||||||
DOC_STRIP_PATTERN = re.compile(r'(?:^[ \t]+|\A\n)', re.MULTILINE)
|
|
||||||
DOC_FORMAT_PATTERN = re.compile(r'(?<!\n)\n(?!\n)', re.MULTILINE)
|
|
||||||
|
|
||||||
def __init__(self, handler, *names, **properties):
|
def __init__(self, handler, *names, **properties):
|
||||||
self.handler = handler
|
self.handler = handler
|
||||||
self.names = names
|
self.names = names
|
||||||
|
@ -192,19 +195,8 @@ class Command(object):
|
||||||
"""
|
"""
|
||||||
Extract handler's documentation which is a doc-string and
|
Extract handler's documentation which is a doc-string and
|
||||||
transform it to a usable format.
|
transform it to a usable format.
|
||||||
|
|
||||||
Transformation is done based on the DOC_STRIP_PATTERN and
|
|
||||||
DOC_FORMAT_PATTERN regular expression patterns.
|
|
||||||
"""
|
"""
|
||||||
documentation = self.handler.__doc__ or None
|
return getdoc(self.handler)
|
||||||
|
|
||||||
if not documentation:
|
|
||||||
return
|
|
||||||
|
|
||||||
documentation = re.sub(self.DOC_STRIP_PATTERN, str(), documentation)
|
|
||||||
documentation = re.sub(self.DOC_FORMAT_PATTERN, ' ', documentation)
|
|
||||||
|
|
||||||
return documentation
|
|
||||||
|
|
||||||
def extract_description(self):
|
def extract_description(self):
|
||||||
"""
|
"""
|
||||||
|
@ -243,9 +235,9 @@ def command(*names, **properties):
|
||||||
can be reached. If no names are given - the the native name (the one
|
can be reached. If no names are given - the the native name (the one
|
||||||
extracted from the command handler) will be used.
|
extracted from the command handler) will be used.
|
||||||
|
|
||||||
If include_native=True is given (default) and names is non-empty -
|
If native=True is given (default) and names is non-empty - then the
|
||||||
then the native name of the command will be prepended in addition to
|
native name of the command will be prepended in addition to the
|
||||||
the given names.
|
given names.
|
||||||
|
|
||||||
If usage=True is given (default) - then command help will be
|
If usage=True is given (default) - then command help will be
|
||||||
appended with autogenerated usage info, based of the command handler
|
appended with autogenerated usage info, based of the command handler
|
||||||
|
@ -273,14 +265,14 @@ def command(*names, **properties):
|
||||||
If overlap=True is given - then all the extra arguments will be
|
If overlap=True is given - then all the extra arguments will be
|
||||||
mapped as if they were values for the keyword arguments.
|
mapped as if they were values for the keyword arguments.
|
||||||
|
|
||||||
If expand_short=True is given (default) - then short, one-letter
|
If expand=True is given (default) - then short, one-letter options
|
||||||
options will be expanded to a verbose ones, based of the comparison
|
will be expanded to a verbose ones, based of the comparison of the
|
||||||
of the first letter. If more then one option with the same first
|
first letter. If more then one option with the same first letter is
|
||||||
letter is given - then only first one will be used in the expansion.
|
given - then only first one will be used in the expansion.
|
||||||
"""
|
"""
|
||||||
names = list(names)
|
names = list(names)
|
||||||
|
|
||||||
include_native = properties.get('include_native', True)
|
native = properties.get('native', True)
|
||||||
|
|
||||||
usage = properties.get('usage', True)
|
usage = properties.get('usage', True)
|
||||||
source = properties.get('source', False)
|
source = properties.get('source', False)
|
||||||
|
@ -288,7 +280,7 @@ def command(*names, **properties):
|
||||||
empty = properties.get('empty', False)
|
empty = properties.get('empty', False)
|
||||||
extra = properties.get('extra', False)
|
extra = properties.get('extra', False)
|
||||||
overlap = properties.get('overlap', False)
|
overlap = properties.get('overlap', False)
|
||||||
expand_short = properties.get('expand_short', True)
|
expand = properties.get('expand', True)
|
||||||
|
|
||||||
if empty and not raw:
|
if empty and not raw:
|
||||||
raise DefinitionError("Empty option can be used only with raw commands")
|
raise DefinitionError("Empty option can be used only with raw commands")
|
||||||
|
@ -303,7 +295,7 @@ def command(*names, **properties):
|
||||||
'extra': extra,
|
'extra': extra,
|
||||||
'overlap': overlap,
|
'overlap': overlap,
|
||||||
'empty': empty,
|
'empty': empty,
|
||||||
'expand_short': expand_short
|
'expand': expand
|
||||||
}
|
}
|
||||||
|
|
||||||
def decorator(handler):
|
def decorator(handler):
|
||||||
|
@ -314,9 +306,9 @@ def command(*names, **properties):
|
||||||
command = Command(handler, *names, **properties)
|
command = Command(handler, *names, **properties)
|
||||||
|
|
||||||
# Extract and inject a native name if either no other names are
|
# Extract and inject a native name if either no other names are
|
||||||
# specified or include_native property is enabled, while making
|
# specified or native property is enabled, while making
|
||||||
# sure it is going to be the first one in the list.
|
# sure it is going to be the first one in the list.
|
||||||
if not names or include_native:
|
if not names or native:
|
||||||
names.insert(0, command.native_name)
|
names.insert(0, command.native_name)
|
||||||
command.names = tuple(names)
|
command.names = tuple(names)
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,56 @@
|
||||||
# Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
|
# Copyright (c) 2009-2010, Alexander Cherniuk (ts33kr@gmail.com)
|
||||||
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# it under the terms of the GNU General Public License as published by
|
# modification, are permitted provided that the following conditions
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# are met:
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful,
|
# * Redistributions of source code must retain the above copyright
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# notice, this list of conditions and the following disclaimer.
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The module contains examples of how to create your own commands, by
|
This module contains examples of how to create your own commands, by
|
||||||
creating a new command container and definding a set of commands.
|
creating a new command container, bounded to a specific command host,
|
||||||
|
and definding a set of commands inside of it.
|
||||||
|
|
||||||
Keep in mind that this module is not being loaded, so the code will not
|
Keep in mind that this module is not being loaded from anywhere, so the
|
||||||
be executed and commands defined here will not be detected.
|
code in here will not be executed and commands defined here will not be
|
||||||
|
detected.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ..framework import CommandContainer, command, doc
|
from ..framework import CommandContainer, command, doc
|
||||||
from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands
|
from hosts import *
|
||||||
|
|
||||||
class CustomCommonCommands(CommandContainer):
|
class CustomCommonCommands(CommandContainer):
|
||||||
"""
|
"""
|
||||||
|
The AUTOMATIC class variable, set to a positive value, instructs the
|
||||||
|
command system to automatically discover the command container and
|
||||||
|
enable it.
|
||||||
|
|
||||||
This command container bounds to all three available in the default
|
This command container bounds to all three available in the default
|
||||||
implementation command hosts. This means that commands defined in
|
implementation command hosts. This means that commands defined in
|
||||||
this container will be available to all - chat, private chat and a
|
this container will be available to all: chat, private chat and a
|
||||||
group chat.
|
group chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (ChatCommands, PrivateChatCommands, GroupChatCommands)
|
AUTOMATIC = True
|
||||||
|
HOSTS = ChatCommands, PrivateChatCommands, GroupChatCommands
|
||||||
|
|
||||||
@command
|
@command
|
||||||
def dance(self):
|
def dance(self):
|
||||||
|
@ -46,45 +64,58 @@ class CustomCommonCommands(CommandContainer):
|
||||||
|
|
||||||
After all the documentation - there will be autogenerated (based
|
After all the documentation - there will be autogenerated (based
|
||||||
on the method signature) usage information appended. You can
|
on the method signature) usage information appended. You can
|
||||||
turn it off though, if you want.
|
turn it off, if you want.
|
||||||
"""
|
"""
|
||||||
return "I can't dance, you stupid fuck, I'm just a command system! A cool one, though..."
|
return "I don't dance."
|
||||||
|
|
||||||
class CustomChatCommands(CommandContainer):
|
class CustomChatCommands(CommandContainer):
|
||||||
"""
|
"""
|
||||||
This command container bounds only to the ChatCommands command host.
|
This command container bounds only to the ChatCommands command host.
|
||||||
Therefore command defined here will be available only to a chat.
|
Therefore commands defined inside of the container will be available
|
||||||
|
only to a chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (ChatCommands,)
|
AUTOMATIC = True
|
||||||
|
HOSTS = ChatCommands,
|
||||||
|
|
||||||
@doc(_("The same as using a doc-string, except it supports translation"))
|
@command("squal", "bawl")
|
||||||
@command
|
|
||||||
def sing(self):
|
def sing(self):
|
||||||
return "Are you phreaking kidding me? Buy yourself a damn stereo..."
|
"""
|
||||||
|
This command has an additional aliases. It means the command will
|
||||||
|
be available under three names: sing (the native name), squal
|
||||||
|
(the first alias), bawl (the second alias).
|
||||||
|
|
||||||
|
You can turn off the usage of the native name, if you want, and
|
||||||
|
specify a name or a set of names, as aliases, under which a
|
||||||
|
command will be available.
|
||||||
|
"""
|
||||||
|
return "Buy yourself a stereo."
|
||||||
|
|
||||||
class CustomPrivateChatCommands(CommandContainer):
|
class CustomPrivateChatCommands(CommandContainer):
|
||||||
"""
|
"""
|
||||||
This command container bounds only to the PrivateChatCommands
|
This command container bounds only to the PrivateChatCommands
|
||||||
command host. Therefore command defined here will be available only
|
command host. Therefore commands defined inside of the container
|
||||||
to a private chat.
|
will be available only to a private chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (PrivateChatCommands,)
|
AUTOMATIC = True
|
||||||
|
HOSTS = PrivateChatCommands,
|
||||||
|
|
||||||
@command
|
@command
|
||||||
|
@doc(_("The same as using a doc-string, except it supports translation"))
|
||||||
def make_coffee(self):
|
def make_coffee(self):
|
||||||
return "What do I look like, you ass? A coffee machine!?"
|
return "I'm not a coffee machine!"
|
||||||
|
|
||||||
class CustomGroupChatCommands(CommandContainer):
|
class CustomGroupChatCommands(CommandContainer):
|
||||||
"""
|
"""
|
||||||
This command container bounds only to the GroupChatCommands command
|
This command container bounds only to the GroupChatCommands command
|
||||||
host. Therefore command defined here will be available only to a
|
host. Therefore commands defined inside of the container will be
|
||||||
group chat.
|
available only to a group chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (GroupChatCommands,)
|
AUTOMATIC = True
|
||||||
|
HOSTS = GroupChatCommands,
|
||||||
|
|
||||||
@command
|
@command
|
||||||
def fetch(self):
|
def fetch(self):
|
||||||
return "You should really buy yourself a dog and start torturing it instead of me..."
|
return "Buy yourself a dog."
|
|
@ -0,0 +1,120 @@
|
||||||
|
# Copyright (c) 2010, Alexander Cherniuk (ts33kr@gmail.com)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Provides facilities to safely execute expressions inside a shell process
|
||||||
|
and capture the resulting output, in an asynchronous fashion, avoiding
|
||||||
|
deadlocks. If the process execution time reaches the threshold - it is
|
||||||
|
forced to terminate. Consists of a tiny framework and a couple of
|
||||||
|
commands as a frontend.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
from os.path import expanduser
|
||||||
|
|
||||||
|
from glib import timeout_add
|
||||||
|
|
||||||
|
from ..framework import CommandContainer, command, doc
|
||||||
|
from hosts import *
|
||||||
|
|
||||||
|
class Execute(CommandContainer):
|
||||||
|
AUTOMATIC = True
|
||||||
|
HOSTS = ChatCommands, PrivateChatCommands, GroupChatCommands
|
||||||
|
|
||||||
|
DIRECTORY = "~"
|
||||||
|
|
||||||
|
POLL_INTERVAL = 100
|
||||||
|
POLL_COUNT = 5
|
||||||
|
|
||||||
|
@command("exec", raw=True)
|
||||||
|
@doc(_("Execute expression inside a shell, show output"))
|
||||||
|
def execute(self, expression):
|
||||||
|
Execute.spawn(self, expression)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def spawn(cls, processor, expression):
|
||||||
|
pipes = dict(stdout=PIPE, stderr=PIPE)
|
||||||
|
directory = expanduser(cls.DIRECTORY)
|
||||||
|
popen = Popen(expression, shell=True, cwd=directory, **pipes)
|
||||||
|
cls.monitor(processor, popen)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def monitor(cls, processor, popen):
|
||||||
|
poller = cls.poller(processor, popen)
|
||||||
|
timeout_add(cls.POLL_INTERVAL, poller.next)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poller(cls, processor, popen):
|
||||||
|
for x in xrange(cls.POLL_COUNT):
|
||||||
|
yield cls.brush(processor, popen)
|
||||||
|
cls.overdue(processor, popen)
|
||||||
|
yield False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def brush(cls, processor, popen):
|
||||||
|
if popen.poll() is not None:
|
||||||
|
cls.terminated(processor, popen)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def terminated(cls, processor, popen):
|
||||||
|
stdout, stderr = cls.fetch(popen)
|
||||||
|
success = popen.returncode == 0
|
||||||
|
if success and stdout:
|
||||||
|
processor.echo(stdout)
|
||||||
|
elif not success and stderr:
|
||||||
|
processor.echo_error(stderr)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def overdue(cls, processor, popen):
|
||||||
|
popen.terminate()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetch(cls, popen):
|
||||||
|
data = popen.communicate()
|
||||||
|
return map(cls.clean, data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clean(text):
|
||||||
|
strip = chr(10) + chr(32)
|
||||||
|
return text.strip(strip)
|
||||||
|
|
||||||
|
class Show(Execute):
|
||||||
|
|
||||||
|
@command("sh", raw=True)
|
||||||
|
@doc(_("Execute expression inside a shell, send output"))
|
||||||
|
def show(self, expression):
|
||||||
|
Show.spawn(self, expression)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def terminated(cls, processor, popen):
|
||||||
|
stdout, stderr = cls.fetch(popen)
|
||||||
|
success = popen.returncode == 0
|
||||||
|
if success and stdout:
|
||||||
|
processor.send(stdout)
|
||||||
|
elif not success and stderr:
|
||||||
|
processor.echo_error(stderr)
|
|
@ -25,18 +25,18 @@ class ChatCommands(CommandHost):
|
||||||
This command host is bound to the command processor which processes
|
This command host is bound to the command processor which processes
|
||||||
commands from a chat.
|
commands from a chat.
|
||||||
"""
|
"""
|
||||||
pass
|
AUTOMATIC = True
|
||||||
|
|
||||||
class PrivateChatCommands(CommandHost):
|
class PrivateChatCommands(CommandHost):
|
||||||
"""
|
"""
|
||||||
This command host is bound to the command processor which processes
|
This command host is bound to the command processor which processes
|
||||||
commands from a private chat.
|
commands from a private chat.
|
||||||
"""
|
"""
|
||||||
pass
|
AUTOMATIC = True
|
||||||
|
|
||||||
class GroupChatCommands(CommandHost):
|
class GroupChatCommands(CommandHost):
|
||||||
"""
|
"""
|
||||||
This command host is bound to the command processor which processes
|
This command host is bound to the command processor which processes
|
||||||
commands from a group chat.
|
commands from a group chat.
|
||||||
"""
|
"""
|
||||||
pass
|
AUTOMATIC = True
|
||||||
|
|
|
@ -1,42 +1,58 @@
|
||||||
# Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
|
# Copyright (c) 2009-2010, Alexander Cherniuk (ts33kr@gmail.com)
|
||||||
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# it under the terms of the GNU General Public License as published by
|
# modification, are permitted provided that the following conditions
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# are met:
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful,
|
# * Redistributions of source code must retain the above copyright
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# notice, this list of conditions and the following disclaimer.
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Provides a glue to tie command system framework and the actual code
|
Provides a glue to tie command system framework and the actual code
|
||||||
where it would be dropped in. Defines a little bit of scaffolding to
|
where it would be dropped in. Defines a little bit of scaffolding to
|
||||||
support interaction between the two and a few utility methods so you
|
support interaction between the two and a few utility methods so you
|
||||||
don't need to dig up the code itself code to write basic commands.
|
don't need to dig up the code itself to write basic commands.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from types import StringTypes
|
from types import StringTypes
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
|
|
||||||
|
from pango import FontDescription
|
||||||
from common import gajim
|
from common import gajim
|
||||||
|
|
||||||
from ..framework import CommandProcessor
|
from ..framework import CommandProcessor
|
||||||
from ..errors import CommandError, NoCommandError
|
from ..errors import CommandError, NoCommandError
|
||||||
|
from ..tools import gconf
|
||||||
|
|
||||||
class ChatCommandProcessor(CommandProcessor):
|
class ChatCommandProcessor(CommandProcessor):
|
||||||
"""
|
"""
|
||||||
A basic scaffolding to provide convenient interaction between the
|
A basic scaffolding to provide convenient interaction between the
|
||||||
command system and chat controls.
|
command system and chat controls. It will be merged directly into
|
||||||
|
the controls, by ChatCommandProcessor being among superclasses of
|
||||||
|
the controls.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def process_as_command(self, text):
|
def process_as_command(self, text):
|
||||||
self.command_succeeded = False
|
self.command_succeeded = False
|
||||||
flag = super(ChatCommandProcessor, self).process_as_command(text)
|
parents = super(ChatCommandProcessor, self)
|
||||||
|
flag = parents.process_as_command(text)
|
||||||
if flag and self.command_succeeded:
|
if flag and self.command_succeeded:
|
||||||
self.add_history(text)
|
self.add_history(text)
|
||||||
self.clear_input()
|
self.clear_input()
|
||||||
|
@ -44,17 +60,18 @@ class ChatCommandProcessor(CommandProcessor):
|
||||||
|
|
||||||
def execute_command(self, name, arguments):
|
def execute_command(self, name, arguments):
|
||||||
try:
|
try:
|
||||||
super(ChatCommandProcessor, self).execute_command(name, arguments)
|
parents = super(ChatCommandProcessor, self)
|
||||||
|
parents.execute_command(name, arguments)
|
||||||
except NoCommandError, error:
|
except NoCommandError, error:
|
||||||
details = dict(name=error.name, message=error.message)
|
details = dict(name=error.name, message=error.message)
|
||||||
message = "%(name)s: %(message)s\n" % details
|
message = "%(name)s: %(message)s\n" % details
|
||||||
message += "Try using the //%(name)s or /say /%(name)s " % details
|
message += "Try using the //%(name)s or /say /%(name)s " % details
|
||||||
message += "construct if you intended to send it as a text."
|
message += "construct if you intended to send it as a text."
|
||||||
self.echo(message, 'error')
|
self.echo_error(message)
|
||||||
except CommandError, error:
|
except CommandError, error:
|
||||||
self.echo("%s: %s" % (error.name, error.message), 'error')
|
self.echo_error("%s: %s" % (error.name, error.message))
|
||||||
except Exception:
|
except Exception:
|
||||||
self.echo("An error occured while trying to execute the command", 'error')
|
self.echo_error("Error during command execution!")
|
||||||
print_exc()
|
print_exc()
|
||||||
else:
|
else:
|
||||||
self.command_succeeded = True
|
self.command_succeeded = True
|
||||||
|
@ -87,14 +104,52 @@ class ChatCommandProcessor(CommandProcessor):
|
||||||
class CommandTools:
|
class CommandTools:
|
||||||
"""
|
"""
|
||||||
Contains a set of basic tools and shortcuts you can use in your
|
Contains a set of basic tools and shortcuts you can use in your
|
||||||
commands to performe some simple operations.
|
commands to perform some simple operations. These will be merged
|
||||||
|
directly into the controls, by CommandTools being among superclasses
|
||||||
|
of the controls.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def echo(self, text, kind='info'):
|
def __init__(self):
|
||||||
|
self.install_tags()
|
||||||
|
|
||||||
|
def install_tags(self):
|
||||||
|
buffer = self.conv_textview.tv.get_buffer()
|
||||||
|
|
||||||
|
name = gconf("/desktop/gnome/interface/monospace_font_name")
|
||||||
|
name = name if name else "Monospace"
|
||||||
|
font = FontDescription(name)
|
||||||
|
|
||||||
|
command_ok_tag = buffer.create_tag("command_ok")
|
||||||
|
command_ok_tag.set_property("font-desc", font)
|
||||||
|
command_ok_tag.set_property("foreground", "#3465A4")
|
||||||
|
|
||||||
|
command_error_tag = buffer.create_tag("command_error")
|
||||||
|
command_error_tag.set_property("font-desc", font)
|
||||||
|
command_error_tag.set_property("foreground", "#F57900")
|
||||||
|
|
||||||
|
def shift_line(self):
|
||||||
|
buffer = self.conv_textview.tv.get_buffer()
|
||||||
|
iter = buffer.get_end_iter()
|
||||||
|
if iter.ends_line() and not iter.is_start():
|
||||||
|
buffer.insert_with_tags_by_name(iter, "\n", "eol")
|
||||||
|
|
||||||
|
def append_with_tags(self, text, *tags):
|
||||||
|
buffer = self.conv_textview.tv.get_buffer()
|
||||||
|
iter = buffer.get_end_iter()
|
||||||
|
buffer.insert_with_tags_by_name(iter, text, *tags)
|
||||||
|
|
||||||
|
def echo(self, text, tag="command_ok"):
|
||||||
"""
|
"""
|
||||||
Print given text to the user.
|
Print given text to the user, as a regular command output.
|
||||||
"""
|
"""
|
||||||
self.print_conversation(str(text), kind)
|
self.shift_line()
|
||||||
|
self.append_with_tags(text, tag)
|
||||||
|
|
||||||
|
def echo_error(self, text):
|
||||||
|
"""
|
||||||
|
Print given text to the user, as an error command output.
|
||||||
|
"""
|
||||||
|
self.echo(text, "command_error")
|
||||||
|
|
||||||
def send(self, text):
|
def send(self, text):
|
||||||
"""
|
"""
|
||||||
|
@ -128,3 +183,10 @@ class CommandTools:
|
||||||
Get the current connection object.
|
Get the current connection object.
|
||||||
"""
|
"""
|
||||||
return gajim.connections[self.account]
|
return gajim.connections[self.account]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_jid(self):
|
||||||
|
"""
|
||||||
|
Get a full JID of the contact.
|
||||||
|
"""
|
||||||
|
return self.contact.get_full_jid()
|
|
@ -30,7 +30,8 @@ from ..errors import CommandError
|
||||||
from ..framework import CommandContainer, command, doc
|
from ..framework import CommandContainer, command, doc
|
||||||
from ..mapping import generate_usage
|
from ..mapping import generate_usage
|
||||||
|
|
||||||
from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands
|
from hosts import *
|
||||||
|
import execute
|
||||||
|
|
||||||
# This holds constants fron the logger, which we'll be using in some of our
|
# This holds constants fron the logger, which we'll be using in some of our
|
||||||
# commands.
|
# commands.
|
||||||
|
@ -42,7 +43,8 @@ class StandardCommonCommands(CommandContainer):
|
||||||
to all - chat, private chat, group chat.
|
to all - chat, private chat, group chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (ChatCommands, PrivateChatCommands, GroupChatCommands)
|
AUTOMATIC = True
|
||||||
|
HOSTS = ChatCommands, PrivateChatCommands, GroupChatCommands
|
||||||
|
|
||||||
@command
|
@command
|
||||||
@doc(_("Clear the text window"))
|
@doc(_("Clear the text window"))
|
||||||
|
@ -56,7 +58,7 @@ class StandardCommonCommands(CommandContainer):
|
||||||
self.chat_buttons_set_visible(new_status)
|
self.chat_buttons_set_visible(new_status)
|
||||||
|
|
||||||
@command(overlap=True)
|
@command(overlap=True)
|
||||||
@doc(_("Show help on a given command or a list of available commands if -(-a)ll is given"))
|
@doc(_("Show help on a given command or a list of available commands if -a is given"))
|
||||||
def help(self, command=None, all=False):
|
def help(self, command=None, all=False):
|
||||||
if command:
|
if command:
|
||||||
command = self.get_command(command)
|
command = self.get_command(command)
|
||||||
|
@ -163,7 +165,8 @@ class StandardCommonChatCommands(CommandContainer):
|
||||||
to a chat and a private chat only.
|
to a chat and a private chat only.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (ChatCommands, PrivateChatCommands)
|
AUTOMATIC = True
|
||||||
|
HOSTS = ChatCommands, PrivateChatCommands
|
||||||
|
|
||||||
@command
|
@command
|
||||||
@doc(_("Toggle the GPG encryption"))
|
@doc(_("Toggle the GPG encryption"))
|
||||||
|
@ -178,41 +181,37 @@ class StandardCommonChatCommands(CommandContainer):
|
||||||
gajim.connections[self.account].sendPing(self.contact)
|
gajim.connections[self.account].sendPing(self.contact)
|
||||||
|
|
||||||
@command
|
@command
|
||||||
@doc(_("Send DTMF events through an open audio session"))
|
@doc(_("Send DTMF sequence through an open audio session"))
|
||||||
def dtmf(self, events):
|
def dtmf(self, sequence):
|
||||||
if not self.audio_sid:
|
if not self.audio_sid:
|
||||||
raise CommandError(_("There is no open audio session with this contact"))
|
raise CommandError(_("No open audio sessions with the contact"))
|
||||||
# Valid values for DTMF tones are *, # or a number.
|
for tone in sequence:
|
||||||
events = [e for e in events if e in ('*', '#') or e.isdigit()]
|
if not (tone in ("*", "#") or tone.isdigit()):
|
||||||
if events:
|
raise CommandError(_("%s is not a valid tone") % tone)
|
||||||
session = gajim.connections[self.account].get_jingle_session(
|
gjs = self.connection.get_jingle_session
|
||||||
self.contact.get_full_jid(), self.audio_sid)
|
session = gjs(self.full_jid, self.audio_sid)
|
||||||
content = session.get_content('audio')
|
content = session.get_content("audio")
|
||||||
content.batch_dtmf(events)
|
content.batch_dtmf(sequence)
|
||||||
else:
|
|
||||||
raise CommandError(_("No valid DTMF event specified"))
|
|
||||||
|
|
||||||
@command
|
@command
|
||||||
@doc(_("Toggle audio session"))
|
@doc(_("Toggle audio session"))
|
||||||
def audio(self):
|
def audio(self):
|
||||||
if not self.audio_available:
|
if not self.audio_available:
|
||||||
raise CommandError(_("Audio sessions are not available"))
|
raise CommandError(_("Audio sessions are not available"))
|
||||||
else:
|
# An audio session is toggled by inverting the state of the
|
||||||
# A state of an audio session is toggled by inverting a state of the
|
# appropriate button.
|
||||||
# appropriate button.
|
state = self._audio_button.get_active()
|
||||||
state = self._audio_button.get_active()
|
self._audio_button.set_active(not state)
|
||||||
self._audio_button.set_active(not state)
|
|
||||||
|
|
||||||
@command
|
@command
|
||||||
@doc(_("Toggle video session"))
|
@doc(_("Toggle video session"))
|
||||||
def video(self):
|
def video(self):
|
||||||
if not self.video_available:
|
if not self.video_available:
|
||||||
raise CommandError(_("Video sessions are not available"))
|
raise CommandError(_("Video sessions are not available"))
|
||||||
else:
|
# A video session is toggled by inverting the state of the
|
||||||
# A state of a video session is toggled by inverting a state of the
|
# appropriate button.
|
||||||
# appropriate button.
|
state = self._video_button.get_active()
|
||||||
state = self._video_button.get_active()
|
self._video_button.set_active(not state)
|
||||||
self._video_button.set_active(not state)
|
|
||||||
|
|
||||||
class StandardChatCommands(CommandContainer):
|
class StandardChatCommands(CommandContainer):
|
||||||
"""
|
"""
|
||||||
|
@ -220,7 +219,8 @@ class StandardChatCommands(CommandContainer):
|
||||||
to a chat.
|
to a chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (ChatCommands,)
|
AUTOMATIC = True
|
||||||
|
HOSTS = ChatCommands,
|
||||||
|
|
||||||
class StandardPrivateChatCommands(CommandContainer):
|
class StandardPrivateChatCommands(CommandContainer):
|
||||||
"""
|
"""
|
||||||
|
@ -228,7 +228,8 @@ class StandardPrivateChatCommands(CommandContainer):
|
||||||
to a private chat.
|
to a private chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (PrivateChatCommands,)
|
AUTOMATIC = True
|
||||||
|
HOSTS = PrivateChatCommands,
|
||||||
|
|
||||||
class StandardGroupChatCommands(CommandContainer):
|
class StandardGroupChatCommands(CommandContainer):
|
||||||
"""
|
"""
|
||||||
|
@ -236,7 +237,8 @@ class StandardGroupChatCommands(CommandContainer):
|
||||||
to a group chat.
|
to a group chat.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
HOSTS = (GroupChatCommands,)
|
AUTOMATIC = True
|
||||||
|
HOSTS = GroupChatCommands,
|
||||||
|
|
||||||
@command(raw=True)
|
@command(raw=True)
|
||||||
@doc(_("Change your nickname in a group chat"))
|
@doc(_("Change your nickname in a group chat"))
|
||||||
|
@ -324,23 +326,24 @@ class StandardGroupChatCommands(CommandContainer):
|
||||||
@command
|
@command
|
||||||
@doc(_("Display names of all group chat occupants"))
|
@doc(_("Display names of all group chat occupants"))
|
||||||
def names(self, verbose=False):
|
def names(self, verbose=False):
|
||||||
get_contact = lambda nick: gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
|
ggc = gajim.contacts.get_gc_contact
|
||||||
nicks = gajim.contacts.get_nick_list(self.account, self.room_jid)
|
gnl = gajim.contacts.get_nick_list
|
||||||
|
|
||||||
# First we do alpha-numeric sort and then role-based one.
|
get_contact = lambda nick: ggc(self.account, self.room_jid, nick)
|
||||||
nicks.sort()
|
get_role = lambda nick: get_contact(nick).role
|
||||||
nicks.sort(key=lambda nick: get_contact(nick).role)
|
nicks = gnl(self.account, self.room_jid)
|
||||||
|
|
||||||
if verbose:
|
nicks = sorted(nicks)
|
||||||
for nick in nicks:
|
nicks = sorted(nicks, key=get_role)
|
||||||
contact = get_contact(nick)
|
|
||||||
|
|
||||||
role = helpers.get_uf_role(contact.role)
|
if not verbose:
|
||||||
affiliation = helpers.get_uf_affiliation(contact.affiliation)
|
return ", ".join(nicks)
|
||||||
|
|
||||||
self.echo("%s - %s - %s" % (nick, role, affiliation))
|
for nick in nicks:
|
||||||
else:
|
contact = get_contact(nick)
|
||||||
return ', '.join(nicks)
|
role = helpers.get_uf_role(contact.role)
|
||||||
|
affiliation = helpers.get_uf_affiliation(contact.affiliation)
|
||||||
|
self.echo("%s - %s - %s" % (nick, role, affiliation))
|
||||||
|
|
||||||
@command('ignore', raw=True)
|
@command('ignore', raw=True)
|
||||||
@doc(_("Forbid an occupant to send you public or private messages"))
|
@doc(_("Forbid an occupant to send you public or private messages"))
|
||||||
|
@ -350,4 +353,4 @@ class StandardGroupChatCommands(CommandContainer):
|
||||||
@command('unignore', raw=True)
|
@command('unignore', raw=True)
|
||||||
@doc(_("Allow an occupant to send you public or private messages"))
|
@doc(_("Allow an occupant to send you public or private messages"))
|
||||||
def unblock(self, who):
|
def unblock(self, who):
|
||||||
self.on_unblock(None, who)
|
self.on_unblock(None, who)
|
|
@ -205,7 +205,7 @@ def adapt_arguments(command, arguments, args, opts):
|
||||||
# The second stage of transforming options to an associatable state.
|
# The second stage of transforming options to an associatable state.
|
||||||
# Expanding short, one-letter options to a verbose ones, if
|
# Expanding short, one-letter options to a verbose ones, if
|
||||||
# corresponding optin has been given.
|
# corresponding optin has been given.
|
||||||
if command.expand_short:
|
if command.expand:
|
||||||
expanded = []
|
expanded = []
|
||||||
for spec_key, spec_value in norm_kwargs.iteritems():
|
for spec_key, spec_value in norm_kwargs.iteritems():
|
||||||
letter = spec_key[0] if len(spec_key) > 1 else None
|
letter = spec_key[0] if len(spec_key) > 1 else None
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
# Copyright (c) 2010, Alexander Cherniuk (ts33kr@gmail.com)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
from types import *
|
||||||
|
from glib import GError
|
||||||
|
|
||||||
|
def remove(sequence, target):
|
||||||
|
if isinstance(sequence, ListType):
|
||||||
|
if target in sequence:
|
||||||
|
sequence.remove(target)
|
||||||
|
elif isinstance(sequence, DictType):
|
||||||
|
if target in sequence:
|
||||||
|
del sequence[target]
|
||||||
|
|
||||||
|
def gconf(path):
|
||||||
|
try:
|
||||||
|
from gconf import client_get_default
|
||||||
|
client = client_get_default()
|
||||||
|
return client.get_string(path)
|
||||||
|
except ImportError, GError:
|
||||||
|
pass
|
|
@ -271,6 +271,8 @@ def check_and_possibly_create_paths():
|
||||||
XTLS_CERTS = configpaths.gajimpaths['MY_PEER_CERTS']
|
XTLS_CERTS = configpaths.gajimpaths['MY_PEER_CERTS']
|
||||||
LOCAL_XTLS_CERTS = configpaths.gajimpaths['MY_CERT']
|
LOCAL_XTLS_CERTS = configpaths.gajimpaths['MY_CERT']
|
||||||
|
|
||||||
|
PLUGINS_CONFIG_PATH = gajim.PLUGINS_CONFIG_DIR
|
||||||
|
|
||||||
if not os.path.exists(MY_DATA):
|
if not os.path.exists(MY_DATA):
|
||||||
create_path(MY_DATA)
|
create_path(MY_DATA)
|
||||||
elif os.path.isfile(MY_DATA):
|
elif os.path.isfile(MY_DATA):
|
||||||
|
@ -347,6 +349,18 @@ def check_and_possibly_create_paths():
|
||||||
jingle_xtls.make_certs(cert_name, 'gajim')
|
jingle_xtls.make_certs(cert_name, 'gajim')
|
||||||
|
|
||||||
|
|
||||||
|
if not os.path.exists(PLUGINS_CONFIG_PATH):
|
||||||
|
create_path(PLUGINS_CONFIG_PATH)
|
||||||
|
elif os.path.isfile(PLUGINS_CONFIG_PATH):
|
||||||
|
print _('%s is a file but it should be a directory') % PLUGINS_CONFIG_PATH
|
||||||
|
print _('Gajim will now exit')
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
def create_path(directory):
|
def create_path(directory):
|
||||||
|
head, tail = os.path.split(directory)
|
||||||
|
if not os.path.exists(head):
|
||||||
|
create_path(head)
|
||||||
|
if os.path.exists(directory):
|
||||||
|
return
|
||||||
print _('creating %s directory') % directory
|
print _('creating %s directory') % directory
|
||||||
os.mkdir(directory, 0700)
|
os.mkdir(directory, 0700)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue