[orca] Work on bgo#615485 - Orca should support the Instantbird chat client
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Work on bgo#615485 - Orca should support the Instantbird chat client
- Date: Mon, 12 Apr 2010 03:24:24 +0000 (UTC)
commit f61442d94a3c2516cd6e3830bf03177c8dee7b8e
Author: Joanmarie Diggs <Joanmarie Diggs gmail com>
Date: Sun Apr 11 23:09:54 2010 -0400
Work on bgo#615485 - Orca should support the Instantbird chat client
This is just a start. Still need to look at:
1. Better presentation of tree items in buddy list.
2. Get typing status working.
3. Get room-specific chat histories working (seems to work ok when
there's a single history rather than one per room)
Plus testing and user feedback, of course. Note that this assumes
you are using Instantbird nightly dev/beta (0.2).
configure.in | 1 +
src/orca/chat.py | 21 +++-
src/orca/scripts/apps/Instantbird/Makefile.am | 9 ++
src/orca/scripts/apps/Instantbird/__init__.py | 20 +++
src/orca/scripts/apps/Instantbird/chat.py | 169 +++++++++++++++++++++++++
src/orca/scripts/apps/Instantbird/script.py | 122 ++++++++++++++++++
src/orca/scripts/apps/Makefile.am | 1 +
7 files changed, 340 insertions(+), 3 deletions(-)
---
diff --git a/configure.in b/configure.in
index f775675..862000f 100644
--- a/configure.in
+++ b/configure.in
@@ -79,6 +79,7 @@ src/orca/scripts/apps/soffice/Makefile
src/orca/scripts/apps/empathy/Makefile
src/orca/scripts/apps/evolution/Makefile
src/orca/scripts/apps/gcalctool/Makefile
+src/orca/scripts/apps/Instantbird/Makefile
src/orca/scripts/apps/packagemanager/Makefile
src/orca/scripts/apps/pidgin/Makefile
src/orca/scripts/apps/planner/Makefile
diff --git a/src/orca/chat.py b/src/orca/chat.py
index abef254..464e0d5 100644
--- a/src/orca/chat.py
+++ b/src/orca/chat.py
@@ -662,6 +662,19 @@ class Chat:
speech.speak(text)
braille.displayMessage(text)
+ def getMessageFromEvent(self, event):
+ """Get the actual displayed message. This will almost always be the
+ unaltered any_data from an event of type object:text-changed:insert.
+
+ Arguments:
+ - event: the Event from which to take the text.
+
+ Returns the string which should be presented as the newly-inserted
+ text. (Things like chatroom name prefacing get handled elsewhere.)
+ """
+
+ return event.any_data
+
def presentInsertedText(self, event):
"""Gives the Chat class an opportunity to present the text from the
text inserted Event.
@@ -711,8 +724,9 @@ class Chat:
else:
conversation = self.getConversation(event.source)
name = conversation.name
- message = event.any_data.strip("\n")
- self.addMessageToHistory(message, conversation)
+ message = self.getMessageFromEvent(event).strip("\n")
+ if message:
+ self.addMessageToHistory(message, conversation)
# The user may or may not want us to present this message. Also,
# don't speak the name if it's the focused chat.
@@ -720,7 +734,8 @@ class Chat:
focused = self.isFocusedChat(event.source)
if focused:
name = ""
- self.utterMessage(name, event.any_data, focused)
+ if message:
+ self.utterMessage(name, message, focused)
return True
elif self.isAutoCompletedTextEvent(event):
diff --git a/src/orca/scripts/apps/Instantbird/Makefile.am b/src/orca/scripts/apps/Instantbird/Makefile.am
new file mode 100644
index 0000000..bdbeb1b
--- /dev/null
+++ b/src/orca/scripts/apps/Instantbird/Makefile.am
@@ -0,0 +1,9 @@
+orca_pathdir=$(pyexecdir)
+
+orca_python_PYTHON = \
+ __init__.py \
+ chat.py \
+ script.py
+
+orca_pythondir=$(pyexecdir)/orca/scripts/apps/Instantbird
+
diff --git a/src/orca/scripts/apps/Instantbird/__init__.py b/src/orca/scripts/apps/Instantbird/__init__.py
new file mode 100644
index 0000000..c81df83
--- /dev/null
+++ b/src/orca/scripts/apps/Instantbird/__init__.py
@@ -0,0 +1,20 @@
+# Orca
+#
+# Copyright 2010 Joanmarie Diggs
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA 02110-1301 USA.
+
+from script import Script
diff --git a/src/orca/scripts/apps/Instantbird/chat.py b/src/orca/scripts/apps/Instantbird/chat.py
new file mode 100644
index 0000000..7bd09b5
--- /dev/null
+++ b/src/orca/scripts/apps/Instantbird/chat.py
@@ -0,0 +1,169 @@
+# Orca
+#
+# Copyright 2010 Joanmarie Diggs.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA 02110-1301 USA.
+
+"""Custom chat module for Instantbird."""
+
+__id__ = "$Id$"
+__version__ = "$Revision$"
+__date__ = "$Date$"
+__copyright__ = "Copyright (c) 2010 Joanmarie Diggs."
+__license__ = "LGPL"
+
+import pyatspi
+
+import orca.chat as chat
+
+########################################################################
+# #
+# The Instantbird chat class. #
+# #
+########################################################################
+
+class Chat(chat.Chat):
+
+ def __init__(self, script, buddyListAncestries):
+ # IMs get inserted as embedded object characters in these roles.
+ #
+ self._messageParentRoles = [pyatspi.ROLE_DOCUMENT_FRAME,
+ pyatspi.ROLE_SECTION]
+
+ chat.Chat.__init__(self, script, buddyListAncestries)
+
+ ########################################################################
+ # #
+ # InputEvent handlers and supporting utilities #
+ # #
+ ########################################################################
+
+ def getMessageFromEvent(self, event):
+ """Get the actual displayed message. This will almost always be the
+ unaltered any_data from an event of type object:text-changed:insert.
+
+ Arguments:
+ - event: the Event from which to take the text.
+
+ Returns the string which should be presented as the newly-inserted
+ text. (Things like chatroom name prefacing get handled elsewhere.)
+ """
+
+ string = ""
+
+ # IMs are written in areas that look like bubbles. When a new bubble
+ # is inserted, we see an embedded object character inserted into the
+ # document frame. The first paragraph is the bubble title; the
+ # rest (usually just one) are the message itself.
+ #
+ if event.source.getRole() == pyatspi.ROLE_DOCUMENT_FRAME:
+ bubble = event.source[event.detail1]
+ paragraphs = self._script.findByRole(bubble, pyatspi.ROLE_PARAGRAPH)
+ for paragraph in paragraphs:
+ try:
+ msg = paragraph.queryText().getText(0, -1)
+ except:
+ pass
+ else:
+ string = self._script.appendString(string, msg)
+
+ return string
+
+ # If we instead have a section, we are writing another message into
+ # the existing bubble. In this case, we get three separate items
+ # inserted: a separator, a paragraph with the desired text, and an
+ # empty section.
+ #
+ if event.source.getRole() == pyatspi.ROLE_SECTION:
+ obj = event.source[event.detail1]
+ if obj and obj.getRole() == pyatspi.ROLE_PARAGRAPH:
+ try:
+ text = obj.queryText()
+ except:
+ pass
+ else:
+ string = text.getText(0, -1)
+
+ return string
+
+ ########################################################################
+ # #
+ # Convenience methods for identifying, locating different accessibles #
+ # #
+ ########################################################################
+
+ def isChatRoomMsg(self, obj):
+ """Returns True if the given accessible is the text object for
+ associated with a chat room conversation.
+
+ Arguments:
+ - obj: the accessible object to examine.
+ """
+
+ # We might need to refine this later. For now, just get things
+ # working.
+ #
+ if obj and obj.getRole() in self._messageParentRoles:
+ return True
+
+ return False
+
+ def getChatRoomName(self, obj):
+ """Attempts to find the name of the current chat room.
+
+ Arguments:
+ - obj: The accessible of interest
+
+ Returns a string containing what we think is the chat room name.
+ """
+
+ ancestor = self._script.getAncestor(obj,
+ [pyatspi.ROLE_SCROLL_PANE,
+ pyatspi.ROLE_FRAME],
+ [pyatspi.ROLE_APPLICATION])
+
+ if ancestor and ancestor.getRole() == pyatspi.ROLE_SCROLL_PANE:
+ # The scroll pane has a proper labelled by relationship set.
+ #
+ return self._script.getDisplayedLabel(ancestor)
+
+ try:
+ text = self._script.getDisplayedText(ancestor)
+ if text.lower().strip() != self._script.name.lower().strip():
+ return text
+ except:
+ return ""
+
+ def isFocusedChat(self, obj):
+ """Returns True if we plan to treat this chat as focused for
+ the purpose of deciding whether or not a message should be
+ presented to the user.
+
+ Arguments:
+ - obj: the accessible object to examine.
+ """
+
+ # Normally, we'd see if the top level window associated
+ # with this object had STATE_ACTIVE. That doesn't work
+ # here. So see if the script for the locusOfFocus is
+ # this script. If so, the only other possibility is that
+ # we're in the buddy list instead.
+ #
+ if obj and obj.getState().contains(pyatspi.STATE_SHOWING) \
+ and self._script.isInActiveApp(obj) and not self.isInBuddyList(obj):
+ return True
+
+ return False
diff --git a/src/orca/scripts/apps/Instantbird/script.py b/src/orca/scripts/apps/Instantbird/script.py
new file mode 100644
index 0000000..a20bc26
--- /dev/null
+++ b/src/orca/scripts/apps/Instantbird/script.py
@@ -0,0 +1,122 @@
+# Orca
+#
+# Copyright 2010 Joanmarie Diggs.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA 02110-1301 USA.
+
+"""Custom script for Instantbird."""
+
+__id__ = "$Id$"
+__version__ = "$Revision$"
+__date__ = "$Date$"
+__copyright__ = "Copyright (c) 2010 Joanmarie Diggs."
+__license__ = "LGPL"
+
+import pyatspi
+
+import orca.default as default
+
+from chat import Chat
+
+########################################################################
+# #
+# The Instantbird script class. #
+# #
+########################################################################
+
+class Script(default.Script):
+
+ def __init__(self, app):
+ """Creates a new script for the given application."""
+
+ # So we can take an educated guess at identifying the buddy list.
+ #
+ self._buddyListAncestries = [[pyatspi.ROLE_LIST,
+ pyatspi.ROLE_FRAME]]
+
+ # We want the functionality of the default script without the
+ # conflicting enhancements we'd pull in from the Gecko script.
+ # (Widgets may be a different story, but for now let's try
+ # subclassing the default script rather than the Gecko script.)
+ #
+ default.Script.__init__(self, app)
+
+ def getChat(self):
+ """Returns the 'chat' class for this script."""
+
+ return Chat(self, self._buddyListAncestries)
+
+ def setupInputEventHandlers(self):
+ """Defines InputEventHandler fields for this script that can be
+ called by the key and braille bindings. Here we need to add the
+ handlers for chat functionality.
+ """
+
+ default.Script.setupInputEventHandlers(self)
+ self.inputEventHandlers.update(self.chat.inputEventHandlers)
+
+ def getKeyBindings(self):
+ """Defines the key bindings for this script. Here we need to add
+ the keybindings associated with chat functionality.
+
+ Returns an instance of keybindings.KeyBindings.
+ """
+
+ keyBindings = default.Script.getKeyBindings(self)
+
+ bindings = self.chat.keyBindings
+ for keyBinding in bindings.keyBindings:
+ keyBindings.add(keyBinding)
+
+ return keyBindings
+
+ def getAppPreferencesGUI(self):
+ """Return a GtkVBox contain the application unique configuration
+ GUI items for the current application. The chat-related options
+ get created by the chat module.
+ """
+
+ return self.chat.getAppPreferencesGUI()
+
+ def setAppPreferences(self, prefs):
+ """Write out the application specific preferences lines and set the
+ new values. The chat-related options get written out by the chat
+ module.
+
+ Arguments:
+ - prefs: file handle for application preferences.
+ """
+
+ self.chat.setAppPreferences(prefs)
+
+ def onTextInserted(self, event):
+ """Called whenever text is added to an object."""
+
+ if self.chat.presentInsertedText(event):
+ return
+
+ default.Script.onTextInserted(self, event)
+
+ def onWindowActivated(self, event):
+ """Called whenever a toplevel window is activated."""
+
+ # Hack to "tickle" the accessible hierarchy. Otherwise, the
+ # events we need to present text added to the chatroom are
+ # missing.
+ #
+ allPageTabs = self.findByRole(event.source, pyatspi.ROLE_PAGE_TAB)
+
+ default.Script.onWindowActivated(self, event)
diff --git a/src/orca/scripts/apps/Makefile.am b/src/orca/scripts/apps/Makefile.am
index 917116b..44a5e87 100644
--- a/src/orca/scripts/apps/Makefile.am
+++ b/src/orca/scripts/apps/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS = \
gnome-window-properties \
Banshee \
empathy \
+ Instantbird \
yelp
orca_pathdir=$(pyexecdir)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]