foiegras r50 - in trunk: . data src/foiegras src/foiegras/windows



Author: denisw
Date: Fri Feb  1 16:38:06 2008
New Revision: 50
URL: http://svn.gnome.org/viewvc/foiegras?rev=50&view=rev

Log:
2008-02-01  Denis Washington  <denisw svn gnome org>

	* src/foiegras/docbuffer.py:
	Beginnings of a new text buffer which doesn't rely on inner text views,
	which are not very nice to edit. It currently supports only very few
	features (opening and saving is not yet implemented), but is already
	integrated into some controls. (Inline tags can already be applied;
	support for block tags is still very weak.)

    * src/foiegras/document.py:
    * src/foiegras/windows/main.py:
    Use the new buffer, plus some code cleanup.

    * data/toolbar.ui:
    Remove some block tags which cannot be applied to text (like <figure>).
    These should be accessible through something like an "Insert" menu and/or
    menu tool item.


Added:
   trunk/src/foiegras/docbuffer.py
Modified:
   trunk/ChangeLog
   trunk/data/toolbar.ui
   trunk/src/foiegras/document.py
   trunk/src/foiegras/windows/main.py

Modified: trunk/data/toolbar.ui
==============================================================================
--- trunk/data/toolbar.ui	(original)
+++ trunk/data/toolbar.ui	Fri Feb  1 16:38:06 2008
@@ -17,27 +17,23 @@
     <toolbar name="BlockToolbar">
         <toolitem name="Caption" action="CaptionAction" />
         <toolitem name="Citation" action="CitationAction" />
-        <toolitem name="MultimediaObject" action="MultimediaObjectAction" />
         <toolitem name="CodeSnippet" action="CodeSnippetAction" />
         <toolitem name="Paragraph" action="ParagraphAction" />
         <toolitem name="Screen" action="ScreenAction" />
         <toolitem name="EditorialComment" action="EditorialCommentAction" />
-        <toolitem name="Figure" action="FigureAction" />
         <toolitem name="List" action="ListAction" />
         <toolitem name="Note" action="NoteAction" />
         <toolitem name="Synopse" action="SynopseAction" />
-        <toolitem name="Table" action="TableAction" />
     </toolbar>
     <toolbar name="InlineToolbar">
         <toolitem name="ApplicationName" action="ApplicationNameAction" />
-        <toolitem name="CodeSnippet" action="CodeSnippetAction" />
         <toolitem name="Command" action="CommandAction" />
         <toolitem name="ComputerOutput" action="ComputerOutputAction" />
         <toolitem name="Date" action="DateAction" />
         <toolitem name="Emphasis" action="EmphasisAction" />
         <toolitem name="FileName" action="FileNameAction" />
         <toolitem name="GUILabel" action="GUILabelAction" />
-        <toolitem name="Hyperlink" action="HyperlinkAction" />
+        <toolitem name="InlineCode" action="InlineCodeAction" />
         <toolitem name="KeyStroke" action="KeyStrokeAction" />
         <toolitem name="MultimediaObject" action="MultimediaObjectAction" />
         <toolitem name="Quote" action="QuoteAction" />

