Index: src/orca/settings.py
===================================================================
--- src/orca/settings.py	(revision 3532)
+++ src/orca/settings.py	(working copy)
@@ -155,7 +155,9 @@
     "enabledBrailledTextAttributes",
     "textAttributesBrailleIndicator",
     "enableProgressBarUpdates",
-    "progressBarUpdateInterval"
+    "progressBarUpdateInterval",
+    "enableContractedBraille",
+    "brailleContractionTable"
 ]
 
 # The name of the module that hold the user interface for the main window
@@ -905,3 +907,11 @@
 # changes.  
 #
 inferLiveRegions = True
+
+# Contracted braille support.
+# 
+enableContractedBraille = False
+
+# Contracted braille table.
+# 
+brailleContractionTable = ''
Index: src/orca/orca-setup.glade
===================================================================
--- src/orca/orca-setup.glade	(revision 3532)
+++ src/orca/orca-setup.glade	(working copy)
@@ -1252,8 +1252,8 @@
 				  <property name="wrap">False</property>
 				  <property name="adjustment">10 1 9999 1 10 10</property>
 				  <accessibility>
+				    <atkrelation target="speakProgressBarUnitsLabel" type="labelled-by"/>
 				    <atkrelation target="speakProgressBarLabel" type="labelled-by"/>
-				    <atkrelation target="speakProgressBarUnitsLabel" type="labelled-by"/>
 				  </accessibility>
 				  <signal name="value_changed" handler="speakProgressBarValueChanged" last_modification_time="Thu, 14 Jun 2007 15:09:00 GMT"/>
 				</widget>
@@ -1525,6 +1525,7 @@
 
 		  <child>
 		    <widget class="GtkFrame" id="contractedBrailleFrame">
+		      <property name="visible">True</property>
 		      <property name="label_xalign">0</property>
 		      <property name="label_yalign">0.5</property>
 		      <property name="shadow_type">GTK_SHADOW_NONE</property>
@@ -1549,7 +1550,7 @@
 			      <property name="spacing">0</property>
 
 			      <child>
-				<widget class="GtkCheckButton" id="checkbutton1">
+				<widget class="GtkCheckButton" id="contractedBrailleCheckbutton">
 				  <property name="visible">True</property>
 				  <property name="can_focus">True</property>
 				  <property name="label" translatable="yes">_Enable Contracted Braille</property>
@@ -1612,6 +1613,7 @@
 				      <accessibility>
 					<atkrelation target="contractionTableLabel" type="labelled-by"/>
 				      </accessibility>
+				      <signal name="changed" handler="contractionTableComboChanged" last_modification_time="Fri, 18 Jan 2008 00:39:59 GMT"/>
 				    </widget>
 				    <packing>
 				      <property name="padding">0</property>
@@ -3504,8 +3506,8 @@
 							  <property name="wrap">False</property>
 							  <property name="adjustment">1 24 256 1 10 10</property>
 							  <accessibility>
+							    <atkrelation target="magCursorSizeLabel" type="labelled-by"/>
 							    <atkrelation target="magCursorSizeUnitsLabel" type="labelled-by"/>
-							    <atkrelation target="magCursorSizeLabel" type="labelled-by"/>
 							  </accessibility>
 							  <signal name="value_changed" handler="magCursorSizeValueChanged" last_modification_time="Wed, 03 May 2006 15:31:48 GMT"/>
 							</widget>
@@ -3857,8 +3859,8 @@
 							  <property name="wrap">False</property>
 							  <property name="adjustment">1 1 256 1 10 10</property>
 							  <accessibility>
+							    <atkrelation target="magCrossHairSizeLabel" type="labelled-by"/>
 							    <atkrelation target="magCrossHairSizeUnitsLabel" type="labelled-by"/>
-							    <atkrelation target="magCrossHairSizeLabel" type="labelled-by"/>
 							  </accessibility>
 							  <signal name="value_changed" handler="magCrossHairSizeValueChanged" last_modification_time="Wed, 03 May 2006 15:39:23 GMT"/>
 							</widget>
@@ -4295,8 +4297,8 @@
 						  <property name="wrap">False</property>
 						  <property name="adjustment">0 0 100 1 10 10</property>
 						  <accessibility>
+						    <atkrelation target="magEdgeMarginUnitsLabel" type="labelled-by"/>
 						    <atkrelation target="magEdgeMarginLabel" type="labelled-by"/>