Added: trunk/src/foiegras/docbuffer.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/docbuffer.py	Fri Feb  1 16:38:06 2008
@@ -0,0 +1,365 @@
+# Copyright (C) 2008 by Denis Washington <denisw svn gnome org>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import pango
+import gobject
+
+
+INLINE_TAGS = []
+BLOCK_TAGS = []
+ATTRIBUTES = []
+
+TAG_TABLE = gtk.TextTagTable()
+
+def setup_tags():
+
+    def block_tag(name):
+        BLOCK_TAGS.append(name)
+        return gtk.TextTag(name)
+
+    def inline_tag(name):
+        INLINE_TAGS.append(name)
+        return gtk.TextTag(name)
+
+
+    # <app>
+    tag = inline_tag("app")
+    TAG_TABLE.add(tag)
+
+    # <caption>
+    tag = block_tag("caption")
+    TAG_TABLE.add(tag)
+
+    # <cmd>
+    tag = inline_tag("cmd")
+    tag.set_property("family", "monospace")
+    TAG_TABLE.add(tag)
+
+    # <code>
+    tag = inline_tag("code")
+    tag.set_property("family", "monospace")
+    TAG_TABLE.add(tag)
+
+    # <code-inline>
+    tag = inline_tag("code-inline")
+    tag.set_property("family", "monospace")
+    TAG_TABLE.add(tag)
+
+    # <cite>
+    tag = block_tag("cite")
+    tag.set_property("style", pango.STYLE_ITALIC)
+    TAG_TABLE.add(tag)
+
+    # <date>
+    tag = inline_tag("date")
+    tag.set_property("style", pango.STYLE_ITALIC)
+    TAG_TABLE.add(tag)
+
+    # <em>
+    tag = inline_tag("em")
+    tag.set_property("style", pango.STYLE_ITALIC)
+    TAG_TABLE.add(tag)
+
+    # <figure>
+    tag = block_tag("figure")
+    TAG_TABLE.add(tag)
+
+    # <file>
+    tag = inline_tag("file")
+    tag.set_property("style", pango.STYLE_ITALIC)
+    TAG_TABLE.add(tag)
+
+    # <gui>
+    tag = inline_tag("gui")
+    tag.set_property("style", pango.STYLE_ITALIC)
+    TAG_TABLE.add(tag)
+
+    # <input>
+    tag = inline_tag("input")
+    tag.set_property("family", "monospace")
+    TAG_TABLE.add(tag)
+
+    # <key>
+    tag = inline_tag("key")
+    tag.set_property("style", pango.STYLE_ITALIC)
+    TAG_TABLE.add(tag)
+
+    # <link>
+    tag = inline_tag("link")
+    tag.set_property("foreground", "#0000ff")
+    tag.set_property("underline", True)
+    TAG_TABLE.add(tag)
+
+    # <list>
+    tag = block_tag("list")
+    TAG_TABLE.add(tag)
+
+    # <note>
+    tag = block_tag("note")
+    tag.set_property("paragraph-background", "#f0f0f0")
+    tag.set_property("foreground", "#0000ee")
+    TAG_TABLE.add(tag)
+
+    # <output>
+    tag = inline_tag("output")
+    tag.set_property("family", "monospace")
+    TAG_TABLE.add(tag)
+
+    # <p>
+    tag = block_tag("p")
+    TAG_TABLE.add(tag)
+
+    # <screen>
+    tag = block_tag("screen")
+    TAG_TABLE.add(tag)
+
+    # <synopsis>
+    tag = block_tag("synopsis")
+    TAG_TABLE.add(tag)
+
+    # <sys>
+    tag = inline_tag("sys")
+    tag.set_property("family", "monospace")
+    TAG_TABLE.add(tag)
+
+    # <var>
+    tag = inline_tag("var")
+    tag.set_property("style", pango.STYLE_ITALIC)
+    TAG_TABLE.add(tag)
+
+setup_tags()
+
+
+class DocumentBuffer (gtk.TextBuffer):
+    """
+    Represents a Mallard document.
+    """
+
+    def __init__(self, filename = None):
+        """
+        Creates a Document.
+        """
+        gtk.TextBuffer.__init__(self, TAG_TABLE)
+
+        self.__filename = filename
+        self.__block_tag = "p"
+        self.__activated_tags = set()
+        self.__deactivated_tags = set()
+
+        self.connect("insert-text", self.__insert_text_cb)
+        self.connect_after("insert-text", self.__insert_text_after_cb)
+
+
+    def get_filename(self):
+        """
+        Returns the name of the file represented by the buffer.
+        """
+        return self.__filename
+
+
+    def save(self, filename = None):
+        """
+        Saves the document buffer's content. If no file name is given,
+        the document is saved at the location referred to by the the
+        return value of the buffer's get_filename() method.
+        """
+        if filename:
+            self.__filename = filename
+
+        foiegras.buffer.save.save_document(self)
+
+
+    def apply_block_tag(self, tag_name, block_iter = None):
+        """
+        Applies a block tag to the block in which the passed text iterator
+        is located. If no iterator is given, the tag is applied to the block
+        at the current cursor position.
+        """
+        if not block_iter:
+            block_iter = self.get_iter_at_mark(self.get_insert())
+
+        start_iter = block_iter.copy()
+        start_iter.set_line_offset(0)
+        end_iter = block_iter.copy()
+        end_iter.forward_to_line_end()
+
+        self.apply_tag_by_name(tag_name, start_iter, end_iter)
+
+
+    def apply_inline_tag(self, tag_name, start_iter = None, end_iter = None):
+        """
+        Applies an inline tag to the passed range. If both iterators point at
+        the same spot in the buffer, the tag is "activated", meaning that
+        it is applied to subsequently inserted text until deactivated. If no
+        iterators are given, the tag is applied to the currently selected range
+        (or activated at the current cursor position).
+        """
+        if not start_iter:
+            start_iter = self.get_iter_at_mark(self.get_insert())
+        if not end_iter:
+            end_iter = self.get_iter_at_mark(self.get_selection_bound())
+
+        if start_iter.equal(end_iter):
+            self.__set_tag_active(tag_name, True)
+        else:
+            self.apply_tag_by_name(tag_name, start_iter, end_iter)
+
+
+    def remove_inline_tag(self, tag_name, start_iter = None, end_iter = None):
+        """
+        Removes an inline tag from the passed range. If both iterators point at
+        the same spot in the buffer, the tag is deactivated (see doc comment of
+        apply_inline_tag()). If no iterators are given, the tag is removed from
+        the currently selected range (or deactivated at the current cursor
+        position).
+        """
+        if not start_iter:
+            start_iter = self.get_iter_at_mark(self.get_insert())
+        if not end_iter:
+            end_iter = self.get_iter_at_mark(self.get_selection_bound())
+
+        if start_iter.equal(end_iter):
+            self.__set_tag_active(tag_name, False)
+        else:
+            self.remove_tag_by_name(tag_name, start_iter, end_iter)
+
+
+    def __set_tag_active(self, tag_name, active):
+        """
+        Manually activates or deactivates a tag. (See apply_inline_tag().)
+        """
+        if active:
+            self.__activated_tags.add(tag_name)
+
+            if tag_name in self.__deactivated_tags:
+                self.__deactivated_tags.remove(tag_name)
+                
+        else:
+            self.__deactivated_tags.add(tag_name)
+
+            if tag_name in self.__activated_tags:
+                self.__activated_tags.remove(tag_name)
+
+
+    def get_tags_at_selected_range(self):
+        """
+        Returns the names of all tags applied to the currently selected
+        text range or, if nothing is selected, of the current cursor
+        position.
+        """
+        bounds = self.get_selection_bounds()
+
+        if len(bounds) == 0:
+            start = end = self.get_iter_at_mark(self.get_insert())
+        else:
+            start = bounds[0]
+            end = bounds[1] 
+        
+        start.backward_char()
+
+        tags = set()
+
+        for tag in start.get_tags():
+            tags.add(tag.get_property("name"))
+
+        if start.equal(end):
+            tags = tags.union(self.__activated_tags)
+        else:
+            it = start.copy()
+
+            while not it.equal(end):
+                applied = set()
+
+                for tag in it.get_tags():
+                    applied.add(tag.get_property("name"))
+
+                tags = tags.intersection(applied)
+                it.forward_char()
+
+        if len(tags) == 0:
+            tags.add("p")
+
+        return tags
+
+
+    def __insert_text_cb(self, textbuffer, location, text, length):
+        """
+        "insert-text" signal handler.
+        """
+        block_tag = None
+
+        for tag_name in BLOCK_TAGS:
+            tag = self.get_tag_table().lookup(tag_name)
+
+            if location.has_tag(tag):
+                block_tag = tag_name
+
+        if block_tag:
+            self.__block_tag = block_tag
+        else:
+            self.__block_tag = "p"
+
+
+    def __insert_text_after_cb(self, textbuffer, location, text, length):
+        """
+        "insert-text" signal handler. (Runs after the default hander).
+        """
+        num_lines_back = 0
+
+        for i in range(length):
+            if text[i] == "\n" or (text[i] == "\r" and text[i + 1] != "\n"):
+                 num_lines_back += 1
+
+        for i in range(num_lines_back):
+            location.backward_line()
+
+        self.apply_block_tag(self.__block_tag, location)
+
+        start_iter = location.copy()
+        start_iter.backward_chars(length)
+
+        for tag_name in self.__get_active_tags(start_iter):
+            self.apply_tag_by_name(tag_name, start_iter, location)
+
+        self.notify("cursor-position")
+
+
+    def __get_active_tags(self, location):
+        """
+        Returns the active tags at the passed text iterator.
+        """
+        active_tags = set()
+
+        it = location.copy()
+        it.backward_char()
+
+        for tag in it.get_tags():
+            active_tags.add(tag.get_property("name"))
+
+        active_tags = active_tags.union(self.__activated_tags)
+        active_tags = active_tags.difference(self.__deactivated_tags)
+
+        self.__activated_tags.clear()
+        self.__deactivated_tags.clear()
+
+        if len(active_tags) == 0:
+            active_tags.add("p")
+
+        return active_tags
+

Modified: trunk/src/foiegras/document.py
==============================================================================
--- trunk/src/foiegras/document.py	(original)
+++ trunk/src/foiegras/document.py	Fri Feb  1 16:38:06 2008
@@ -19,88 +19,102 @@
 import gtk
 
 import foiegras.buffer
-from foiegras.buffer import MallardBuffer
-from foiegras.buffer import textview
+from foiegras import docbuffer
 
 
 class Document(gtk.VBox):
     """
     This is the default Document abstraction class.
     """
+
     def __init__(self, filename=None):
         """ Constructor for Document. """
         gtk.VBox.__init__(self)
-        
-        self._view = textview.MallardTextView(buffer=None)
 
-        self._buffer = MallardBuffer.MallardBuffer(self._view, filename)
-        self._view.set_buffer (self._buffer)
-        self._buffer.read_page(show_tags=False) 
+        self._buffer = docbuffer.DocumentBuffer()
+
+        self._view = gtk.TextView(self._buffer)
+        self._view.set_pixels_above_lines(6)
+        self._view.set_pixels_below_lines(6)
+        self._view.set_left_margin(6)
+        self._view.set_right_margin(6)
 
         self._filename = filename
         self._changed = False
-        
-        # Read the file's contents into the buffer
-#         if self._filename is not None:
-#             f = file(self._filename, 'r')
-#             self._buffer.set_text(f.read())
-#             f.close()
-        
-        # Set up the callback for text change
-        self._buffer.connect('changed', self._set_changed)
-        
+
         # Create the ScrolledWindow
         self._scrolledwindow = gtk.ScrolledWindow()
         self._scrolledwindow.add(self._view)
         self._scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        
+
         self.add(self._scrolledwindow)
         self.show_all()
-#         itst = self._buffer.get_start_iter()
-#         itend = self._buffer.get_end_iter()
 
-#         print "Text amount: "+str(self._buffer.get_text(itst, itend, True))
 
-    
     def _set_changed(self, buffer):
-        """ Text has changed in the TextBuffer. """
+        """
+        Text has changed in the TextBuffer.
+        """
         self._changed = True
-    
+
     def apply_patch(self, patch_file):
-        """ Applies a patch to the current document - useful for the review mode. """
+        """
+        Applies a patch to the current document - useful for the review mode.
+        """
         pass
-    
+
+
     def get_buffer(self):
-        """ Returns the TextBuffer. """
+        """
+        Returns the TextBuffer.
+        """
         return self._buffer
-    
+
+
     def get_changed(self):
-        """ Returns True if the text has changed. """
+        """
+        Returns True if the text has changed.
+        """
         return self._changed
-    
+
+
     def get_filename(self):
-        """ Returns the filename of the document. """
+        """
+        Returns the filename of the document.
+        """
         return self._filename
-    
+
+
     def get_content(self):
-        """ Return the text of the document (contents of file). """
+        """
+        Returns the text of the document (contents of file).
+        """
         (start, end) = self._buffer.get_bounds()
         return self._buffer.get_text(start, end)
-    
+
+
     def get_view(self):
-        """ Return the TextView. """
+        """
+        Return the TextView.
+        """
         return self._view
-    
+
+
     def open(filename):
-        """ Static method that returns a Document object if open is
-        successful. """
+        """
+        Static method that returns a Document object if open is
+        successful.
+        """
         # FIXME: need to work out proper opening, e.g. file checks and throwing
         # exceptions if something went wrong
         doc = Document(filename)
         return doc
-    
+
+
     def save(self):
-        """ Save the document. """
+        """
+        Save the document.
+        """
         if self._filename is not None:
             f = file(self._filename, 'w')
             (start, end) = self._buffer.get_bounds()
@@ -109,9 +123,12 @@
             self._changed = False
         else:
             print "DEBUG: no filename specified, really shouldn't happen."
-    
+
+
     def set_filename(self, filename):
-        """ Specify the document's filename. """
+        """
+        Specify the document's filename.
+        """
         self._filename = filename
 
 
@@ -120,21 +137,30 @@
     This class represents a translatable Document (it has a read-only original
     document, and a translatable document in split view).
     """
+
     def __init__(self, filename, pofile):
-        """ Constructor for TranslateDocument. """
+        """
+        Constructor for TranslateDocument.
+        """
         Document.__init__(self, filename)
-        
+
         self._obuffer = gtk.TextBuffer()
         self._oview = gtk.TextView(self._obuffer)
-    
+
+
     def open(filename, pofile):
-        """ Static method that returns a TranslateDocument object if open is
-        successful. """
+        """
+        Static method that returns a TranslateDocument object if open is
+        successful.
+        """
         # FIXME: need to work out proper opening, e.g. file checks and throwing
         # exceptions if something went wrong
         doc = TranslateDocument(filename, pofile)
         return doc
-    
+
+
     def save(self):
-        """ Save the translation. """
+        """
+        Save the translation.
+        """
         pass

Modified: trunk/src/foiegras/windows/main.py
==============================================================================
--- trunk/src/foiegras/windows/main.py	(original)
+++ trunk/src/foiegras/windows/main.py	Fri Feb  1 16:38:06 2008
@@ -31,10 +31,48 @@
 from foiegras.windows.preferences import PreferencesDialog
 from foiegras.windows.patch import CreatePatchDialog
 
+ACTION_TO_TAG = {
+    # block tags
+    'CaptionAction'          : 'caption',
+    'CitationAction'         : 'cite',
+    'MultimediaObjectAction' : 'media',
+    'CodeSnippetAction'      : 'code',
+    'ParagraphAction'        : 'p',
+    'EditorialCommentAction' : 'comment',
+    'FigureAction'           : 'figure',
+    'ListAction'             : 'list',
+    'NoteAction'             : 'note',
+    'ScreenAction'           : 'screen',
+    'SynopseAction'          : 'synopse',
+    'TableAction'            : 'table',
+
+    # inline tags
+    'ApplicationNameAction'  : 'app',
+    'CommandAction'          : 'cmd',
+    'ComputerOutputAction'   : 'output',
+    'DateAction'             : 'date',
+    'EmphasisAction'         : 'em',
+    'FileNameAction'         : 'file',
+    'GUILabelAction'         : 'gui',
+    'HyperlinkAction'        : 'link',
+    'InlineCodeAction'       : 'code-inline',
+    'KeyStrokeAction'        : 'key',
+    'QuoteAction'            : 'quote',
+    'SystemItemAction'       : 'sys',
+    'UserInputAction'        : 'input',
+    'VariableTextAction'     : 'var',
+}
+
+TAG_TO_ACTION = {}
+for key in ACTION_TO_TAG.iterkeys():
+    TAG_TO_ACTION[ACTION_TO_TAG[key]] = key
+
+
 def _(str):
     """ Dummy gettext replacement. """
     return str
 
+
 class OpenRecentToolAction(gtk.Action):
     __gtype_name__ = "OpenRecentToolAction"
 
@@ -43,7 +81,10 @@
 
 
 class MainWindow:
-    """ This is a wrapper class around Foie Gras main window. """
+    """
+    This is a wrapper class around Foie Gras main window.
+    """
+
     def __init__(self, app, filename=None):
         """
         Constructor for the MainWindow.
@@ -53,21 +94,22 @@
         self._app = app
         self._conf = self._app.get_conf()
         self._document = None
-        
+        self._auto_toggled = False
+
         gladefile = self._app.get_datadir() + os.sep + 'main.glade'
         self._glade = gtk.glade.XML(gladefile, 'window_main', 'foiegras')
-        
+
         signals = { 'on_window_main_delete_event': self.close }
-        
+
         self._glade.signal_autoconnect(signals)
-        
+
         self._window = self._glade.get_widget('window_main')
         self._vbox = self._glade.get_widget('vbox_main')
         self._hpaned = self._glade.get_widget('hpaned_document')
-        
+
         # Set up UIManager to load menus and toolbars
         self.uimanager = gtk.UIManager()
-        
+
         # Set up actions
         actions = [
             ('FileMenuAction', None, _("File"), None, _(""), self.dummy_action),
@@ -91,43 +133,49 @@
             ('PreferencesAction', gtk.STOCK_PREFERENCES, _("Preferences"), None, _(""), self.show_preferences),
             ('InformationsAction', gtk.STOCK_INFO, _("Informations"), None, _(""), self.dummy_action),
             ('SectionsAction', None, _("Sections"), None, _(""), self.dummy_action),
-            ('CaptionAction', None, _("Caption"), None, _(""), self.dummy_action),
-            ('CitationAction', None, _("Citation"), None, _(""), self.dummy_action),
-            ('MultimediaObjectAction', None, _("Multimedia Object"), None, _(""), self.dummy_action),
-            ('CodeSnippetAction', None, _("Code Snippet"), None, _(""), self.dummy_action),
-            ('ParagraphAction', None, _("Paragraph"), None, _(""), self.dummy_action),
-            ('ScreenAction', None, _("Screen"), None, _(""), self.dummy_action),
-            ('EditorialCommentAction', None, _("Editorial Comment"), None, _(""), self.dummy_action),
-            ('FigureAction', None, _("Figure"), None, _(""), self.dummy_action),
-            ('ListAction', None, _("List"), None, _(""), self.dummy_action),
-            ('NoteAction', None, _("Note"), None, _(""), self.dummy_action),
-            ('SynopseAction', None, _("Synopse"), None, _(""), self.dummy_action),
-            ('TableAction', None, _("Table"), None, _(""), self.dummy_action),
-            ('ApplicationNameAction', gtk.STOCK_EXECUTE, _("Application Name"), None, _(""), self.dummy_action),
-            ('CommandAction', None, _("Command"), None, _(""), self.dummy_action),
-            ('ComputerOutputAction', None, _("Computer Output"), None, _(""), self.dummy_action),
-            ('DateAction', None, _("Date"), None, _(""), self.dummy_action),
-            ('EmphasisAction', None, _("Emphasis"), None, _(""), self.dummy_action),
-            ('FileNameAction', None, _("File Name"), None, _(""), self.dummy_action),
-            ('GUILabelAction', None, _("GUI Label"), None, _(""), self.dummy_action),
-            ('HyperlinkAction', None, _("Hyperlink"), None, _(""), self.dummy_action),
-            ('KeyStrokeAction', None, _("Key Stroke"), None, _(""), self.dummy_action),
-            ('QuoteAction', None, _("Quote"), None, _(""), self.dummy_action),
-            ('SystemItemAction', None, _("System Item"), None, _(""), self.dummy_action),
-            ('UserInputAction', None, _("User Input"), None, _(""), self.dummy_action),
-            ('VariableTextAction', None, _("Variable Text"), None, _(""), self.dummy_action),
             ('CreatePatchAction', None, _("Create Patch"), None, _(""), self.create_patch),
             ('CommitAction', None, _("Commit"), None, _(""), self.commit),
             ('ReviewAction', None, _("Review"), None, _(""), self.dummy_action),
             ('ContentsAction', None, _("Contents"), None, _(""), self.dummy_action),
             ('AboutAction', gtk.STOCK_ABOUT, _("About"), None, _(""), self.about)
         ]
+
+        self._annotation_actions = [
+            ('CaptionAction', None, _("_Caption"), None, _(""), self.apply_block_tag),
+            ('CitationAction', None, _("Citation"), None, _(""), self.apply_block_tag),
+            ('MultimediaObjectAction', None, _("Multimedia Object"), None, _(""), self.apply_block_tag),
+            ('CodeSnippetAction', None, _("Code Snippet"), None, _(""), self.apply_block_tag),
+            ('ParagraphAction', None, _("Paragraph"), None, _(""), self.apply_block_tag),
+            ('ScreenAction', None, _("Screen"), None, _(""), self.apply_block_tag),
+            ('EditorialCommentAction', None, _("Editorial Comment"), None, _(""), self.apply_block_tag),
+            ('FigureAction', None, _("Figure"), None, _(""), self.apply_block_tag),
+            ('ListAction', None, _("List"), None, _(""), self.apply_block_tag),
+            ('NoteAction', None, _("Note"), None, _(""), self.apply_block_tag),
+            ('SynopseAction', None, _("Synopse"), None, _(""), self.apply_block_tag),
+            ('TableAction', None, _("Table"), None, _(""), self.apply_block_tag),
+            ('ApplicationNameAction', gtk.STOCK_EXECUTE, _("Application Name"), None, _(""), self.apply_inline_tag),
+            ('CommandAction', None, _("Command"), None, _(""), self.apply_inline_tag),
+            ('ComputerOutputAction', None, _("Computer Output"), None, _(""), self.apply_inline_tag),
+            ('DateAction', None, _("Date"), None, _(""), self.apply_inline_tag),
+            ('EmphasisAction', None, _("_Emphasis"), None, _(""), self.apply_inline_tag),
+            ('FileNameAction', None, _("File Name"), None, _(""), self.apply_inline_tag),
+            ('GUILabelAction', None, _("GUI Label"), None, _(""), self.apply_inline_tag),
+            ('HyperlinkAction', None, _("Hyperlink"), None, _(""), self.apply_inline_tag),
+            ('InlineCodeAction', None, _("Inline Code"), None, _(""), self.apply_inline_tag),
+            ('KeyStrokeAction', None, _("Key Stroke"), None, _(""), self.apply_inline_tag),
+            ('QuoteAction', None, _("Quote"), None, _(""), self.apply_inline_tag),
+            ('SystemItemAction', None, _("System Item"), None, _(""), self.apply_inline_tag),
+            ('UserInputAction', None, _("User Input"), None, _(""), self.apply_inline_tag),
+            ('VariableTextAction', None, _("Variable Text"), None, _(""), self.apply_inline_tag),
+        ]
+
         self._actiongroup = gtk.ActionGroup('menubar')
         self._actiongroup.add_actions(actions)
+        self._actiongroup.add_toggle_actions(self._annotation_actions)
         self._actiongroup.add_action(OpenRecentToolAction("OpenToolAction", _("Open"), _(""), gtk.STOCK_OPEN))
-        
+
         self.uimanager.insert_action_group(self._actiongroup, 0)
-        
+
         # Further UIManager stuff
         self.ui = {}
         self.ui['menubar'] = self.uimanager.add_ui_from_file(self._app.get_datadir() + os.sep + 'menubar.ui')
@@ -138,16 +186,16 @@
         self._tool_open = self.uimanager.get_widget('/MainToolbar/Open')
         self._toolbar_block = self.uimanager.get_widget('/BlockToolbar')
         self._toolbar_inline = self.uimanager.get_widget('/InlineToolbar')
-        
+
         # Initialize Recently Used submenu
         self._recent_menu = gtk.RecentChooserMenu(self._app.recent_manager)
         self._recent_menu.connect('item-activated', self._recent_item_activated)
         self._recent_menu.add_filter(self._app.recent_filter)
         self._menu_recent.set_submenu(self._recent_menu)
         self._tool_open.set_menu(self._recent_menu)
-        
+
         self._tool_open.connect('clicked', self._open_toolbar)
-        
+
         # Toolbar properties
         self._toolbar_block.set_orientation(gtk.ORIENTATION_VERTICAL)
         self._toolbar_block.set_style(gtk.TOOLBAR_BOTH_HORIZ)
@@ -155,20 +203,22 @@
         self._toolbar_inline.set_orientation(gtk.ORIENTATION_VERTICAL)
         self._toolbar_inline.set_style(gtk.TOOLBAR_BOTH_HORIZ)
         self._toolbar_inline.set_border_width(3)
-        
+
         # Iterate through the ToolItems and set the label alignment accordingly
         num = self._toolbar_block.get_n_items()
         for i in range(num):
             item = self._toolbar_block.get_nth_item(i)
+            item.set_use_underline(True)
             try:
                 l = gtk.Label(item.get_label())
                 l.set_alignment(0.0, 0.5)
                 l.set_padding(3, 0)
+                l.set_use_underline(True)
                 l.show()
                 item.set_label_widget(l)
             except AttributeError:
                 pass
-        
+
         num = self._toolbar_inline.get_n_items()
         for i in range(num):
             item = self._toolbar_inline.get_nth_item(i)
@@ -176,91 +226,120 @@
                 l = gtk.Label(item.get_label())
                 l.set_alignment(0.0, 0.5)
                 l.set_padding(3, 0)
+                l.set_use_underline(True)
                 l.show()
                 item.set_label_widget(l)
             except AttributeError:
                 pass
-        
+
         # Pack menus and toolbars into the appropriate places
         self._vbox.pack_start(self._menubar, False, False)
         self._vbox.pack_start(self._toolbar_main, False, False)
         self._vbox.reorder_child(self._menubar, 0)
         self._vbox.reorder_child(self._toolbar_main, 1)
-        
+
         # Try to open default document (if n/a, just load a blank one)
         if filename is not None and os.path.exists(filename):
             self._document = Document(filename)
         else:
             self._document = Document()
         self._app.set_document(self._document)
-        
+        self._document.get_buffer().connect("notify::cursor-position", self._cursor_position_changed)
+
         # Set up a notebook
         self._notebook_toolbox = gtk.Notebook()
         self._notebook_toolbox.append_page(self._toolbar_block, gtk.Label(_("Block")))
         self._notebook_toolbox.append_page(self._toolbar_inline, gtk.Label(_("Inline")))
-        
+
         # Add the document and the notebook to the window
         self._hpaned.add1(self._document)
         self._hpaned.add2(self._notebook_toolbox)
-        
+
         # To be able to show the star on changes
         self._document.get_buffer().connect('changed', self._buffer_changed)
-        
+
         self.set_title()
-        
+
         # The document should grab the focus and place the cursor to the
         # beginning
         self._document.get_view().grab_focus()
         self._document.get_buffer().place_cursor(self._document.get_buffer().get_start_iter())
-        
+
         # Resize the window
         self._window.resize(self._conf.get_preference('window_width', 'int', 600),
                             self._conf.get_preference('window_height', 'int', 400))
         self._hpaned.set_position(self._conf.get_preference('hpaned_position', 'int', 400))
-    
+
+
     def _buffer_changed(self, buffer):
-        """ Text was modified, set title accordingly. """
+        """
+        Text was modified, set title accordingly.
+        """
         if self._document.get_filename() is None:
-            title = _("(Unsaved document)")
+            title = _("(Unsaved Document)")
         else:
             title = os.path.basename(self._document.get_filename())
+
+        self._window.set_title('*%s - Foie Gras' % title)
+
+
+    def _cursor_position_changed(self, buf, arg):
+        """
+        Updates the toggle action's state when the cursor position changes.
+        """
+        tags = buf.get_tags_at_selected_range()
+
+        self._auto_toggled = True
+
+        for action_tuple in self._annotation_actions:
+            name = action_tuple[0]
+            tag = ACTION_TO_TAG[name]
+
+            self._actiongroup.get_action(name).set_active(tag in tags)
+
+        self._auto_toggled = False
+
             
-        self._window.set_title(title + '* - Foie Gras')
-    
     def _open_toolbar(self, widget):
         self.open_document(None)
-    
+
+
     def _recent_item_activated(self, chooser):
-        """ Recently Used item-activated signal handler. """
+        """
+        Recently Used item-activated signal handler.
+        """
         uri = chooser.get_current_item().get_uri()
-        
+
         if self._document.get_changed():
             dialog = AskSaveDialog(self._document.get_filename(), self._window)
-            
+
             response = dialog.run()
-            
+
             if response != gtk.RESPONSE_NONE:
                 dialog.destroy()
-                
+
                 if response == gtk.RESPONSE_YES:
                     self.save_document(None)
                 elif response == gtk.RESPONSE_NO:
                     pass
                 elif response == gtk.RESPONSE_CANCEL:
                     return
-        
+
         # Strip 'file://' from the beginning
         filename = uri[7:]
-        
+
         doc = Document(filename)
         self._app.set_document(doc)
         self.replace_document(doc)
-        
+
         # Add to Recently Used
         self._app.recent_manager.add_full(uri, self._app.recent_data)
-    
+
+
     def about(self, action):
-        """ About action handler. """
+        """
+        About action handler.
+        """
         a = gtk.AboutDialog()
         a.set_name('Foie Gras')
         a.set_version(None)
@@ -280,21 +359,24 @@
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA""")
         a.set_website('http://live.gnome.org/ProjectMallard/FoieGras')
         a.set_authors([ 'Szilveszter Farkas <szilveszter farkas gmail com>' ])
-        
+
         a.run()
         a.destroy()
-    
+
+
     def close(self, widget, event):
-        """ Close window event handler. """
+        """
+        Close window event handler.
+        """
         # Check whether document has changed
         if self._document.get_changed():
             dialog = AskSaveDialog(self._document.get_filename(), self._window)
-            
+
             response = dialog.run()
-            
+
             if response != gtk.RESPONSE_NONE:
                 dialog.destroy()
-                
+
                 if response == gtk.RESPONSE_YES:
                     # Let's save the document
                     self.save_document(None)
@@ -304,20 +386,23 @@
                 elif response == gtk.RESPONSE_CANCEL:
                     # We don't want to quit
                     return True
-        
+
         # Save the window size before quit
         size = self._window.get_size()
         self._conf.set_preference('window_width', 'int', size[0])
         self._conf.set_preference('window_height', 'int', size[1])
         self._conf.set_preference('hpaned_position', 'int', self._hpaned.get_position())
-        
+
         # End the main loop
         gtk.main_quit()
-        
+
         return False
-    
+
+
     def commit(self, action):
-        """ Commit action handler. """
+        """
+        Commit action handler.
+        """
         # We allow committing only if the document was saved
         if self._app.get_document().get_filename() is not None and not self._app.get_document().get_changed():
             dialog = CommitDialog(self._app)
@@ -325,9 +410,12 @@
         else:
             warning_dialog(_("Committing not allowed"),
                            _("Please save your document before committing."))
-    
+
+
     def create_patch(self, action):
-        """ Create Patch action handler. """
+        """
+        Create Patch action handler.
+        """
         # We allow creating patches only if the document was saved
         if self._app.get_document().get_filename() is not None and not self._app.get_document().get_changed():
             dialog = CreatePatchDialog(self._app)
@@ -335,91 +423,103 @@
         else:
             warning_dialog(_("Creating patch not allowed"),
                            _("Please save your document before creating a patch."))
-    
+
+
     def dummy_action(self, action):
-        """ Dummy action handler. """
+        """
+        Dummy action handler.
+        """
         pass
-    
+
+
     def new_document(self, action):
-        """ New document. """
+        """
+        New document.
+        """
         if self._document.get_changed():
             dialog = AskSaveDialog(self._document.get_filename(), self._window)
-            
+
             response = dialog.run()
-            
+
             if response != gtk.RESPONSE_NONE:
                 dialog.destroy()
-                
+
                 if response == gtk.RESPONSE_YES:
                     self.save_document(None)
                 elif response == gtk.RESPONSE_NO:
                     pass
                 elif response == gtk.RESPONSE_CANCEL:
                     return
-        
+
         doc = Document()
         self._app.set_document(self._document)
         self.replace_document(doc)
 
+
     def open_document(self, action):
-        """ OpenAction handler. """
+        """
+        OpenAction handler.
+        """
         if self._document.get_changed():
             dialog = AskSaveDialog(self._document.get_filename(), self._window)
-            
+
             response = dialog.run()
-            
+
             if response != gtk.RESPONSE_NONE:
                 dialog.destroy()
-                
+
                 if response == gtk.RESPONSE_YES:
                     self.save_document(None)
                 elif response == gtk.RESPONSE_NO:
                     pass
                 elif response == gtk.RESPONSE_CANCEL:
                     return
-        
+
         open_buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                         gtk.STOCK_OPEN, gtk.RESPONSE_OK)
-        
+
         filter = gtk.FileFilter()
         filter.set_name(_("Project Mallard XML files"))
         filter.add_pattern('*.xml')
         filter_all = gtk.FileFilter()
         filter_all.set_name(_("All files"))
         filter_all.add_pattern('*')
-            
+
         dialog = gtk.FileChooserDialog(title=_("Open Document"),
                                        action=gtk.FILE_CHOOSER_ACTION_OPEN,
                                        buttons=open_buttons)
         dialog.set_default_response(gtk.RESPONSE_OK)
         dialog.add_filter(filter)
         dialog.add_filter(filter_all)
-        
+
         response = dialog.run()
-        
+
         if response != gtk.RESPONSE_NONE:
             if response == gtk.RESPONSE_OK:
                 doc = Document(dialog.get_filename())
                 self._app.set_document(doc)
                 self.replace_document(doc)
-                
+
                 # Add to Recently Used
                 self._app.recent_manager.add_full('file://' + dialog.get_filename(),
                                                   self._app.recent_data)
-            
+
             dialog.destroy()
-    
+
+
     def quit(self, action):
-        """ QuitAction handler. """
+        """
+        QuitAction handler.
+        """
         # Check whether document has changed
         if self._document.get_changed():
             dialog = AskSaveDialog(self._document.get_filename(), self._window)
-            
+
             response = dialog.run()
-            
+
             if response != gtk.RESPONSE_NONE:
                 dialog.destroy()
-                
+
                 if response == gtk.RESPONSE_YES:
                     # Let's save the document
                     self.save_document(None)
@@ -429,16 +529,17 @@
                 elif response == gtk.RESPONSE_CANCEL:
                     # We don't want to quit
                     return
-        
+
         # Save the window size before quit
         size = self._window.get_size()
         self._conf.set_preference('window_width', 'int', size[0])
         self._conf.set_preference('window_height', 'int', size[1])
         self._conf.set_preference('hpaned_position', 'int', self._hpaned.get_position())
-        
+
         # End the main loop
         gtk.main_quit()
-    
+
+
     def replace_document(self, new_document):
         """
         Replace the current document in the main window with the document
@@ -452,98 +553,139 @@
         self._hpaned.add1(self._document)
         # Show the document itself
         self._document.show_all()
-        
+
         # To be able to show the star on changes
         self._document.get_buffer().connect('changed', self._buffer_changed)
-        
+
         self.set_title()
-        
+
         # The document should grab the focus and place the cursor to the
         # beginning
         self._document.get_view().grab_focus()
         self._document.get_buffer().place_cursor(self._document.get_buffer().get_start_iter())
-    
+
+
     def save_document(self, action):
-        """ SaveAction handler. """
+        """
+        SaveAction handler.
+        """
         doc = self._app.get_document()
-        
+
         if doc.get_filename() is not None:
             doc.save()
             self.set_title()
         else:
             self.save_document_as(action)
-    
+
+
     def save_document_as(self, action):
-        """ SaveAsAction handler. """
+        """
+        SaveAsAction handler.
+        """
         doc = self._app.get_document()
-        
+
         save_buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                         gtk.STOCK_SAVE, gtk.RESPONSE_OK)
-        
+
         filter = gtk.FileFilter()
         filter.set_name(_("Project Mallard XML files"))
         filter.add_pattern('*.xml')
         filter_all = gtk.FileFilter()
         filter_all.set_name(_("All files"))
         filter_all.add_pattern('*')
-        
+
         dialog = gtk.FileChooserDialog(title=_("Save Document"),
                                        action=gtk.FILE_CHOOSER_ACTION_SAVE,
                                        buttons=save_buttons)
         dialog.set_default_response(gtk.RESPONSE_OK)
         dialog.add_filter(filter)
         dialog.add_filter(filter_all)
-        
+
         response = dialog.run()
-        
+
         fn = None
-        
+
         if response != gtk.RESPONSE_NONE:
             if response == gtk.RESPONSE_OK:
                 fn = dialog.get_filename()
                 if fn[-4:] != '.xml':
                     fn = fn + '.xml'
-            
+
             dialog.destroy()
-        
+
         if fn is not None:
             if os.path.exists(fn):
                 # We have a problem: file already exists
                 dialog = AskOverwriteDialog(self._document.get_filename(), self._window)
-                
+
                 response = dialog.run()
-                
+
                 if response != gtk.RESPONSE_NONE:
                     dialog.destroy()
-                    
+
                     if response == gtk.RESPONSE_CANCEL:
                         return
                 else:
                     return
-            
+
             doc.set_filename(fn)
             doc.save()
-            
+
             # Add to Recently Used
             self._app.recent_manager.add_full('file://' + fn,
                                               self._app.recent_data)
-            
+
             self.set_title()
-    
+
+
     def set_title(self):
-        """ Put the filename into the main window's title. """
+        """
+        Put the filename into the main window's title.
+        """
         if self._document.get_filename() is None:
-            title = _("(Unsaved document)")
+            title = _('(Unsaved Document)')
         else:
             title = os.path.basename(self._document.get_filename())
-            
+
         self._window.set_title(title + ' - Foie Gras')
-    
+
+
     def show(self):
-        """ Display the window. """
+        """
+        Display the window.
+        """
         self._window.show_all()
-    
+
+
     def show_preferences(self, action):
-        """ Show the Preferences dialog. """
+        """
+        Show the Preferences dialog.
+        """
         pref = PreferencesDialog(self._app)
         pref.show()
+
+
+    def apply_block_tag(self, action):
+        """
+        Applies a block tag to the current selection.
+        """
+        if not self._auto_toggled:
+            tag = ACTION_TO_TAG[action.get_name()]
+            self._document._buffer.apply_block_tag(tag)
+
+
+    def apply_inline_tag(self, action):
+        """
+        Applies an inline tag to the current selection.
+        """
+        if not self._auto_toggled:
+            tag = ACTION_TO_TAG[action.get_name()]
+
+            if action.get_active():
+                self._document._buffer.apply_inline_tag(tag)
+            else:
+                self._document._buffer.remove_inline_tag(tag)
+
+            self._document.get_view().grab_focus()
+
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]