-						    <atkrelation target="magEdgeMarginUnitsLabel" type="labelled-by"/>
 						  </accessibility>
 						  <signal name="value_changed" handler="magEdgeMarginValueChanged" last_modification_time="Thu, 06 Dec 2007 22:57:50 GMT"/>
 						</widget>
Index: src/orca/orca_prefs.py
===================================================================
--- src/orca/orca_prefs.py	(revision 3532)
+++ src/orca/orca_prefs.py	(working copy)
@@ -687,6 +687,8 @@
             elif key == "textAttributesBrailleIndicator":
                 value = self._getTextAttributesBrailleIndicatorString( \
                                                               prefsDict[key])
+            elif key == "brailleContractionTable":
+                value = "'%s'" % prefsDict[key]
             else:
                 value = prefsDict[key]
 
Index: src/orca/braille.py
===================================================================
--- src/orca/braille.py	(revision 3532)
+++ src/orca/braille.py	(working copy)
@@ -38,6 +38,14 @@
 
 import pyatspi
 
+try:
+    import louis
+except ImportError:
+    louis = None
+    _defaultContractionTable = None
+else:
+    _defaultContractionTable = louis.getDefaultTable()
+
 # We'll use the official BrlAPI pythons (as of BrlTTY 3.8) if they
 # are available.  Otherwise, we'll fall back to our own bindings.
 #
@@ -276,13 +284,25 @@
         if not string:
             string = ""
 
+        # If louis is None, then we don't go into contracted mode.
+        self.contracted = settings.enableContractedBraille and \
+                          louis is not None
+        
         string = string.decode("UTF-8")
-        if string[-1:] == "\n":
-            string = string[:-1]
-        self.string = string.encode("UTF-8")
+        string.strip('\n')
+        self.rawLine = string.encode("UTF-8")
 
-        self.cursorOffset = cursorOffset
+        if self.contracted:
+            global _defaultContractionTable
+            self.contractionTable = settings.brailleContractionTable or \
+                                    _defaultContractionTable
 
+            self.string, self.inPos, self.outPos, self.cursorOffset = \
+                         self.contractLine(self.rawLine, cursorOffset)
+        else:
+            self.string = self.rawLine
+            self.cursorOffset = cursorOffset
+            
     def processRoutingKey(self, offset):
         """Processes a cursor routing key press on this Component.  The offset
         is 0-based, where 0 represents the leftmost character of string
@@ -299,7 +319,66 @@
         #
         mask = ['\x00'] * len(self.string)
         return "".join(mask)
+    
+    def contractLine(self, line, cursorOffset=0, expandOnCursor=False):
+        """Contract the given line. Returns the contracted line, and the
+        cursor position in the contracted line.
 
+        Arguments:
+        - line: Line to contract.
+        - cursorOffset: Offset of cursor,defaults to 0.
+        - expandOnCursor: Expand word under cursor, False by default.
+        """
+
+        try:
+            cursorOnSpace = line[cursorOffset] == ' '
+        except IndexError:
+            cursorOnSpace = False
+            
+        if not expandOnCursor or cursorOnSpace:
+            contracted, inPos, outPos, cursorPos = \
+                             louis.translate([self.contractionTable],
+                                             line.decode(),
+                                             cursorPos=cursorOffset)
+        else:
+            contracted, inPos, outPos, cursorPos = \
+                             louis.translate([self.contractionTable],
+                                             line.decode(),
+                                             cursorPos=cursorOffset,
+                                             mode=louis.MODE.compbrlAtCursor)
+
+        return contracted, inPos, outPos, cursorPos
+    
+    def displayToBufferOffset(self, display_offset):
+        try:
+            offset = self.inPos[display_offset]
+        except IndexError:
+            # Off the chart, we just place the cursor at the end of the line.
+            offset = len(self.rawLine)
+        except AttributeError:
+            # Not in contracted mode.
+            offset = display_offset
+
+        return offset
+
+    def setContractedBraille(self, contracted):
+        if self.contracted == contracted:
+            return
+        self.contracted = contracted
+        if contracted:
+            global _defaultContractionTable
+            self.contractionTable = settings.brailleContractionTable or \
+                                    _defaultContractionTable
+
+            self.string, self.inPos, self.outPos, self.cursorOffset = \
+                         self.contractLine(self.rawLine, self.cursorOffset)
+        else:
+            self.string = self.rawLine
+            try:
+                self.cursorOffset = self.inPos[self.cursorOffset]
+            except IndexError:
+                self.cursorOffset = len(self.string)
+
 class Component(Region):
     """A subclass of Region backed by an accessible.  This Region will react
     to any cursor routing key events and perform the default action on the
@@ -381,15 +460,18 @@
         self._maxCaretOffset = self.lineOffset + len(string.decode("UTF-8"))
 
         self.eol = eol
-        string = string + self.eol
+        self.label = label+ ' ' if label else ''
+        print self.label
 
-        self.label = label
-        if self.label:
-            string = self.label + " " + string
-            cursorOffset += len(self.label.decode("UTF-8")) + 1
+        string = self.label + string
 
+        cursorOffset += len(self.label)
+        
         Region.__init__(self, string, cursorOffset)
 
+        if not self.contracted:
+            self.string += self.eol
+
     def repositionCursor(self):
         """Attempts to reposition the cursor in response to a new
         caret position.  If it is possible (i.e., the caret is on
@@ -400,16 +482,21 @@
         [string, caretOffset, lineOffset] = \
                  orca_state.activeScript.getTextLineAtCaret(self.accessible)
         cursorOffset = min(caretOffset - lineOffset, len(string))
-        if self.label:
-            cursorOffset += len(self.label.decode("UTF-8")) + 1
-
+        
         if lineOffset != self.lineOffset:
             return False
-        else:
-            self.caretOffset = caretOffset
-            self.lineOffset = lineOffset
-            self.cursorOffset = cursorOffset
 
+        self.caretOffset = caretOffset
+        self.lineOffset = lineOffset
+
+        cursorOffset += len(self.label)
+
+        if self.contracted:
+            self.string, self.inPos, self.outPos, cursorOffset = \
+                       self.contractLine(self.rawLine, cursorOffset, True)
+
+        self.cursorOffset = cursorOffset
+
         return True
 
     def processRoutingKey(self, offset):
@@ -417,11 +504,11 @@
         is 0-based, where 0 represents the leftmost character of text
         associated with this region.  Note that the zeroeth character may have
         been scrolled off the display."""
+        
+        offset = self.displayToBufferOffset(offset)
 
-        if self.label:
-            offset = offset - len(self.label.decode("UTF-8")) - 1
-            if offset < 0:
-                return
+        if offset < 0:
+            return
 
         newCaretOffset = min(self.lineOffset + offset, self._maxCaretOffset)
         self.accessible.queryText().setCaretOffset(newCaretOffset)
@@ -517,17 +604,48 @@
 
         mask = "".join(attrMask)
 
+        if self.contracted:
+            contractedMask = [0]*len(self.rawLine)
+            outPos = self.outPos[len(self.label):]
+            if self.label:
+                # Transform the offsets.
+                outPos = \
+                       [offset - len(self.label) - 1 for offset in outPos]
+            for i, m in enumerate(mask):
+                try:
+                    contractedMask[outPos[i]] |= ord(m)
+                except IndexError:
+                    continue
+            mask = ''.join(map(chr, contractedMask))
+
         # Add empty mask characters for the EOL character as well as for
         # any label that might be present.
         #
         for i in range (0, len(self.eol)):
             mask += '\x00'
+
         if self.label:
             for i in range (0, len(self.label) + 1):
                 mask = '\x00' + mask
 
         return mask
 
+    def contractLine(self, line, cursorOffset=0, expandOnCursor=True):
+        contracted, inPos, outPos, cursorPos = Region.contractLine(
+            self, line, cursorOffset, expandOnCursor)
+        
+        return contracted + self.eol, inPos, outPos, cursorPos
+
+    def displayToBufferOffset(self, display_offset):
+        offset = Region.displayToBufferOffset(self, display_offset)
+        offset -= len(self.label)
+        return offset
+
+    def setContractedBraille(self, contracted):
+        Region.setContractedBraille(self, contracted)
+        if not contracted:
+            self.string += self.eol
+
 class ReviewComponent(Component):
     """A subclass of Component that is to be used for flat review mode."""
 
@@ -573,6 +691,7 @@
         associated with this region.  Note that the zeroeth character may have
         been scrolled off the display."""
 
+        offset = self.displayToBufferOffset(offset)
         newCaretOffset = self.lineOffset + offset
         self.accessible.queryText().setCaretOffset(newCaretOffset)
 
@@ -657,6 +776,10 @@
         if region:
             region.processRoutingKey(regionOffset)
 
+    def setContractedBraille(self, contracted):
+        for region in self.regions:
+            region.setContractedBraille(contracted)
+
 def getRegionAtCell(cell):
     """Given a 1-based cell offset, return the braille region
     associated with that cell in the form of [region, offsetinregion]
@@ -1052,6 +1175,12 @@
             _lines[lineNum].processRoutingKey(cursor)
             consumed = True
 
+    if command in (0x2141, 65): # Toggle six dot braille
+        settings.enableContractedBraille = not settings.enableContractedBraille
+        for line in _lines:
+            line.setContractedBraille(settings.enableContractedBraille)
+        refresh()
+
     if settings.timeoutCallback and (settings.timeoutTime > 0):
         signal.alarm(0)
 
@@ -1067,7 +1196,7 @@
         lower = key & 0xFFFFFFFF
         #keyType = lower >> 29
         keyCode = lower & 0x1FFFFFFF
-
+        
         # [[TODO: WDW - HACK If we have a cursor routing key, map
         # it back to the code we used to get with earlier versions
         # of BrlAPI (i.e., bit 0x100 was the indicator of a cursor
@@ -1103,9 +1232,11 @@
         #
         for key in keys:
             keySet.append(brlapi.KEY_TYPE_CMD | key)
-
+            
         brlAPI.acceptKeys(brlapi.rangeType_command, keySet)
 
+        brlAPI.acceptKeys(brlapi.rangeType_key, [65])
+
         debug.println(debug.LEVEL_FINEST, "Using BrlAPI v0.5.0+")
     except:
         debug.printException(debug.LEVEL_FINEST)
Index: src/orca/orca_gui_prefs.py
===================================================================
--- src/orca/orca_gui_prefs.py	(revision 3532)
+++ src/orca/orca_gui_prefs.py	(working copy)
@@ -49,6 +49,11 @@
 import speech
 import speechserver
 
+try:
+    import louis
+except ImportError:
+    louis = None
+
 from orca_i18n import _  # for gettext support
 
 (HANDLER, DESCRIP, MOD_MASK1, MOD_USED1, KEY1, OLDTEXT1, TEXT1, \
@@ -947,7 +952,13 @@
     def contractedBrailleToggled(self, checkbox):
         hbox = self.widgets.get_widget('contractionTablesHBox')
         hbox.set_sensitive(checkbox.get_active())
+        self.prefsDict["enableContractedBraille"] = checkbox.get_active()
 
+    def contractionTableComboChanged(self, combobox):
+        model = combobox.get_model()
+        iter = combobox.get_active_iter()
+        self.prefsDict["brailleContractionTable"] = model[iter][1]
+        
     def textAttributeSpokenToggled(self, cell, path, model):
         """The user has toggled the state of one of the text attribute
         checkboxes to be spoken. Update our model to reflect this, then
@@ -1431,6 +1442,36 @@
         state = prefs["brailleRolenameStyle"] == \
                             settings.BRAILLE_ROLENAME_STYLE_SHORT
         self.get_widget("abbrevRolenames").set_active(state)
+        if louis is None:
+            self.get_widget( \
+                "contractedBrailleCheckbutton").set_sensitive(False)
+        else:
+            self.get_widget("contractedBrailleCheckbutton").set_active( \
+                prefs["enableContractedBraille"])
+            # Set up contraction table combo box and set it to the
+            # currently used one.
+            # 
+            tablesCombo = self.get_widget("contractionTableCombo")
+            tableDict = louis.listTables()
+            selectedTableIter = None
+            selectedTable = prefs["brailleContractionTable"] or \
+                             louis.getDefaultTable()
+            if tableDict:
+                tablesModel = gtk.ListStore(str, str)
+                for name, fname in tableDict.items():
+                    it = tablesModel.append([name, fname])
+                    if os.path.join(louis.TABLES_DIR, fname) == selectedTable:
+                        selectedTable = it
+                cell = gtk.CellRendererText()
+                tablesCombo.pack_start(cell, True)
+                tablesCombo.add_attribute(cell, 'text', 0)
+                tablesCombo.set_model(tablesModel)
+                if selectedTable:
+                    tablesCombo.set_active_iter(selectedTable)
+                else:
+                    tablesCombo.set_active(0)
+            else:
+                tablesCombo.set_sensitive(False)
         if prefs["brailleVerbosityLevel"] == settings.VERBOSITY_LEVEL_BRIEF:
             self.get_widget("brailleBriefButton").set_active(True)
         else:
