foiegras r47 - in trunk: . data doc src src/foiegras src/foiegras/buffer src/foiegras/vcs src/foiegras/windows



Author: dscorgie
Date: Mon Jan 28 19:26:58 2008
New Revision: 47
URL: http://svn.gnome.org/viewvc/foiegras?rev=47&view=rev

Log:
Initial merge of tags and appshell branches into trunk


Added:
   trunk/ChangeLog
   trunk/MAINTAINERS
   trunk/data/
   trunk/data/commit.glade
   trunk/data/main.glade
   trunk/data/menubar.ui
   trunk/data/patch.glade
   trunk/data/preferences.glade
   trunk/data/taglist.xml
   trunk/data/toolbar.ui
   trunk/doc/
   trunk/doc/gconf.txt
   trunk/doc/testattributes.py   (contents, props changed)
   trunk/mallard.png   (contents, props changed)
   trunk/setup.py   (contents, props changed)
   trunk/src/
   trunk/src/foiegras/
   trunk/src/foiegras/__init__.py
   trunk/src/foiegras/application.py
   trunk/src/foiegras/attributes.py
   trunk/src/foiegras/buffer/
   trunk/src/foiegras/buffer/MallardBuffer.py
   trunk/src/foiegras/buffer/MallardTextView.py
   trunk/src/foiegras/buffer/__init__.py
   trunk/src/foiegras/buffer/attribute_handler.py
   trunk/src/foiegras/buffer/attribute_renderer.py
   trunk/src/foiegras/buffer/block_handler.py
   trunk/src/foiegras/buffer/buffer.py
   trunk/src/foiegras/buffer/editor.py
   trunk/src/foiegras/buffer/inline_handler.py
   trunk/src/foiegras/buffer/mallard.png   (contents, props changed)
   trunk/src/foiegras/buffer/table.py
   trunk/src/foiegras/buffer/table_handler.py
   trunk/src/foiegras/buffer/tagparser.py
   trunk/src/foiegras/buffer/testing.xml
   trunk/src/foiegras/buffer/xmlparser.py
   trunk/src/foiegras/document.py
   trunk/src/foiegras/errors.py
   trunk/src/foiegras/preferences.py
   trunk/src/foiegras/vcs/
   trunk/src/foiegras/vcs/__init__.py
   trunk/src/foiegras/vcs/bazaar.py
   trunk/src/foiegras/vcs/subversion.py
   trunk/src/foiegras/windows/
   trunk/src/foiegras/windows/__init__.py
   trunk/src/foiegras/windows/commit.py
   trunk/src/foiegras/windows/dialog.py
   trunk/src/foiegras/windows/main.py
   trunk/src/foiegras/windows/patch.py
   trunk/src/foiegras/windows/preferences.py
   trunk/start-foiegras   (contents, props changed)
   trunk/testing.xml

Added: trunk/MAINTAINERS
==============================================================================
--- (empty file)
+++ trunk/MAINTAINERS	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,3 @@
+Don Scorgie
+E-mail: Don Scorgie org
+Userid: dscorgie

Added: trunk/data/commit.glade
==============================================================================
--- (empty file)
+++ trunk/data/commit.glade	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.3.1 on Sun Jul 15 21:56:13 2007 by phanatic snatcher-->
+<glade-interface>
+  <widget class="GtkDialog" id="dialog_commit">
+    <property name="width_request">500</property>
+    <property name="height_request">400</property>
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Commit to Repository</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox">
+        <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="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox_commit">
+            <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="spacing">3</property>
+            <child>
+              <widget class="GtkTable" id="table_commit">
+                <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="n_rows">2</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">3</property>
+                <property name="row_spacing">3</property>
+                <child>
+                  <widget class="GtkEntry" id="entry_relpath">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <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="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkComboBox" id="combobox_vcsprofile">
+                    <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>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label_relpath">
+                    <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="xalign">0</property>
+                    <property name="label" translatable="yes">Relative path:</property>
+                  </widget>
+                  <packing>
+                    <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>
+                  <widget class="GtkLabel" id="label_vcsprofile">
+                    <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="xalign">0</property>
+                    <property name="label" translatable="yes">Version Control profile:</property>
+                  </widget>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label_message">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">Please provide a commit message:</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkScrolledWindow" id="scrolledwindow_message">
+                <property name="visible">True</property>
+                <property name="can_focus">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="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                <property name="shadow_type">GTK_SHADOW_IN</property>
+                <child>
+                  <widget class="GtkTextView" id="textview_message">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area">
+            <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="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button_cancel">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_cancel_clicked"/>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button_commit">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">Commi_t</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_commit_clicked"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/data/main.glade
==============================================================================
--- (empty file)
+++ trunk/data/main.glade	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.3.3 on Sat Aug  4 20:13:48 2007 -->
+<glade-interface>
+  <widget class="GtkWindow" id="window_main">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Foie Gras</property>
+    <signal name="delete_event" handler="on_window_main_delete_event"/>
+    <child>
+      <widget class="GtkVBox" id="vbox_main">
+        <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>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <widget class="GtkHPaned" id="hpaned_document">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkStatusbar" id="statusbar_main">
+            <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="spacing">2</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/data/menubar.ui
==============================================================================
--- (empty file)
+++ trunk/data/menubar.ui	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,69 @@
+<ui>
+    <menubar name="MainMenu">
+        <menu name="FileMenu" action="FileMenuAction">
+            <menuitem name="New" action="NewAction" />
+            <menuitem name="Open" action="OpenAction" />
+            <menuitem name="RecentlyUsed" action="RecentlyUsedAction" />
+            <separator />
+            <menuitem name="Save" action="SaveAction" />
+            <menuitem name="SaveAs" action="SaveAsAction" />
+            <separator />
+            <menuitem name="Quit" action="QuitAction" />
+        </menu>
+        <menu name="EditMenu" action="EditMenuAction">
+            <menuitem name="Undo" action="UndoAction" />
+            <menuitem name="Redo" action="RedoAction" />
+            <separator />
+            <menuitem name="Cut" action="CutAction" />
+            <menuitem name="Copy" action="CopyAction" />
+            <menuitem name="Paste" action="PasteAction" />
+            <separator />
+            <menuitem name="Preferences" action="PreferencesAction" />
+        </menu>
+        <menu name="DocumentMenu" action="DocumentMenuAction">
+            <menuitem name="Informations" action="InformationsAction" />
+            <menuitem name="Sections" action="SectionsAction" />
+        </menu>
+        <menu name="BlockMenu" action="BlockMenuAction">
+            <menuitem name="Caption" action="CaptionAction" />
+            <menuitem name="Citation" action="CitationAction" />
+            <menuitem name="MultimediaObject" action="MultimediaObjectAction" />
+            <menuitem name="CodeSnippet" action="CodeSnippetAction" />
+            <menuitem name="Paragraph" action="ParagraphAction" />
+            <menuitem name="Screen" action="ScreenAction" />
+            <menuitem name="EditorialComment" action="EditorialCommentAction" />
+            <menuitem name="Figure" action="FigureAction" />
+            <menuitem name="List" action="ListAction" />
+            <menuitem name="Note" action="NoteAction" />
+            <menuitem name="Synopse" action="SynopseAction" />
+            <menuitem name="Table" action="TableAction" />
+        </menu>
+        <menu name="InlineMenu" action="InlineMenuAction">
+            <menuitem name="ApplicationName" action="ApplicationNameAction" />
+            <menuitem name="CodeSnippet" action="CodeSnippetAction" />
+            <menuitem name="Command" action="CommandAction" />
+            <menuitem name="ComputerOutput" action="ComputerOutputAction" />
+            <menuitem name="Date" action="DateAction" />
+            <menuitem name="Emphasis" action="EmphasisAction" />
+            <menuitem name="FileName" action="FileNameAction" />
+            <menuitem name="GUILabel" action="GUILabelAction" />
+            <menuitem name="Hyperlink" action="HyperlinkAction" />
+            <menuitem name="KeyStroke" action="KeyStrokeAction" />
+            <menuitem name="MultimediaObject" action="MultimediaObjectAction" />
+            <menuitem name="Quote" action="QuoteAction" />
+            <menuitem name="SystemItem" action="SystemItemAction" />
+            <menuitem name="UserInput" action="UserInputAction" />
+            <menuitem name="VariableText" action="VariableTextAction" />
+        </menu>
+        <menu name="ContributeMenu" action="ContributeMenuAction">
+            <menuitem name="CreatePatch" action="CreatePatchAction" />
+            <menuitem name="Commit" action="CommitAction" />
+            <menuitem name="Review" action="ReviewAction" />
+        </menu>
+        <menu name="HelpMenu" action="HelpMenuAction">
+            <menuitem name="Contents" action="ContentsAction" />
+            <separator />
+            <menuitem name="About" action="AboutAction" />
+        </menu>
+    </menubar>
+</ui>

Added: trunk/data/patch.glade
==============================================================================
--- (empty file)
+++ trunk/data/patch.glade	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.3.1 on Sun Jul 15 18:54:53 2007 by phanatic snatcher-->
+<glade-interface>
+  <widget class="GtkDialog" id="dialog_create_patch">
+    <property name="width_request">400</property>
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Create Patch</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox">
+        <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="spacing">2</property>
+        <child>
+          <widget class="GtkTable" id="table_create_patch">
+            <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="n_rows">2</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">3</property>
+            <property name="row_spacing">3</property>
+            <child>
+              <widget class="GtkEntry" id="entry_relpath">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <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="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label_relpath">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">Relative path:</property>
+              </widget>
+              <packing>
+                <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>
+              <widget class="GtkComboBox" id="combobox_vcsprofile">
+                <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>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label_vcsprofile">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">Version Control profile:</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area">
+            <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="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button_cancel">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_cancel_clicked"/>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button_create">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">Create _Patch</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_create_clicked"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="dialog_save_patch">
+    <property name="width_request">500</property>
+    <property name="height_request">400</property>
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Save Patch</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox">
+        <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="spacing">2</property>
+        <child>
+          <widget class="GtkScrolledWindow" id="scrolledwindow_patch">
+            <property name="visible">True</property>
+            <property name="can_focus">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="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+            <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+            <child>
+              <placeholder/>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area">
+            <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="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button_cancel">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_cancel_clicked"/>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button_save">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">gtk-save</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_save_clicked"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/data/preferences.glade
==============================================================================
--- (empty file)
+++ trunk/data/preferences.glade	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,344 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.3.1 on Sun Jul 15 18:55:22 2007 by phanatic snatcher-->
+<glade-interface>
+  <widget class="GtkDialog" id="dialog_preferences">
+    <property name="width_request">400</property>
+    <property name="height_request">400</property>
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Preferences</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox">
+        <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="spacing">2</property>
+        <child>
+          <widget class="GtkNotebook" id="notebook_preferences">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkHBox" id="hbox_preferences_vcs">
+                <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="border_width">3</property>
+                <property name="spacing">3</property>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow_vcs">
+                    <property name="visible">True</property>
+                    <property name="can_focus">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="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="treeview_vcs">
+                        <property name="visible">True</property>
+                        <property name="can_focus">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="headers_clickable">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="vbuttonbox_preferences_vcs">
+                    <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="spacing">3</property>
+                    <property name="layout_style">GTK_BUTTONBOX_START</property>
+                    <child>
+                      <widget class="GtkButton" id="button_vcs_add">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">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="label" translatable="yes">gtk-add</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                        <signal name="clicked" handler="on_button_vcs_add_clicked"/>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="button_vcs_edit">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">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="label" translatable="yes">gtk-edit</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                        <signal name="clicked" handler="on_button_vcs_edit_clicked"/>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="button_vcs_remove">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">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="label" translatable="yes">gtk-remove</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                        <signal name="clicked" handler="on_button_vcs_remove_clicked"/>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="tab_expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label_preferences_vcs">
+                <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="label" translatable="yes">Version Control</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="tab_expand">False</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area">
+            <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="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button_close">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_close_clicked"/>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="dialog_vcs_profile">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Version Control profile</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox">
+        <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="spacing">2</property>
+        <child>
+          <widget class="GtkTable" id="table_vcs">
+            <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="n_rows">5</property>
+            <property name="n_columns">2</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <widget class="GtkComboBox" id="combobox_vcs_type">
+                <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>
+              </widget>
+              <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="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label_vcs_type">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">Type:</property>
+              </widget>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label_vcs_name">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">Name:</property>
+              </widget>
+              <packing>
+                <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>
+              <widget class="GtkLabel" id="label_vcs_uri">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">URI:</property>
+              </widget>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkCheckButton" id="checkbutton_vcs_readonly">
+                <property name="visible">True</property>
+                <property name="can_focus">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="label" translatable="yes">Read-only repository</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="y_options">GTK_EXPAND</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="entry_vcs_name">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <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="y_options">GTK_EXPAND</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="entry_vcs_uri">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <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>
+                <property name="y_options">GTK_EXPAND</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label_vcs_id">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">ID:</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="entry_vcs_id">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <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_EXPAND</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area">
+            <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="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button_vcs_cancel">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_vcs_cancel_clicked"/>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button_vcs_save">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">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="label" translatable="yes">gtk-save</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_button_vcs_save_clicked"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/data/taglist.xml
==============================================================================
--- (empty file)
+++ trunk/data/taglist.xml	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,129 @@
+<!-- 
+The tag list maintains the tag list used in Foiegras.
+The default rendering style of the tags are specified here.
+To change the styles of tags, change accordingly.
+The attributes of the tags are listed under the respective tags
+-->
+
+<foiegras_tag_config>
+	<!-- inline Tags -->
+	<tag name= "em" type= "inline" style = "weight=pango.WEIGHT_BOLD" >
+	</tag>
+
+	<tag name= "link" type= "inline" style = "weight=pango.WEIGHT_NORMAL,foreground = 'blue', underline=pango.UNDERLINE_SINGLE " >
+		<type>embed</type> 		
+		<xref>CONSTRAINT_STRING</xref>
+		<href>URL_STRING</href>		
+	</tag>
+	
+	<tag name= "code" type= "inline" style = "weight=pango.WEIGHT_NORMAL,foreground = 'blue', family = 'Monospace'" >
+		<xref>CONSTRAINT_STRING</xref>		
+	</tag>
+	
+	<tag name= "app" type= "inline" style = "weight=pango.WEIGHT_NORMAL, style = pango.STYLE_ITALIC, font = 'Arial Bold Italic 13'" >
+	</tag>
+	
+	<tag name= "cmd" type= "inline" style = "family = 'Monospace', background='#e3e7fb'" >
+	</tag>
+	
+	<tag name= "var" type= "inline" style = "family = 'Monospace', style = pango.STYLE_ITALIC" >
+	</tag>
+	
+	<tag name= "file" type= "inline" style = "family = 'Sans', weight = pango.WEIGHT_BOLD" >
+	</tag>
+	
+	<tag name= "gui" type= "inline" style = "font = 'Times New Roman Italic 12', style = pango.STYLE_ITALIC, weight=pango.WEIGHT_HEAVY" >
+	</tag>							
+
+	<tag name= "input" type= "inline" style = "font = 'Sans Italic 12',  underline=pango.UNDERLINE_SINGLE" >
+	</tag>
+	
+	<tag name= "key" type= "inline" style = "font = 'Sans Italic 12', underline=pango.UNDERLINE_DOUBLE,weight=pango.WEIGHT_BOLD" >
+	</tag>
+	
+	<tag name= "media" type= "inline" style = "font = 'Times New Roman Italic 12'" >
+		<type>image</type>
+		<mime>image/png | image/gif | image/jpg</mime>
+		<href>PATH_STRING</href>	
+	</tag>		
+
+	<tag name= "output" type= "inline" style = "font = 'Monospace Italic bold 12', foreground = 'blue'" >
+	</tag>	
+
+	<tag name= "quote" type= "inline" style = "font = 'Monospace Italic bold 12', style=pango.STYLE_ITALIC" >
+	</tag>	
+
+	<tag name= "sys" type= "inline" style = "font = 'Arial Bold 12'" >
+	</tag>	
+
+	
+	<tag name= "tag" type= "inline" style = "weight=pango.WEIGHT_BOLD,foreground = 'green'" >
+	</tag>	
+
+	<tag name= "mal_tag" type= "inline" style = "weight=pango.WEIGHT_BOLD,foreground = 'orange'" >
+	</tag>			
+	<!-- inline Tags close -->
+	
+	
+	<!-- block tags -->
+	<tag name= "synopsis" type= "block" style = "family = 'Times New Roman', foreground = 'blue'" border = "1" border_color="blue"  background= "light green">
+	</tag>		
+	
+	<tag name= "caption" type= "block" style = "family = 'Times New Roman', foreground = 'dark gray'" border = "2" border_color="blue" background= "light gray">
+	</tag>		
+	
+	<tag name= "cite" type= "block" style = "style=pango.STYLE_ITALIC" border = "2" border_color="blue" background= "red">
+	</tag>			
+	
+	<tag name= "p" type= "block" style = "foreground = 'blue'" border = "1" border_color="blue" background = "light blue">
+	</tag>	
+	
+	<tag name= "comment" type= "block" style = "family = 'Times New Roman'" border = "2" border_color="blue" background = "light gray">
+	</tag>	
+	
+	<tag name= "figure" type= "block" style = "family = 'Times New Roman'" border = "2" border_color="gray" background = "white">
+	</tag>		 		
+	
+	<tag name= "screen" type= "block" style = "family = 'Times New Roman'" border = "2" border_color="blue" background = "light yellow">
+	</tag>	
+
+	<tag name= "list" type= "block" style = "family = 'Times New Roman'" border = "2" border_color="blue" background = "white">
+	</tag>			
+	
+	<tag name= "notes" type= "block" style = "family = 'Times New Roman'" border = "2" border_color="blue" background = "white">
+	</tag>						
+	<!-- block tags close-->
+	
+	<!-- Table tags -->
+	<tag name = "table" type= "table" style = "family = 'Times New Roman', foreground = 'black'" border = "1">
+		<frame>all | none | top | bottom | left | right</frame>
+		<rules>all | groups | none | rows | rowgroups | cols | colgroups</rules>
+		<shade>all | groups | none | rows | rowgroups | cols | colgroups</shade>		
+	</tag>		
+	
+	<tag name = "tr" type= "table" style = "family = 'Times New Roman', foreground = 'black'" border = "1">
+	</tag>		
+	
+	<tag name = "td" type= "table" style = "family = 'Times New Roman', foreground = 'black'" border = "1">
+	</tag>			
+	
+	<tag name = "thead" type= "table" style = "family = 'Times New Roman', foreground = 'black'" border = "1">
+	</tag>	
+	
+	<tag name = "tbody" type= "table" style = "family = 'Times New Roman', foreground = 'black'" border = "1">
+	</tag>	
+	
+	<tag name = "colgroup" type= "table" style = "family = 'Times New Roman', foreground = 'black'" border = "1">
+	</tag>		 	
+	
+	<tag name = "col" type= "table" style = "family = 'Times New Roman', foreground = 'black'" border = "1">
+	</tag>						
+	<!-- block tags close-->	
+
+	<!-- Special tags -->
+	<tag name = "title" type="special" style = "weight=pango.WEIGHT_BOLD,foreground = 'green'">
+	  </tag>
+	<tag name = "info" type = "special">
+	  </tag>
+
+</foiegras_tag_config>

Added: trunk/data/toolbar.ui
==============================================================================
--- (empty file)
+++ trunk/data/toolbar.ui	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,48 @@
+<ui>
+    <toolbar name="MainToolbar">
+        <toolitem name="New" action="NewAction" />
+        <toolitem name="Open" action="OpenToolAction" />
+        <toolitem name="Save" action="SaveAction" />
+        <separator />
+        <toolitem name="Cut" action="CutAction" />
+        <toolitem name="Copy" action="CopyAction" />
+        <toolitem name="Paste" action="PasteAction" />
+        <separator />
+        <toolitem name="Preferences" action="PreferencesAction" />
+        <separator />
+        <toolitem name="CreatePatch" action="CreatePatchAction" />
+        <toolitem name="Commit" action="CommitAction" />
+        <toolitem name="Review" action="ReviewAction" />
+    </toolbar>
+    <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="KeyStroke" action="KeyStrokeAction" />
+        <toolitem name="MultimediaObject" action="MultimediaObjectAction" />
+        <toolitem name="Quote" action="QuoteAction" />
+        <toolitem name="SystemItem" action="SystemItemAction" />
+        <toolitem name="UserInput" action="UserInputAction" />
+        <toolitem name="VariableText" action="VariableTextAction" />
+    </toolbar>
+</ui>

Added: trunk/doc/gconf.txt
==============================================================================
--- (empty file)
+++ trunk/doc/gconf.txt	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,14 @@
+Foie Gras GConf scheme plan
+===========================
+
+/
+    apps/
+        foiegras/
+	    vcsprofiles/
+		name
+		readonly
+		type
+		uri
+	    hpaned_position
+	    window_height
+	    window_width

Added: trunk/doc/testattributes.py
==============================================================================
--- (empty file)
+++ trunk/doc/testattributes.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+
+import gtk
+
+from foiegras.attributes import *
+
+mimefield = MIMEField(title='MIME type', default='text/plain', help_text='Select a MIME type')
+mimefield.add_filter('text/')
+mimefield.apply_filters()
+
+textfield = TextField(title='Some text', default='with default value', help_text='This text should help you...')
+
+dialog = AttributeDialog()
+dialog.add_field(mimefield)
+dialog.add_field(textfield)
+dialog.construct()
+
+dialog.run()
+print "DEBUG: values =", dialog.get_field_values()
+
+gtk.main()
+

Added: trunk/mallard.png
==============================================================================
Binary file. No diff available.

Added: trunk/setup.py
==============================================================================
--- (empty file)
+++ trunk/setup.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,32 @@
+#!/usr/bin/python
+
+import glob
+import os.path
+
+from distutils.core import setup
+
+setup(
+    name = "Foie Gras",
+    version = "0.0.0",
+    maintainer = "Szilveszter Farkas",
+    maintainer_email = "szilveszter farkas gmail com",
+    description = "WYSIWYG Documentation Editor for Project Mallard",
+    license = "GNU GPL v2",
+    scripts = [ "start-foiegras" ],
+    package_dir = {
+        "foiegras": os.path.join("src", "foiegras"),
+        "foiegras.vcs": os.path.join("src", "foiegras", "vcs"), 
+        "foiegras.windows": os.path.join("src", "foiegras", "windows"),
+        "foiegras.buffer": os.path.join("src", "foiegras", "buffer")
+        },
+    packages = [
+        "foiegras",
+        "foiegras.vcs",
+        "foiegras.windows",
+        "foiegras.buffer"
+        ],
+    data_files = [ (os.path.join("share", "foiegras"), glob.glob(os.path.join("data", "*.glade"))),
+                   (os.path.join("share", "foiegras"), glob.glob(os.path.join("data", "*.ui"))),
+                   (os.path.join("share", "foiegras"), glob.glob(os.path.join("data", "*.xml")))
+               ]
+)

Added: trunk/src/foiegras/__init__.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/__init__.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,16 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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
+

Added: trunk/src/foiegras/application.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/application.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,72 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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
+
+from foiegras.windows.main import MainWindow
+from foiegras.preferences import FoieGrasPreferencesGconf
+
+class FoieGrasApplication:
+    """
+    This is the main application class for Foie Gras.
+    """
+    def __init__(self, datadir):
+        """ Constructor for the application class. """
+        self._conf = FoieGrasPreferencesGconf()
+        self._datadir = datadir
+        self._document = None
+        
+        self._info = None
+        self._properties = None
+        self._vcs = None
+        
+        # Initialize GtkRecentManager
+        self.recent_manager = gtk.recent_manager_get_default()
+        self.recent_data = { 'mime_type': 'text/plain',
+                             'app_name': 'Foie Gras',
+                             'app_exec': 'start-foiegras' }
+        self.recent_filter = gtk.RecentFilter()
+        self.recent_filter.add_application('Foie Gras')
+        
+        self._main = MainWindow(self)
+        
+        self._main.show()
+    
+    def get_conf(self):
+        """ Return the Gconf backend object. """
+        return self._conf
+    
+    def get_datadir(self):
+        """ Return the path to the data directory. """
+        return self._datadir
+    
+    def get_document(self):
+        """ Return the Document object. """
+        return self._document
+    
+    def get_vcs(self):
+        """ Return the VersionControl object. """
+        return self._vcs
+    
+    def set_document(self, document):
+        """ Set the Document object. """
+        self._document = document
+    
+    def set_vcs(self, vcs):
+        """ Set the VersionControl object. """
+        self._vcs = vcs

Added: trunk/src/foiegras/attributes.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/attributes.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,183 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 mimetypes
+
+import gobject
+import gtk
+
+def _(x):
+    return x
+
+
+class AttributeDialog(gtk.Dialog):
+    """ This class is responsible for creating a dialog based on the added
+    attribute fields. """
+    # No fields at the beginning
+    fields = []
+    tooltips = gtk.Tooltips()
+    
+    def __init__(self, parent=None):
+        gtk.Dialog.__init__(self,
+                            _("Attribute Editor - Foie Gras"),
+                            parent,
+                            0,
+                            ( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+                              gtk.STOCK_APPLY, gtk.RESPONSE_OK )
+                        )
+        self.tooltips.enable()
+    
+    def add_field(self, field):
+        self.fields.append(field)
+    
+    def construct(self):
+        """ No more fields should be added after calling this method. """
+        self._table = gtk.Table(rows=len(self.fields), columns=2)
+        # Create labels from titles
+        self._labels = []
+        for field in self.fields:
+            self._labels.append(gtk.Label(field.title))
+            if field.help_text is not None:
+                self.tooltips.set_tip(field.get_widget(), field.help_text)
+        
+        # Build up the table
+        i = 0
+        for field in self.fields:
+            self._table.attach(self._labels[i], 0, 1, i, i + 1)
+            self._table.attach(field.get_widget(), 1, 2, i, i + 1)
+            i += 1
+        
+        # Set some properties
+        self._table.set_row_spacings(3)
+        self._table.set_col_spacings(3)
+        self._table.set_border_width(5)
+        
+        self.vbox.pack_start(self._table, True, True)
+        self.vbox.show_all()
+    
+    def get_field_values(self):
+        """ Return the field values as a list. """
+        values = []
+        for field in self.fields:
+            values.append(field.get_value())
+        
+        return values
+
+
+class BaseField:
+    """ Interface for the specific fields. """
+    # We default to required value
+    required = True
+    # No title
+    title = None
+    # Default help text is None as well
+    help_text = None
+    # Default value
+    default = None
+    
+    def __init__(self, title, help_text=None, required=True, default=None):
+        self.title = title
+        self.help_text = help_text
+        self.required = required
+        self.default = default
+        
+        self.construct_widget()
+        
+        if self.default is not None:
+            self.set_value(self.default)
+    
+    def construct_widget(self):
+        pass
+    
+    def get_value(self):
+        raise NotImplementedError
+    
+    def get_widget(self):
+        raise NotImplementedError
+    
+    def set_value(self, value):
+        raise NotImplementedError
+
+
+class MIMEField(BaseField):
+    """ Field specific to MIME types. """
+    _filters = []
+    
+    def _apply_filters(self, model, path, iter, user_data):
+        type = model.get_value(iter, 0)
+        for filter in self._filters:
+            if type.startswith(filter):
+                user_data.append([ type ])
+    
+    def add_filter(self, filter):
+        """ Add a filter. """
+        self._filters.append(filter)
+    
+    def apply_filters(self):
+        """ Apply the given filters. """
+        new_model = gtk.ListStore(gobject.TYPE_STRING)
+        self._model.foreach(self._apply_filters, new_model)
+        self._model = new_model
+        self.widget.set_model(self._model)
+        
+        # Search for the default again, since the model has changed
+        if self.default is not None:
+            self.set_value(self.default)
+    
+    def construct_widget(self):
+        self.widget = gtk.ComboBox()
+        self._model = gtk.ListStore(gobject.TYPE_STRING)
+        
+        mimetypes.init()
+        for ext, type in mimetypes.types_map.iteritems():
+            self._model.append([ type ])
+        
+        cell = gtk.CellRendererText()
+        self.widget.pack_start(cell, True)
+        self.widget.add_attribute(cell, 'text', 0)
+        self.widget.set_model(self._model)
+    
+    def get_value(self):
+        return self._model[self.widget.get_active()][0]
+    
+    def get_widget(self):
+        return self.widget
+    
+    def set_value(self, value):
+        i = 0
+        for item in self._model:
+            if value == item[0]:
+                self.widget.set_active(i)
+                break
+            i += 1
+        else:
+            self._model.append(value)
+            self.widget.set_active(len(self._model) - 1)
+
+
+class TextField(BaseField):
+    """ Field for basic text input. """
+    def construct_widget(self):
+        self.widget = gtk.Entry()
+    
+    def get_value(self):
+        return self.widget.get_text()
+    
+    def get_widget(self):
+        return self.widget
+    
+    def set_value(self, value):
+        self.widget.set_text(value)

Added: trunk/src/foiegras/buffer/MallardBuffer.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/MallardBuffer.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,50 @@
+#! /usr/bin/python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import sys, os, errno
+import gtk,pango,table,xmlparser,tagparser
+
+class MallardBuffer(gtk.TextBuffer):
+    """The main buffer for text editor"""
+    
+    def __init__(self,main_view, filename=None):
+        """Derived __init__() of gtk.TextBuffer"""
+        tagTable = table.MallardTable()
+        gtk.TextBuffer.__init__(self,tagTable)
+
+        #styles are respective tags are stored in this dict()
+        self.tag_details = dict()
+        self.inner_textviews = []        
+        self.main_textview = main_view
+        #self.window = main.window
+        self.readTags()
+        self.read_page(show_tags=False)
+        #self.create_tag("em",weight = pango.WEIGHT_BOLD, foreground = "orange", style = pango.STYLE_ITALIC)
+
+    def read_page(self,file="testing.xml",show_tags=False):
+        """Opens the Mollard file and parses data to the buffer
+        """
+        try:
+            f = open(file, 'r')
+            page = f.read()
+            self.set_text(page)
+            f.close()
+            self.parser = xmlparser.Parser(self,show_tags)
+        except ZeroDivisionError:
+            print "The XML file given has errors or there's no such file"  
+               
+    def get_parser(self):
+        return self.parser
+ 
+    def readTags(self):
+        """Opens the taglist.txt file, parses and adds tags to the buffer"""
+        try:
+            tagsname = '/usr/share/foiegras/taglist.xml'
+            f = open(tagsname ,'r') 
+            page = f.read()
+            tp = tagparser.TagParser(self,page)
+        except:
+            raise
+    

Added: trunk/src/foiegras/buffer/MallardTextView.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/MallardTextView.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+class MallardTextView(gtk.TextView):
+    """
+    Customized implementation of gtk.TextView for Mallard.
+    """
+    def __init__(self,buffer = None):
+        gtk.TextView.__init__(self,buffer)
+        #stores the total height of block tag height
+        self.block_tag_length = 0
+        #complete hight of the textview
+        self.height = 0
+        #whether textview contains block tags
+        self.is_block_container = False
+        
+        
\ No newline at end of file

Added: trunk/src/foiegras/buffer/__init__.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/__init__.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,16 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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
+

Added: trunk/src/foiegras/buffer/attribute_handler.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/attribute_handler.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+"""
+attribute_handler:
+Validate attributes.
+Call attribute_renderer to render tags.
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import re,sys
+import attribute_renderer
+
+def attribute_handler(tag, buffer, tag_table, attribs, textview):
+    """
+    Handler for validating and rendering tag attributes 
+    """  
+    #check for given attributes with valid attributes
+    for k,v in attribs.iteritems():
+        if k.strip() in tag_table:
+            valid = [x.strip() for  x in tag_table[k].split("|")]
+            #Valid can be a UPPER CASED CONSTANT eg: PATH_STRING
+            #or can be a valid attrib set eg: image/png | image/gif | image/jpg
+            if len(valid) == 1 and valid[0].isupper():
+                #if attribute is a constant it'll validated here
+                if valid[0] == "PATH_STRING":
+                    if re.compile("[A-Za-z0-9/.//_+-]+\.[A-Za-z0-9//_+-]{1}" ).match(v) == None:
+                        raise InvlidAttribute("Invalid pattern for attribute '" + k + "' in '" + tag + "'")
+                if valid[0] == "URL_STRING":
+                    if re.compile("http://[A-Za-z0-9/.//_+-]+\.[A-Za-z0-9//_+-]{1}"; ).match(v) == None:
+                        raise InvlidAttribute("Invalid pattern for attribute '" + k + "' in '" + tag + "'")                    
+            else:
+                #if attribute is a set of values it'll be checked here 
+                #eg: image/png | image/gif | image/jpg
+                if v.strip() not in valid:
+                    raise InvlidAttribute(v + ": Wrong type for attribute " + k + " in " + tag)
+        else:
+            raise InvlidAttribute("Invalid attribute " + k + " for " + tag)
+    
+    #branch according to the parent tag and render accordingly        
+    if tag == "media":
+        #for media tag
+        if "href" in attribs:
+            attribute_renderer.media(buffer, attribs["href"], textview)
+
+    if tag == "table":
+        #for table tag
+        print "table tag attributes are not yet implemented."
+        pass
+        
+#User defined exception for invalid attributes
+class InvlidAttribute(Exception):
+    def __init__(self, value):
+        self.value = value
+    def __str__(self):
+        return repr(self.value)    
\ No newline at end of file

Added: trunk/src/foiegras/buffer/attribute_renderer.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/attribute_renderer.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+"""
+attribute_renderer:
+Render the attributes.
+Will be called by attribute_handler after validating attributes
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+def media(buffer,href,textview):
+    """render media tags"""
+    buffer.insert(buffer.get_end_iter(), "\n")
+    #insert image
+    image = gtk.Image()
+    image.set_from_file(href)
+    buffer.insert_pixbuf(buffer.get_end_iter(), image.get_pixbuf())
+    textview.height += image.get_pixbuf().get_height()
+    #start the new tag in a new line
+    buffer.insert(buffer.get_end_iter(), "\n")    
\ No newline at end of file

Added: trunk/src/foiegras/buffer/block_handler.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/block_handler.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import textview
+
+def handler(parser,element,attrs,tag_start,tag = None):
+    """
+    Hanlder for block tags.
+    controles how each block tag should render. Should be called from xmlparser
+    """   
+    #on tag start signal from xmlparser
+    if tag_start is True:       
+        #parent is the main text view
+        parent = parser.main_buffer.main_textview
+        #temp_buffer is the current buffer
+        parser.temp_buffer = gtk.TextBuffer( parser.main_buffer.get_tag_table() )
+        #child is the new inner text view
+        child = textview.MallardTextView(parser.temp_buffer)
+        child.set_wrap_mode(gtk.WRAP_CHAR)       
+        child.show()
+        #if no itme in innder_textviews list parent = main_buffer
+        #else choose the innermost buffer from innder_textviews list
+        if parser.main_buffer.inner_textviews:
+            parent = parser.main_buffer.inner_textviews[len(parser.main_buffer.inner_textviews)-1] 
+        #if parent is a block container
+        #add the previous block's height to get the total heigh
+        if parent.is_block_container:
+            parent.block_tag_length = parser.temp_block_height
+            parser.temp_block_height = 0
+        #the parent tag is a block container
+        parent.is_block_container = True             
+        #if width and height is defined in the tag, request a set_size 
+        if "width" and "height" in parser.main_buffer.tag_details[element].keys():
+            width = parser.main_buffer.tag_details[element]["width"]
+            height = parser.main_buffer.tag_details[element]["height"]
+            child.set_size_request(int(width),int(height)) 
+        #if background is defined in the tag    
+        if "background" in parser.main_buffer.tag_details[element].keys():
+            try:
+                color = parser.main_buffer.tag_details[element]["background"]
+                child.modify_base(gtk.STATE_NORMAL,gtk.gdk.color_parse(color) )              
+            except Exception:
+                print "Color is not recognizable"
+                exit()
+            
+        #get the text iter to position a new textview
+        iter = parent.get_buffer().get_end_iter()            
+        anchor  = parent.get_buffer().create_child_anchor(iter)           
+        #if a border is defined use a frame
+        if parser.main_buffer.tag_details[element]["border"] != 0:
+            frame = gtk.Frame()
+            frame.add(child)
+            parent.add_child_at_anchor(frame, anchor)    
+            frame.set_property('border-width', int(parser.main_buffer.tag_details[element]["border"]) )     
+            frame.set_property('shadow-type', gtk.SHADOW_ETCHED_IN)            
+            frame.set_property('shadow-type', gtk.SHADOW_ETCHED_IN)                
+            frame.show()             
+        else:
+            parent.add_child_at_anchor(child,anchor)         
+
+        #add the new inner textview to the list
+        parser.main_buffer.inner_textviews.insert(len(parser.main_buffer.inner_textviews),child)               
+        #retreive the text iter of current focused text view    
+        iter1 =  parser.temp_buffer.get_end_iter()         
+        #shows the tag if show_tags is true      
+        if parser.show_tags:
+            parser.temp_buffer.insert_with_tags_by_name(iter1,"\n<"+tag+">\n", parser.main_buffer.tag_details["mal_tag"]["tag"] )
+        else:
+            parser.temp_buffer.insert_with_tags_by_name(iter1,"\n" )
+        
+    #on tag end signal from xmlparser
+    else:
+        iter1 =  parser.temp_buffer.get_end_iter()   
+        #shows the tag if show_tags is true  
+        if parser.show_tags:            
+            parser.temp_buffer.insert_with_tags_by_name(iter1,"\n</"+element+">\n", parser.main_buffer.tag_details["mal_tag"]["tag"] )
+        elif parser.show_tags is False:
+            parser.temp_buffer.insert_with_tags_by_name(iter1,"\n" )  
+
+        #change the focus to an outer textview
+        if parser.main_buffer.inner_textviews:
+            previous_textview = parser.main_buffer.inner_textviews.pop() 
+            
+            if previous_textview.is_block_container == False:
+                parser.temp_block_height = 0
+            
+            start,end = previous_textview.get_buffer().get_bounds()
+            previous_textview.height += end.get_line()*20 + parser.temp_block_height + previous_textview.block_tag_length
+            previous_textview.set_size_request(800,previous_textview.height )
+            parser.temp_block_height += previous_textview.height      
+            #rect = previous_textview.get_visible_rect()
+            #print parser.temp_block_height,element,previous_textview.block_tag_length
+        if parser.main_buffer.inner_textviews:    
+            parser.temp_buffer = parser.main_buffer.inner_textviews[len(parser.main_buffer.inner_textviews)-1].get_buffer()
+        else:                     
+            parser.temp_buffer = parser.main_buffer        

Added: trunk/src/foiegras/buffer/buffer.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/buffer.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,54 @@
+#! /usr/bin/python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import sys, os, errno
+import gtk,pango,table,xmlparser,tagparser
+
+class MallardBuffer(gtk.TextBuffer):
+    """The main buffer for text editor"""
+    
+    def __init__(self,main_view, filename=None):
+        """Derived __init__() of gtk.TextBuffer"""
+        tagTable = table.MallardTable()
+        gtk.TextBuffer.__init__(self,tagTable)
+
+        #styles are respective tags are stored in this dict()
+        self.tag_details = dict()
+        self.inner_textviews = []        
+        self.main_textview = main_view
+        #self.window = main.window
+        self.readTags()
+        self.read_page(show_tags=False)
+        #self.create_tag("em",weight = pango.WEIGHT_BOLD, foreground = "orange", style = pango.STYLE_ITALIC)
+        print "Len of inner: "+str(len(self.inner_textviews))
+        for x in self.inner_textviews:
+            print "Showing inner"
+            x.show_all()
+
+    def read_page(self,file="testing.xml",show_tags=False):
+        """Opens the Mollard file and parses data to the buffer
+        """
+        try:
+            f = open(file, 'r+')
+            page = f.read()
+            self.set_text(page)
+            f.close()
+            self.parser = xmlparser.Parser(self,show_tags)
+        except ZeroDivisionError:
+            print "The XML file given has errors or there's no such file"  
+               
+    def get_parser(self):
+        return self.parser
+ 
+    def readTags(self):
+        """Opens the taglist.txt file, parses and adds tags to the buffer"""
+        try:
+            tagsname = '/usr/share/foiegras/taglist.xml'
+            f = open(tagsname ,'r') 
+            page = f.read()
+            tp = tagparser.TagParser(self,page)
+        except:
+            raise
+    

Added: trunk/src/foiegras/buffer/editor.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/editor.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import gtk,gtk.gdk
+import MallardBuffer,MallardTextView
+
+class TextInterface:
+    """Main class"""
+
+    def delete_event(self, widget, event, data=None):
+        """
+        called when a window close operation is called
+        """
+        return False
+        
+    def destroy(self, widget, data=None):    
+        """
+        The close function for the class
+        """
+        gtk.main_quit()
+        
+    def menuitem_response(self, widget):
+
+        if self.buffer2.get_parser().show_tags is True:
+            self.tag_item.set_name("Hide tags")
+            self.buffer2.read_page(show_tags=False)
+            self.window.queue_draw()    
+     
+        else:
+            self.tag_item.set_name("Show tags")
+            self.buffer2.get_parser().set_show_tags(True)
+            self.buffer2.read_page(show_tags=True)            
+            self.window.queue_draw()
+
+    def testing(self,text_view,step_size, count, extend_selection):
+        print count
+                
+    def __init__(self):
+        """
+        Constructs the Window
+        """    
+        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+        self.window.connect("delete_event", self.delete_event)
+        self.window.connect("destroy", self.destroy)        
+        self.window.set_title("FoieGras-Free your mind")
+       
+#         try:
+#             self.window.set_icon_from_file("../resources/gnome.png")
+#         except:
+#             pass
+            
+        self.window.set_border_width(1)
+        self.window.set_resizable(True)
+        self.window.set_position( gtk.WIN_POS_CENTER )
+        self.window.set_default_size( 800,500 )
+
+        #menu items
+        self.file_menu = gtk.Menu()
+        
+        self.tag_item = gtk.MenuItem("Show tags")
+        self.tag_item.connect("activate",self.menuitem_response)
+        self.file_menu.append(self.tag_item)
+        self.tag_item.show()
+        
+        self.file_root = gtk.MenuItem("Options")
+        self.file_root.set_submenu(self.file_menu)
+        self.file_root.show()
+        
+        self.menu_bar = gtk.MenuBar()
+        self.menu_bar.append(self.file_root)
+        self.menu_bar.show()
+        
+        #vpanned object to hold 2 text views
+        self.vpanned = gtk.VPaned()
+        self.vpanned.set_border_width(10)
+        self.vpanned.set_position(250)
+        self.vpanned.show()
+        
+        self.vbox = gtk.VBox()
+        self.vbox.show()
+        self.vbox.pack_start(self.menu_bar, False, False, 2)        
+        self.vbox.pack_end(self.vpanned, True, True, 2)
+        self.window.add(self.vbox)   
+      
+        #Top textview
+        self.textView1 = MallardTextView.MallardTextView(buffer=None)
+        self.textView1.set_wrap_mode(gtk.WRAP_WORD)
+        self.sw1 = gtk.ScrolledWindow()
+        self.sw1.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self.sw1.add( self.textView1 )
+        self.vpanned.add1(self.sw1 )
+        self.textView1.show()
+        self.sw1.show()
+
+        #bottom textview
+        self.textView2 = MallardTextView.MallardTextView(buffer=None)
+        self.textView2.set_wrap_mode(gtk.WRAP_WORD)  
+        self.sw2 = gtk.ScrolledWindow()
+        self.sw2.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self.sw2.add(self.textView2)        
+        self.vpanned.add2(self.sw2)
+        self.textView2.show()
+        self.sw2.show()
+
+        #setting derived buffer as the buffer for textview
+        self.buffer1,self.buffer2 = MallardBuffer.MallardBuffer(self.textView2), MallardBuffer.MallardBuffer(self.textView1)
+        
+        self.textView1.set_buffer(self.buffer2)
+        self.textView1.set_size_request(800,250)
+        self.textView1.realize()
+        self.textView2.set_buffer(self.buffer1)   
+        self.textView2.set_size_request(800,250)        
+        self.textView2.realize()           
+        self.printTags()
+        
+
+        self.textView1.connect("move-cursor", self.testing )
+        self.buffer2.read_page(show_tags=False) 
+        self.window.show_all()        
+
+    def printTags(self):
+        """
+        demostrating inline tags
+        """
+        self.buffer1.set_text("")
+        iter1 = self.buffer1.get_iter_at_offset(0)
+        self.buffer1.insert_with_tags_by_name(iter1,"this is an em ", self.buffer1.tag_details["em"]["tag"])
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a link ", self.buffer1.tag_details["link"]["tag"])        
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a code snippet ", self.buffer1.tag_details["code"]["tag"])
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is an app ",self.buffer1.tag_details["app"]["tag"] )  
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a cmd ", self.buffer1.tag_details["cmd"]["tag"])
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a var ", self.buffer1.tag_details["var"]["tag"]) 
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a file ", self.buffer1.tag_details["file"]["tag"]) 
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a gui label ", self.buffer1.tag_details["gui"]["tag"]) 
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is an input ", self.buffer1.tag_details["input"]["tag"])
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a key ", self.buffer1.tag_details["key"]["tag"])  
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a media ", self.buffer1.tag_details["media"]["tag"])
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is an output ", self.buffer1.tag_details["output"]["tag"]) 
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a quote ", self.buffer1.tag_details["quote"]["tag"]) 
+        self.buffer1.insert_with_tags_by_name(iter1,"\nthis is a sys\n ", self.buffer1.tag_details["sys"]["tag"]) 
+
+    def main(self):
+        gtk.main()
+        
+if __name__ == "__main__":
+    textInterface = TextInterface()
+    textInterface.main() 

Added: trunk/src/foiegras/buffer/inline_handler.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/inline_handler.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import xmlparser
+
+def handler(parser, element, attrs, tag_start, tag = None):
+    """
+    Hanlder for inline tags.
+    controles how each block tag should render. Should be called from xmlparser
+    """  
+    iter1 =  parser.temp_buffer.get_end_iter()  
+    
+    if tag_start:    
+        #shows the tag if show_tags is true
+        if parser.show_tags:
+            parser.temp_buffer.insert_with_tags_by_name(iter1,"<"+tag+">", parser.main_buffer.tag_details["mal_tag"]["tag"] )
+            
+    else:
+        if parser.show_tags:            
+            parser.temp_buffer.insert_with_tags_by_name(iter1,"</"+element+">", parser.main_buffer.tag_details["mal_tag"]["tag"] )

Added: trunk/src/foiegras/buffer/mallard.png
==============================================================================
Binary file. No diff available.

Added: trunk/src/foiegras/buffer/table.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/table.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import sys, os, errno
+import gtk,table
+
+
+class MallardTable(gtk.TextTagTable):
+    """
+    The main buffer for text editor
+    """
+        
+    def __init__(self):
+        gtk.TextTagTable.__init__(self)
+        #print 'testing'
+        
+    def addTags(self,attrbs = dict() ):
+        """
+        Creates a new tag and adds it to the TextTagTable
+        """    
+        attrbs = set(attrbs)
+        tag = gtk.TextTag()
+        
+        if type(attrbs).__name__ == 'dict':
+            for key,val in attrbs.iteritems():
+                tag.key = val
+        
+        self.add(tag) 
+        
+    def getTable(self):
+        return self
+        
+    
+        
+        
+            
+                
+           
+            
+        

Added: trunk/src/foiegras/buffer/table_handler.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/table_handler.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import gtk,textview
+
+def handler(parser, element, attrs, tag_start, tag = None):
+    """
+    Handler for table related tags.
+    This will decide how table, tr, td, thead, tbody tags 
+    will be displayed.
+    """     
+    #choose the current focused text view
+    if parser.main_buffer.inner_textviews:
+        current_textview = parser.main_buffer.inner_textviews[len(parser.main_buffer.inner_textviews)-1]
+    else:
+        current_textview = parser.main_buffer.main_textview
+               
+    #when tag is starting  
+    if tag_start is True:     
+        #when a table tag is found
+        #start counting the columns        
+        if element == "table":
+            parser.table_status = parser.table_cons["TABLE_DEFINED"]
+        elif element == "tr":
+            parser.last_row = []
+            parser.num_columns = 0            
+        
+    #if tag is closing
+    else:
+        #handling tr tag
+        if element == "tr":         
+            #if table tag is found earlier and tr is found    
+            if parser.table_status ==  parser.table_cons["TABLE_DEFINED"]:
+                #create a list store for each of column in str type
+                liststore = gtk.ListStore(*[str for x in range(parser.num_columns)])
+                liststore.append(parser.last_row)
+                #create a treeview from list store
+                parser.current_table = gtk.TreeView(liststore) 
+                parser.current_table.set_headers_visible(False)
+                parser.current_table.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
+                parser.current_table.set_border_width(4)
+    
+                # create the TreeViewColumns to display the data
+                columns = [gtk.TreeViewColumn() for x in range(parser.num_columns)]
+                # create a list of cellrenders
+                cell_renders = [gtk.CellRendererText() for x in range(parser.num_columns)]
+                # add columns to treeview
+                # add cells to columns
+                # set the cell attributes to the appropriate liststore column
+                for x in range(parser.num_columns):
+                    parser.current_table.append_column(columns[x])
+                    columns[x].pack_start(cell_renders[x],True)
+                    columns[x].set_attributes(cell_renders[x],text=x)
+                    
+                #get the text iter to position a new textview
+                iter = parser.temp_buffer.get_end_iter()            
+                anchor  = parser.temp_buffer.create_child_anchor(iter)
+                current_textview.add_child_at_anchor(parser.current_table,anchor)
+                parser.current_table.show_all()
+                              
+                parser.table_status = parser.table_cons["TABLE_DRAWN"]  
+            #if table is drawn, add each row as table processes
+            elif parser.table_status ==  parser.table_cons["TABLE_DRAWN"]:          
+                #append data to the list store to create a new row           
+                parser.current_table.get_model().append(parser.last_row) 
+        #increase the number of columns by 1 when td tag closed               
+        elif element == "td":
+            parser.num_columns += 1               
+        #close table tag and status of table
+        elif element == "table":
+            parser.table_status = parser.table_cons["NO_TABLE"]    
+            width,height =  parser.current_table.size_request()
+            parser.temp_block_height += height
+                  
\ No newline at end of file

Added: trunk/src/foiegras/buffer/tagparser.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/tagparser.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,74 @@
+import pygtk
+pygtk.require('2.0')
+import gtk,sys
+import xml.parsers.expat, pango
+
+
+class TagParser:
+    """
+    Tag parser for FoieGras
+        
+    Reads tags from a external config file
+    and inserts them to the Text Tag Table
+    """
+    # 3 handler functions
+    def start_element(self,name,attrs):
+        """whan a tag start occurse parser callse this handler"""
+        if name == "tag":      
+            #keep track of the parent tag
+            self.tags_stack.append(attrs["name"])  
+            #keep track of last attribut passed
+            #for the use of char_data function 
+            self.last_attrib = None    
+            #keep track of attribute list 
+            #for a parent tag
+            self.attr_list = {}                    
+        else:
+            self.last_attrib = name.strip()                             
+            #avoide duplicates       
+        if "name" in attrs and attrs["name"] not in self.buffer.tag_details:
+            name = attrs["name"]
+            self.buffer.tag_details[name] = attrs
+            if attrs["type"] != "special":
+                styles = eval( "dict(" + self.buffer.tag_details[name]["style"] + ")" )
+            else:
+                styles = {}
+            #creates a tag in text_tag_table of the buffer
+            self.buffer.create_tag("tag"+ str(self.tag_count),**styles )
+            #put the name of the tag in dict
+            self.buffer.tag_details[name]["tag"]= "tag"+ str(self.tag_count)
+            self.tag_count += 1          
+
+    def char_data(self,data):
+        if self.last_attrib != None and data.strip() != "":
+            self.attr_list[self.last_attrib] = data
+   
+    def end_element(self,name):
+        if name == "tag":
+            try:
+                tag = self.tags_stack.pop()   
+                self.buffer.tag_details[tag]["attribs"] = self.attr_list
+            except Exception,msg:
+                print msg
+                exit()
+
+    def __init__(self,buffer,page):
+        self.tag_count = 0;
+        self.buffer = buffer    
+        #track tag attributes
+        self.attr_list = {}
+        self.tags_stack = []          
+        self.last_attrib = None      
+        #creating a xmlparser
+        p = xml.parsers.expat.ParserCreate()
+        p.StartElementHandler = self.start_element
+        p.CharacterDataHandler = self.char_data  
+        p.EndElementHandler = self.end_element              
+                
+        if buffer.__class__.__name__ == "MallardBuffer" :
+            try:
+                p.Parse( page )
+            except xml.parsers.expat.ExpatError,msg:
+                print "Foiegras Error: ",msg
+                exit()
+            

Added: trunk/src/foiegras/buffer/testing.xml
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/testing.xml	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,72 @@
+<page id="el-synopsis">
+<info>
+  <anchor id="mal_block_synopsis"><title>mal_block_synopsis</title></anchor>
+  <link type="embed" xref="set-block"/>
+</info>
+
+<title>Synopses</title>
+
+<synopsis><code>mal_block_synopsis =
+element synopsis {
+  mal_attr_common,
+  <link xref="mal_block_title"/>?
+  (
+    <link xref="mal_block_code"/>,
+    <link xref="mal_block_p"/>
+  )+
+}</code></synopsis>
+
+<figure>
+  <media type="image" mime="image/png" href="mallard.png"/>
+  <caption>Drake, the Mallard mascot</caption>
+</figure>
+
+<table frame="all" rules="rows">
+  <tr>
+    <td>GNOME 2.6</td>
+    <td>2004-03-15</td>
+    <td>Development</td>
+    <td>Release Notes</td>
+  </tr>
+  <tr>
+    <td>GNOME 2.8</td>
+    <td>2004-09-15</td>
+    <td>Development</td>
+    <td>Release Notes</td>
+  </tr>
+  <tr>
+    <td>GNOME 2.10</td>
+    <td>2005-03-09</td>
+    <td>Development</td>
+    <td>Release Notes</td>
+  </tr>
+</table>
+
+<p>The <code>synopsis</code> element allows you to mark up a block as
+providing an overview of the material being presented.  It is useful
+for providing a listing functions, commands, or options in reference
+material, or for enumerating the items in a menu or other graphical
+control element.</p>
+
+<comment>
+  <cite><name>Shaun McCance</name><date>2006-11-16</date></cite>
+  <p>Add explanation, examples</p>
+</comment>
+
+<section>
+  <title>Processing Expectations</title>
+
+  <p>A <code>synopsis</code> element should be rendered as a displayed
+  block, with each of its child elements interpreted as block elements.
+  Since a <code>synopsis</code> element often contains large blocks,
+  and is generally offset from the running text, processing tools may
+  opt to render it inside a colored or screened box, with a border, or
+  otherwise differently from the surrounding text.</p>
+
+  <p>If a <code xref="mal_block_title">title</code> element is provided,
+  it should appear at the top of the block and be clearly marked as the
+  title using font variations or other stylistic means.</p>
+
+</section>
+
+</page>

Added: trunk/src/foiegras/buffer/xmlparser.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/buffer/xmlparser.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#Gome doc project - Mallard - FoieGras
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import xml.parsers.expat
+import block_handler, inline_handler, table_handler, attribute_handler
+
+
+class Parser:
+    """
+    XML parser for FoieGras
+        
+    Known tags are noted in orange
+    unknown tags are noted in green
+    """
+    #keeps the current loaded tags(eg: tag0, tag1, ...) and elements(eg: em, code,..)
+    tag_stack, elements = [], []
+    show_tags = False
+    temp_block_height = 0
+    #table variables
+    current_table = None #keeps track of the current table
+    ##Table constraints
+    #NO_TABLE = No table tag is found
+    #TABLE_FOUND = Table tag is found and collecting info about the table to draw the table
+    #TABLE_DRAWN = Table tag is closed and table is fully drawn
+    table_cons = {"NO_TABLE":0, "TABLE_DEFINED":1, "TABLE_DRAWN":2} #table constraints
+    table_status = table_cons["NO_TABLE"] #table status when parsing the document
+    num_columns = 0;
+    last_row = []
+    
+    def set_show_tags(self, state):
+        self.show_tags = state
+            
+    def get_show_tags(self):
+        return self.show_tags  
+
+    def special_handler(self, element,attrs,tag_start,tag = None):
+        if element == "info":
+            pass
+
+        if element == "title" and tag_start == True and    \
+        self.title == "":
+            self.title_parsing = True
+        if element == "title" and tag_start == False:
+            self.title_parsing = False
+
+        
+    
+    def start_element(self, name, attrs):
+        """
+        whan a tag start occurse parser callse this handler
+        """
+        #create sentence using tag+attribute
+        tag = name
+        if len(attrs) != 0 :
+            for k, v in attrs.iteritems():
+                tag += " " + k + " = \" " +  v + "\" "
+        #if parsed tag is in the valid tag list (for known tags)
+        if name in self.main_buffer.tag_details.keys(): 
+            #add parsed tag to tag stack
+            #at a given moment tag stack holds the tags until the current tag         
+            self.tag_stack.append(self.main_buffer.tag_details[name]["tag"])
+            self.elements.append(name)         
+            #handling control according to the tag's statues-block or inline
+            if self.main_buffer.tag_details[name]["type"] == "table":
+                table_handler.handler(self, name, attrs, True, tag)       
+            elif self.main_buffer.tag_details[name]["type"] == "block":
+                block_handler.handler(self, name, attrs, True, tag)
+            elif self.main_buffer.tag_details[name]["type"] == "inline":
+                inline_handler.handler(self, name, attrs, True, tag)  
+            elif self.main_buffer.tag_details[name]["type"] == "special":
+                self.special_handler(name, attrs, True, tag)
+
+
+            #choose the current focused text view
+            if self.main_buffer.inner_textviews:
+                current_textview = self.main_buffer.inner_textviews[len(self.main_buffer.inner_textviews)-1]
+            else:
+                current_textview = self.main_buffer.main_textview        
+            
+            #validate tag attributes
+            try:
+                #check validity of attributes
+                attribute_handler.attribute_handler(name, self.temp_buffer, self.main_buffer.tag_details[name]["attribs"], attrs, current_textview)                
+            except KeyError, msg:
+                #occur in an invalid key exception
+                print "No such tag as", msg
+                exit()
+            except attribute_handler.InvlidAttribute, msg:
+                #occur in invalid value exception
+                print msg
+                exit()                     
+            except Exception, msg:
+                print "Error:", msg
+                exit()                      
+        #for unknown tags
+        else:
+            print "Additional"
+            iter1 =  self.temp_buffer.get_end_iter()               
+            self.temp_buffer.insert_with_tags_by_name(iter1, "<"+tag+">", self.main_buffer.tag_details["tag"]["tag"])
+            
+    def end_element(self, name):
+        """
+        when a tag end occurs parser calls this handler    
+        """
+        if name in self.main_buffer.tag_details.keys() and len(self.tag_stack) != 0 : 
+            self.tag_stack.pop()   
+            previous_element = self.elements.pop()
+            
+            if self.main_buffer.tag_details[name]["type"] == "table":
+                table_handler.handler(self, name, None , False)            
+            elif self.main_buffer.tag_details[name]["type"] == "block":
+                block_handler.handler(self, name, None, False)
+            elif self.main_buffer.tag_details[name]["type"] == "inline":
+                inline_handler.handler(self, name, None, False)   
+            elif self.main_buffer.tag_details[name]["type"] == "special":
+                self.special_handler(name, None, False)
+        else:
+            iter1 =  self.temp_buffer.get_end_iter()                  
+            self.temp_buffer.insert_with_tags_by_name(iter1, "</"+name+">", self.main_buffer.tag_details["tag"]["tag"])    
+    
+    def char_data(self, data):
+        """
+        when a character text occurs parser callse this handler
+        """
+        if self.title_parsing:
+            self.title += data
+        if self.table_status == self.table_cons["NO_TABLE"]:  
+            iter1 =  self.temp_buffer.get_end_iter()                          
+            self.temp_buffer.insert_with_tags_by_name(iter1, data, *self.tag_stack)
+        else:
+            #if a new column comes, append the column data to the array
+            #which will be later added to the liststore of the table
+            if self.last_row.__len__() < 4 and data.strip() != "":
+                self.last_row.append( data )               
+
+    
+    def __init__(self, buffer, show_tags= False):
+
+        self.set_show_tags(show_tags)
+
+        self.title_parsing = False
+        self.title = ""
+        
+        p = xml.parsers.expat.ParserCreate()
+        p.StartElementHandler = self.start_element
+        p.EndElementHandler = self.end_element
+        p.CharacterDataHandler = self.char_data
+
+        if buffer.__class__.__name__ == "MallardBuffer" :
+            #main_buffer is the outmost textbuffer and the
+            #buffer of main textview.
+            #temp_buffer keeps current focused inner text buffer 
+            self.temp_buffer = self.main_buffer = buffer
+            self.x, self.y = 400, 10
+            #read the text in buffer
+            iter1, iter2 = self.main_buffer.get_bounds()
+            page = self.main_buffer.get_text(iter1, iter2)
+
+            #format the buffer
+            self.main_buffer.set_text("") 
+            #self.set_show_tags(False)
+            try:
+                p.Parse(page)
+            except xml.parsers.expat.ExpatError, msg:
+                print "Foiegras Error: ", msg
+                exit()                
+
+        print "Title: "+str(self.title)

Added: trunk/src/foiegras/document.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/document.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,140 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 foiegras.buffer
+from foiegras.buffer import MallardBuffer
+from foiegras.buffer import textview
+
+
+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._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. """
+        self._changed = True
+    
+    def apply_patch(self, patch_file):
+        """ Applies a patch to the current document - useful for the review mode. """
+        pass
+    
+    def get_buffer(self):
+        """ Returns the TextBuffer. """
+        return self._buffer
+    
+    def get_changed(self):
+        """ Returns True if the text has changed. """
+        return self._changed
+    
+    def get_filename(self):
+        """ Returns the filename of the document. """
+        return self._filename
+    
+    def get_content(self):
+        """ Return 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 self._view
+    
+    def open(filename):
+        """ 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. """
+        if self._filename is not None:
+            f = file(self._filename, 'w')
+            (start, end) = self._buffer.get_bounds()
+            f.write(self._buffer.get_text(start, end))
+            f.close()
+            self._changed = False
+        else:
+            print "DEBUG: no filename specified, really shouldn't happen."
+    
+    def set_filename(self, filename):
+        """ Specify the document's filename. """
+        self._filename = filename
+
+
+class TranslateDocument(Document):
+    """
+    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. """
+        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. """
+        # 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. """
+        pass

Added: trunk/src/foiegras/errors.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/errors.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,37 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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
+
+class FoieGrasException(Exception):
+    def __init__(self, value=None):
+        self.value = value
+    def __str__(self):
+        return repr(self.value)
+
+
+class UnknownError(FoieGrasException):
+    pass
+
+
+class NoChanges(FoieGrasException):
+    pass
+
+
+class NoWorkingTree(FoieGrasException):
+    pass
+
+
+class NoSuchFile(FoieGrasException):
+    pass

Added: trunk/src/foiegras/preferences.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/preferences.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,174 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os.path
+
+import gconf
+
+GCONF_ROOT = '/apps/foiegras/'
+
+class FoieGrasPreferencesGconf:
+    """ Class that implements the Gconf backend for Foie Gras. """
+    def __init__(self):
+        """ Initialize the Gconf backend. """
+        # Get the default client instance
+        self._client = gconf.client_get_default()
+        # Add the main directory for Foie Gras
+        self._client.add_dir(GCONF_ROOT[:-1], gconf.CLIENT_PRELOAD_NONE)
+    
+    def add_notify(self, key, callback):
+        """
+        Sets up a notification callback.
+        """
+        keypath = GCONF_ROOT + key
+        self._client.notify_add(keypath, callback)
+    
+    def add_vcs_profile(self, data):
+        """
+        Add a new VCS profile.
+        
+        The data is a dictionary with the following format:
+        id:       the ID of the profile
+        name:     human readable name of the profile
+        type:     type of the VCS (supported: bazaar, subversion)
+        uri:      repository location (local or remote, full path)
+        readonly: true if repository is read-only
+        
+        Return True if successfully added, otherwise return False.
+        
+        Note: you can use this method to modify VCS profiles (just specify an
+        existing ID).
+        """
+        try:
+            keypath = GCONF_ROOT + 'vcsprofiles/' + data['id'] + '/'
+        except KeyError:
+            return False
+        
+        try:
+            self._client.set_string(keypath + 'name', data['name'])
+            self._client.set_string(keypath + 'type', data['type'])
+            self._client.set_string(keypath + 'uri', data['uri'])
+            self._client.set_bool(keypath + 'readonly', data['readonly'])
+        except KeyError:
+            return False
+        
+        return True
+    
+    def exists_vcs_profile(self, id):
+        """
+        Checks whether a VCS profile exists with the given ID.
+        
+        Returns True or False.
+        """
+        keypath = GCONF_ROOT + 'vcsprofiles/' + id
+        
+        val = self._client.get_string(keypath + '/name')
+        if val is None:
+            # We assume that there is no such profile
+            return False
+        else:
+            return True
+    
+    def get_preference(self, key, type, default):
+        """
+        Return the value of the given key, or the default, if not specified.
+        
+        Types supported: bool, int, string
+        """
+        val = None
+        keypath = GCONF_ROOT + key
+        
+        if type == 'bool':
+            val = self._client.get_bool(keypath)
+        elif type == 'int':
+            val = self._client.get_int(keypath)
+            if val == 0:
+                val = default
+                self._client.set_int(keypath, val)
+        elif type == 'string':
+            val = self._client.get_string(keypath)
+            if val is None:
+                val = default
+                self._client.set_string(keypath, val)
+        
+        return val
+    
+    def get_vcs_profile(self, id):
+        """
+        Return the preferences of the given VCS profile as a directory.
+        """
+        keypath = GCONF_ROOT + 'vcsprofiles/' + id
+        data = {}
+        
+        val = self._client.get_string(keypath + '/name')
+        if val is None:
+            # We assume that there is no such profile
+            return None
+        else:
+            data['id'] = id
+            data['name'] = val
+            data['type'] = self._client.get_string(keypath + '/type')
+            data['uri'] = self._client.get_string(keypath + '/uri')
+            data['readonly'] = self._client.get_bool(keypath + '/readonly')
+            return data
+    
+    def get_vcs_profiles(self):
+        """
+        Return the list of VCS profiles as a list of directories.
+        """
+        keypath = GCONF_ROOT + 'vcsprofiles'
+        profiles = []
+        
+        for id in self._client.all_dirs(keypath):
+            # We need the final part only
+            id = os.path.basename(id)
+            # Fill up with data
+            data = { 'id': id }
+            data['name'] = self._client.get_string(keypath + '/' + id + '/name')
+            data['type'] = self._client.get_string(keypath + '/' + id + '/type')
+            data['uri'] = self._client.get_string(keypath + '/' + id + '/uri')
+            data['readonly'] = self._client.get_bool(keypath + '/' + id + '/treadonly')
+            # Add to the profile list
+            profiles.append(data)
+        
+        return profiles
+    
+    def remove_vcs_profile(self, id):
+        """
+        Remove the VCS profile with the given ID.
+        """
+        keypath = GCONF_ROOT + 'vcsprofiles/' + id + '/'
+        
+        self._client.unset(keypath + 'name')
+        self._client.unset(keypath + 'type')
+        self._client.unset(keypath + 'uri')
+        self._client.unset(keypath + 'readonly')
+        self._client.unset(keypath[:-1])
+    
+    def set_preference(self, key, type, value):
+        """
+        Set the value for the given key.
+        
+        Types supported: bool, int, string
+        """
+        keypath = GCONF_ROOT + key
+        
+        if type == 'bool':
+            self._client.set_bool(keypath, value)
+        elif type == 'int':
+            self._client.set_int(keypath, value)
+        elif type == 'string':
+            self._client.set_string(keypath, value)

Added: trunk/src/foiegras/vcs/__init__.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/vcs/__init__.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,67 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os.path
+
+from difflib import unified_diff
+from tempfile import mkstemp
+
+# List of supported VCSs (module names)
+FOIE_GRAS_VCS_TYPES = [ 'bazaar', 'subversion' ]
+
+class VersionControl:
+    """ Abstract class for version control backends. """
+    def __init__(self):
+        """ Constructor for the abstract class. """
+        self._url = None
+    
+    def commit(self, path, message):
+        """ Commit the changes to the repository. """
+        raise NotImplementedError
+    
+    def create_diff(self, original, modified, filename):
+        """
+        Generates a diff between the original and the modified file. Both have
+        to be absolute paths.
+        
+        Returns the path to a temporary file containing the diff.
+        """
+        # Get the diff generator
+        olines = open(original, 'r').readlines()
+        mlines = open(modified, 'r').readlines()
+        diff = unified_diff(olines,
+                            mlines,
+                            filename,
+                            filename)
+        # Create temporary file
+        (handler, fullpath) = mkstemp(prefix='foiegras-diff-', text=True)
+        # Write contents into the file
+        f = file(fullpath, 'w')
+        f.writelines(diff)
+        f.close()
+        # Return the path to the temporary file
+        return fullpath
+    
+    def get_file(self, path):
+        """
+        Return the path to a temporary file on the local disk that has content
+        identical to the one in the repository.
+        """
+        raise NotImplementedError
+    
+    def set_url(self, url):
+        """ Set repository URL. """
+        self._url = url

Added: trunk/src/foiegras/vcs/bazaar.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/vcs/bazaar.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,109 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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
+
+from tempfile import mkstemp
+
+from bzrlib.branch import Branch
+from bzrlib.errors import PointlessCommit
+from bzrlib.workingtree import WorkingTree
+
+from foiegras.errors import (NoChanges,
+                             NoSuchFile,
+                             NoWorkingTree,
+                             UnknownError)
+from foiegras.vcs import VersionControl
+
+class BazaarBackend(VersionControl):
+    """ Bazaar VCS backend for Foie Gras. """
+    def __init__(self):
+        """ Constructor for the Bazaar backend. """
+        VersionControl.__init__(self)
+        self._branch = None
+    
+    def commit(self, path, message):
+        """
+        Commit the given file (path - relative path inside th repository) to the
+        Bazaar branch.
+        
+        Return True if the commit was successful, or the respective error code.
+        """
+        if self._branch is not None:
+            rt = self._branch.repository.revision_tree(self._branch.last_revision())
+            id = rt.path2id(path)
+            if id is None:
+                raise NoSuchFile(path)
+            
+            try:
+                wt = WorkingTree.open(self._url)
+            except:
+                raise NoWorkingTree(self._url)
+            
+            try:
+                wt.commit(message,
+                          allow_pointless=False,
+                          strict=False,
+                          local=False,
+                          specific_files=[path])
+                return True
+            except PointlessCommit:
+                raise NoChanges()
+            except:
+                raise UnknownError()
+        
+        # There is no branch at all
+        raise NoWorkingTree(self._url)
+    
+    def get_file(self, path):
+        """
+        Return a tuple containing the path to a temporary file on the local disk
+        that has content identical to the one in the repository, and the
+        original filename.
+        
+        Parameter 'path' has to be a relative path inside the repository.
+        
+        Return None for both if file was not found.
+        """
+        if self._branch is not None:
+            rt = self._branch.repository.revision_tree(self._branch.last_revision())
+            id = rt.path2id(path)
+            if id is not None:
+                # Valid file id
+                content = rt.get_file_text(id)
+                # Create temporary file
+                (handler, fullpath) = mkstemp(prefix='foiegras-', text=True)
+                # Write contents into the file
+                f = file(fullpath, 'w')
+                f.write(content)
+                f.close()
+                # Get the original filename
+                filename = None
+                for item in self._branch.repository.get_inventory(self._branch.last_revision()).entries():
+                    if item[0] == path:
+                        filename = item[1].name
+                        break
+                # Return the path to the temporary file
+                return (fullpath, filename)
+        
+        # We didn't succeed
+        return (None, None)
+    
+    def set_url(self, url):
+        """ Set branch URL, and get the Branch object. """
+        self._url = url
+        try:
+            self._branch = Branch.open(url)
+        except:
+            self._branch = None

Added: trunk/src/foiegras/vcs/subversion.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/vcs/subversion.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,80 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os.path
+
+from tempfile import mkstemp
+
+import pysvn
+
+from foiegras.errors import NoWorkingTree
+from foiegras.vcs import VersionControl
+
+class SubversionBackend(VersionControl):
+    """ Subversion VCS backend for Foie Gras. """
+    def __init__(self):
+        """ Constructor for the Bazaar backend. """
+        VersionControl.__init__(self)
+        
+        self._client = pysvn.Client()
+    
+    def commit(self, path, message):
+        """
+        Commit the given file (path - relative path inside th repository) to the
+        Subversion repository.
+        
+        Return True if the commit was successful
+        """
+        if self._url is not None:
+            revision = self._client.checkin([self._url + path], message)
+            print "DEBUG: revision =", revision
+            return True
+        
+        # There is no branch at all
+        raise NoWorkingTree(self._url)
+    
+    def get_file(self, path):
+        """
+        Return a tuple containing the path to a temporary file on the local disk
+        that has content identical to the one in the repository, and the
+        original filename.
+        
+        Parameter 'path' has to be a relative path inside the repository.
+        
+        Return None for both if file was not found.
+        """
+        if self._url is not None:
+            content = self._client.cat(self._url + path)
+            # Create temporary file
+            (handler, fullpath) = mkstemp(prefix='foiegras-', text=True)
+            # Write contents into the file
+            f = file(fullpath, 'w')
+            f.write(content)
+            f.close()
+            # Get the original filename
+            filename = os.path.basename(self._url + path)
+            # Return the path to the temporary file
+            return (fullpath, filename)
+        
+        # We didn't succeed
+        return (None, None)
+    
+    def set_url(self, url):
+        """ Set branch URL, and get the Branch object. """
+        if not url.endswith('/'):
+            self._url = url + '/'
+        else:
+            self._url = url

Added: trunk/src/foiegras/windows/__init__.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/windows/__init__.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,16 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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
+

Added: trunk/src/foiegras/windows/commit.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/windows/commit.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,154 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os
+
+import pygtk
+pygtk.require('2.0')
+import gobject
+import gtk
+import gtk.glade
+
+from foiegras.errors import (NoChanges,
+                             NoSuchFile,
+                             NoWorkingTree,
+                             UnknownError)
+from foiegras.windows.dialog import error_dialog
+
+def _(str):
+    """ Dummy gettext replacement. """
+    return str
+
+class CommitDialog:
+    """ A wrapper class around the Commit dialog. """
+    
+    def __init__(self, app):
+        """ Constructor for the CreatePatchDialog. """
+        self._app = app
+        self._conf = self._app.get_conf()
+        
+        gladefile = self._app.get_datadir() + os.sep + 'commit.glade'
+        self._glade = gtk.glade.XML(gladefile, 'dialog_commit', 'foiegras')
+        
+        signals = { 'on_button_cancel_clicked': self.close,
+                    'on_button_commit_clicked': self.commit }
+        
+        self._glade.signal_autoconnect(signals)
+        
+        self._window = self._glade.get_widget('dialog_commit')
+        self._combo_profiles = self._glade.get_widget('combobox_vcsprofile')
+        self._entry_relpath = self._glade.get_widget('entry_relpath')
+        self._textview = self._glade.get_widget('textview_message')
+        
+        cell = gtk.CellRendererText()
+        self._combo_profiles.pack_start(cell, True)
+        self._combo_profiles.add_attribute(cell, 'text', 1)
+        
+        fn = self._app.get_document().get_filename()
+        if fn is not None:
+            self._entry_relpath.set_text(os.path.basename(fn))
+    
+    def _get_active_profile(self):
+        """ Return the ID of the selected profile or None, if nothing selected. """
+        model = self._combo_profiles.get_model()
+        active = self._combo_profiles.get_active()
+        if active < 0:
+            return None
+        return model[active][0]
+    
+    def _load_profiles(self):
+        """ This method creates an appropriate ListStore and loads the Version
+        Control profiles into it. """
+        # model = [ id, name ]
+        self._model_vcs = gtk.ListStore(gobject.TYPE_STRING,
+                                        gobject.TYPE_STRING)
+        
+        # Set the model
+        self._combo_profiles.set_model(self._model_vcs)
+        
+        # Retrieve profiles
+        profiles = self._conf.get_vcs_profiles()
+        
+        # Fill up the ListStore
+        for p in profiles:
+            if p['name'] is not None:
+                self._model_vcs.append([ p['id'], p['name'] ])
+            while gtk.events_pending():
+                gtk.main_iteration()
+    
+    def close(self, widget=None):
+        """ Close button clicked handler. """
+        self._window.destroy()
+    
+    def commit(self, widget):
+        """ Commit button clicked handler. """
+        if self._get_active_profile() is None:
+            error_dialog(_("No Version Control profile selected"),
+                         _("Please select a Version Control profile."))
+            return
+        if len(self._entry_relpath.get_text()) == 0:
+            error_dialog(_("Missing relative path"),
+                         _("Please specify the relative path to the original file in the repository."))
+            return
+        
+        (start, end) = self._textview.get_buffer().get_bounds()
+        message = self._textview.get_buffer().get_text(start, end)
+        if len(message.strip()) == 0:
+            error_dialog(_("Missing message"),
+                         _("Please specify a commit message."))
+            return
+        
+        data = self._conf.get_vcs_profile(self._get_active_profile())
+        
+        if data['readonly']:
+            error_dialog(_("Read-only repository"),
+                         _("You cannot commit to a read-only repository."))
+            return
+        
+        if data['type'] == 'bazaar':
+            from foiegras.vcs.bazaar import BazaarBackend
+            vcs = BazaarBackend()
+        elif data['type'] == 'subversion':
+            from foiegras.vcs.subversion import SubversionBackend
+            vcs = SubversionBackend()
+        
+        vcs.set_url(data['uri'])
+        try:
+            vcs.commit(self._entry_relpath.get_text(), message)
+        except NoWorkingTree, e:
+            error_dialog(_("Commit failed"),
+                         _("No working tree found at the location:") + ' ' + e.value)
+            return
+        except NoSuchFile, e:
+            error_dialog(_("Commit failed"),
+                         _("There is no such file in the repository:") + ' ' + e.value)
+            return
+        except NoChanges:
+            error_dialog(_("Commit failed"),
+                         _("There were no changes made to any file."))
+            return
+        except:
+            error_dialog(_("Commit failed"),
+                         _("An unknown error has occured."))
+            return
+        
+        self.close()
+    
+    def show(self):
+        """ Show all contents of the dialog. """
+        self._load_profiles()
+        
+        self._window.show_all()

Added: trunk/src/foiegras/windows/dialog.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/windows/dialog.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,173 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 gtk.glade
+
+def _(str):
+    """ Dummy gettext replacement. """
+    return str
+
+def _message_dialog(type, primary, secondary, buttons=gtk.BUTTONS_OK, parent=None):
+    """
+    Display a given type of MessageDialog with the given message.
+    
+    :param type: message dialog type
+    
+    :param message: the message you want to display.
+    """
+    dialog = gtk.MessageDialog(flags=gtk.DIALOG_MODAL,
+                               type=type,
+                               buttons=buttons,
+                               parent=parent)
+    dialog.set_markup('<big><b>' + primary + '</b></big>')
+    dialog.format_secondary_markup(secondary)
+    response = dialog.run()
+    dialog.destroy()
+    return response
+
+def error_dialog(primary, secondary, parent=None):
+    """ Display an error dialog with the given message. """
+    return _message_dialog(gtk.MESSAGE_ERROR, primary, secondary, parent=parent)
+
+def info_dialog(primary, secondary, parent=None):
+    """ Display an info dialog with the given message. """
+    return _message_dialog(gtk.MESSAGE_INFO, primary, secondary, parent=parent)
+
+def warning_dialog(primary, secondary, parent=None):
+    """ Display a warning dialog with the given message. """
+    return _message_dialog(gtk.MESSAGE_WARNING, primary, secondary, parent=parent)
+
+
+class AskOverwriteDialog(gtk.Dialog):
+    """ This class implements a dialog that asks the user if s/he wants to
+    overwrite an existing file. """
+    def __init__(self, filename, parent):
+        """ Initialize the question dialog. """
+        gtk.Dialog.__init__(self,
+                            title=_("Question") + ' - Foie Gras',
+                            parent=parent,
+                            flags=gtk.DIALOG_MODAL
+                        )
+        
+        # Create the widgets
+        self._image_question = gtk.image_new_from_stock(gtk.STOCK_DIALOG_QUESTION,
+                                                        gtk.ICON_SIZE_DIALOG)
+        self._button_cancel = gtk.Button(stock=gtk.STOCK_CANCEL)
+        self._button_overwrite = gtk.Button("Overwrite")
+        self._hbox = gtk.HBox()
+        self._label_question = gtk.Label()
+        
+        # Set properties
+        self._hbox.set_spacing(5)
+        self._label_question.set_markup(_("<big><b>Do you want to overwrite the old file?</b></big>"))
+        
+        # Set callbacks
+        self._button_cancel.connect('clicked', self._cancel)
+        self._button_overwrite.connect('clicked', self._overwrite)
+        
+        # Pack widgets
+        self._hbox.pack_start(self._image_question)
+        self._hbox.pack_start(self._label_question)
+        self.vbox.add(self._hbox)
+        self.action_area.pack_start(self._button_cancel)
+        self.action_area.pack_start(self._button_overwrite)
+        
+        # Show all widgets
+        self.vbox.show_all()
+        self.action_area.show_all()
+    
+    def _cancel(self, widget):
+        """ Cancel button clicked. """
+        print "DEBUG: Cancel button clicked. """
+        self.response(gtk.RESPONSE_CANCEL)
+    
+    def _overwrite(self, widget):
+        """ Save button click handler. """
+        print "DEBUG: Overwrite button clicked."
+        self.response(gtk.RESPONSE_YES)
+
+
+class AskSaveDialog(gtk.Dialog):
+    """ This class implements a dialog that asks the user if s/he wants to save
+    the changes made to the document. """
+    def __init__(self, filename, parent):
+        """ Initialize the question dialog. """
+        gtk.Dialog.__init__(self,
+                            title=_("Question") + ' - Foie Gras',
+                            parent=parent,
+                            flags=gtk.DIALOG_MODAL
+                        )
+        
+        if filename is None:
+            filename = _("(Unsaved document)")
+        
+        # Create the widgets
+        self._image_question = gtk.image_new_from_stock(gtk.STOCK_DIALOG_QUESTION,
+                                                        gtk.ICON_SIZE_DIALOG)
+        self._button_dont = gtk.Button(_("Don't Save"))
+        self._button_cancel = gtk.Button(stock=gtk.STOCK_CANCEL)
+        self._button_save = gtk.Button(stock=gtk.STOCK_SAVE)
+        self._hbox = gtk.HBox()
+        self._vbox_question = gtk.VBox()
+        self._label_question = gtk.Label()
+        self._label_filename = gtk.Label()
+        
+        # Set properties
+        self._hbox.set_spacing(5)
+        self._hbox.set_border_width(5)
+        self._vbox_question.set_spacing(3)
+        self._label_question.set_markup(_("<big><b>Do you want to save your changes?</b></big>"))
+        self._label_question.set_alignment(0.0, 0.5)
+        self._label_filename.set_text(_("The file has been changed:\n") + filename)
+        self._label_filename.set_alignment(0.0, 0.5)
+        
+        # Set callbacks
+        self._button_cancel.connect('clicked', self._cancel)
+        self._button_dont.connect('clicked', self._dont_save)
+        self._button_save.connect('clicked', self._save)
+        
+        # Pack widgets
+        self._vbox_question.pack_start(self._label_question)
+        self._vbox_question.pack_start(self._label_filename)
+        self._hbox.pack_start(self._image_question)
+        self._hbox.pack_start(self._vbox_question)
+        self.vbox.add(self._hbox)
+        self.action_area.pack_start(self._button_dont)
+        self.action_area.pack_start(self._button_cancel)
+        self.action_area.pack_start(self._button_save)
+        
+        # Show all widgets
+        self.vbox.show_all()
+        self.action_area.show_all()
+    
+    def _cancel(self, widget):
+        """ Cancel button clicked. """
+        print "DEBUG: Cancel button clicked. """
+        self.response(gtk.RESPONSE_CANCEL)
+    
+    def _dont_save(self, widget):
+        """ Don't Save button click handler. """
+        print "DEBUG: Don't Save button clicked."
+        self.response(gtk.RESPONSE_NO)
+    
+    def _save(self, widget):
+        """ Save button click handler. """
+        print "DEBUG: Save button clicked."
+        self.response(gtk.RESPONSE_YES)

Added: trunk/src/foiegras/windows/main.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/windows/main.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,549 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os
+import os.path
+
+import pygtk
+pygtk.require('2.0')
+import gobject
+import gtk
+import gtk.glade
+
+from foiegras.document import Document
+from foiegras.windows.commit import CommitDialog
+from foiegras.windows.dialog import (AskOverwriteDialog,
+                                     AskSaveDialog,
+                                     warning_dialog)
+from foiegras.windows.preferences import PreferencesDialog
+from foiegras.windows.patch import CreatePatchDialog
+
+def _(str):
+    """ Dummy gettext replacement. """
+    return str
+
+class OpenRecentToolAction(gtk.Action):
+    __gtype_name__ = "OpenRecentToolAction"
+
+gobject.type_register(OpenRecentToolAction)
+OpenRecentToolAction.set_tool_item_type(gtk.MenuToolButton)
+
+
+class MainWindow:
+    """ This is a wrapper class around Foie Gras main window. """
+    def __init__(self, app, filename=None):
+        """
+        Constructor for the MainWindow.
+        app: a FoieGrasApplication instance
+        filename: name of the file that should be opened by default
+        """
+        self._app = app
+        self._conf = self._app.get_conf()
+        self._document = None
+        
+        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),
+            ('EditMenuAction', None, _("Edit"), None, _(""), self.dummy_action),
+            ('DocumentMenuAction', None, _("Document"), None, _(""), self.dummy_action),
+            ('BlockMenuAction', None, _("Block"), None, _(""), self.dummy_action),
+            ('InlineMenuAction', None, _("Inline"), None, _(""), self.dummy_action),
+            ('ContributeMenuAction', None, _("Contribute"), None, _(""), self.dummy_action),
+            ('HelpMenuAction', None, _("Help"), None, _(""), self.dummy_action),
+            ('NewAction', gtk.STOCK_NEW, _("New"), None, _(""), self.new_document),
+            ('OpenAction', gtk.STOCK_OPEN, _("Open"), None, _(""), self.open_document),
+            ('RecentlyUsedAction', None, _("Recently Used"), None, _(""), self.dummy_action),
+            ('SaveAction', gtk.STOCK_SAVE, _("Save"), None, _(""), self.save_document),
+            ('SaveAsAction', gtk.STOCK_SAVE_AS, _("Save As"), None, _(""), self.save_document_as),
+            ('QuitAction', gtk.STOCK_QUIT, _("Quit"), None, _(""), self.quit),
+            ('UndoAction', gtk.STOCK_UNDO, _("Undo"), None, _(""), self.dummy_action),
+            ('RedoAction', gtk.STOCK_REDO, _("Redo"), None, _(""), self.dummy_action),
+            ('CutAction', gtk.STOCK_CUT, _("Cut"), None, _(""), self.dummy_action),
+            ('CopyAction', gtk.STOCK_COPY, _("Copy"), None, _(""), self.dummy_action),
+            ('PasteAction', gtk.STOCK_PASTE, _("Paste"), None, _(""), self.dummy_action),
+            ('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._actiongroup = gtk.ActionGroup('menubar')
+        self._actiongroup.add_actions(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')
+        self.ui['toolbar'] = self.uimanager.add_ui_from_file(self._app.get_datadir() + os.sep + 'toolbar.ui')
+        self._menubar = self.uimanager.get_widget('/MainMenu')
+        self._menu_recent = self.uimanager.get_widget('/MainMenu/FileMenu/RecentlyUsed')
+        self._toolbar_main = self.uimanager.get_widget('/MainToolbar')
+        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)
+        self._toolbar_block.set_border_width(3)
+        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)
+            try:
+                l = gtk.Label(item.get_label())
+                l.set_alignment(0.0, 0.5)
+                l.set_padding(3, 0)
+                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)
+            try:
+                l = gtk.Label(item.get_label())
+                l.set_alignment(0.0, 0.5)
+                l.set_padding(3, 0)
+                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)
+        
+        # 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. """
+        if self._document.get_filename() is None:
+            title = _("(Unsaved document)")
+        else:
+            title = os.path.basename(self._document.get_filename())
+            
+        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. """
+        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. """
+        a = gtk.AboutDialog()
+        a.set_name('Foie Gras')
+        a.set_version(None)
+        a.set_copyright('Copyright (c) 2007 Szilveszter Farkas')
+        a.set_license("""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""")
+        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. """
+        # 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)
+                elif response == gtk.RESPONSE_NO:
+                    # We don't have to do anything
+                    pass
+                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. """
+        # 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)
+            dialog.show()
+        else:
+            warning_dialog(_("Committing not allowed"),
+                           _("Please save your document before committing."))
+    
+    def create_patch(self, action):
+        """ 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)
+            dialog.show()
+        else:
+            warning_dialog(_("Creating patch not allowed"),
+                           _("Please save your document before creating a patch."))
+    
+    def dummy_action(self, action):
+        """ Dummy action handler. """
+        pass
+    
+    def new_document(self, action):
+        """ 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. """
+        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. """
+        # 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)
+                elif response == gtk.RESPONSE_NO:
+                    # We don't have to do anything
+                    pass
+                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
+        set in the application instance.
+        """
+        self._document.destroy()
+        # Assign the new document
+        self._document = new_document
+        self._app.set_document(self._document)
+        # Pack the new document into the main window
+        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. """
+        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. """
+        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. """
+        if self._document.get_filename() is None:
+            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. """
+        self._window.show_all()
+    
+    def show_preferences(self, action):
+        """ Show the Preferences dialog. """
+        pref = PreferencesDialog(self._app)
+        pref.show()

Added: trunk/src/foiegras/windows/patch.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/windows/patch.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,236 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os
+
+import pygtk
+pygtk.require('2.0')
+import gobject
+import gtk
+import gtk.glade
+import pango
+
+try:
+    import gtksourceview
+    have_gtksourceview = True
+except ImportError:
+    have_gtksourceview = False
+
+from foiegras.windows.dialog import (AskOverwriteDialog,
+                                     error_dialog)
+
+def _(str):
+    """ Dummy gettext replacement. """
+    return str
+
+class CreatePatchDialog:
+    """ A wrapper class around the Create Patch dialog. """
+    
+    def __init__(self, app):
+        """ Constructor for the CreatePatchDialog. """
+        self._app = app
+        self._conf = self._app.get_conf()
+        
+        gladefile = self._app.get_datadir() + os.sep + 'patch.glade'
+        self._glade = gtk.glade.XML(gladefile, 'dialog_create_patch', 'foiegras')
+        
+        signals = { 'on_button_cancel_clicked': self.close,
+                    'on_button_create_clicked': self.create }
+        
+        self._glade.signal_autoconnect(signals)
+        
+        self._window = self._glade.get_widget('dialog_create_patch')
+        self._combo_profiles = self._glade.get_widget('combobox_vcsprofile')
+        self._entry_relpath = self._glade.get_widget('entry_relpath')
+        
+        cell = gtk.CellRendererText()
+        self._combo_profiles.pack_start(cell, True)
+        self._combo_profiles.add_attribute(cell, 'text', 1)
+        
+        fn = self._app.get_document().get_filename()
+        if fn is not None:
+            self._entry_relpath.set_text(os.path.basename(fn))
+    
+    def _get_active_profile(self):
+        """ Return the ID of the selected profile or None, if nothing selected. """
+        model = self._combo_profiles.get_model()
+        active = self._combo_profiles.get_active()
+        if active < 0:
+            return None
+        return model[active][0]
+    
+    def _load_profiles(self):
+        """ This method creates an appropriate ListStore and loads the Version
+        Control profiles into it. """
+        # model = [ id, name ]
+        self._model_vcs = gtk.ListStore(gobject.TYPE_STRING,
+                                        gobject.TYPE_STRING)
+        
+        # Set the model
+        self._combo_profiles.set_model(self._model_vcs)
+        
+        # Retrieve profiles
+        profiles = self._conf.get_vcs_profiles()
+        
+        # Fill up the ListStore
+        for p in profiles:
+            if p['name'] is not None:
+                self._model_vcs.append([ p['id'], p['name'] ])
+            while gtk.events_pending():
+                gtk.main_iteration()
+    
+    def close(self, widget=None):
+        """ Close button clicked handler. """
+        self._window.destroy()
+    
+    def create(self, widget):
+        """ Create Patch button clicked handler. """
+        if self._get_active_profile() is None:
+            error_dialog(_("No Version Control profile selected"),
+                         _("Please select a Version Control profile."))
+            return
+        if len(self._entry_relpath.get_text()) == 0:
+            error_dialog(_("Missing relative path"),
+                         _("Please specify the relative path to the original file in the repository."))
+            return
+        
+        data = self._conf.get_vcs_profile(self._get_active_profile())
+        if data['type'] == 'bazaar':
+            from foiegras.vcs.bazaar import BazaarBackend
+            vcs = BazaarBackend()
+        elif data['type'] == 'subversion':
+            from foiegras.vcs.subversion import SubversionBackend
+            vcs = SubversionBackend()
+        
+        vcs.set_url(data['uri'])
+        (origfile, filename) = vcs.get_file(self._entry_relpath.get_text())
+        if origfile is None:
+            error_dialog(_("File not found"),
+                         _("Could not find the original file in the repository."))
+            return
+        patchfile = vcs.create_diff(origfile, self._app.get_document().get_filename(), filename)
+        
+        self.close()
+        save = SavePatchDialog(self._app, patchfile)
+        save.show()
+    
+    def show(self):
+        """ Show all contents of the dialog. """
+        self._load_profiles()
+        
+        self._window.show_all()
+
+
+class SavePatchDialog:
+    """ A wrapper around the Save Patch dialog. """
+    
+    def __init__(self, app, tempfile):
+        """ Constructor for the CreatePatchDialog. """
+        self._app = app
+        self._conf = self._app.get_conf()
+        self._tempfile = tempfile
+        
+        gladefile = self._app.get_datadir() + os.sep + 'patch.glade'
+        self._glade = gtk.glade.XML(gladefile, 'dialog_save_patch', 'foiegras')
+        
+        signals = { 'on_button_cancel_clicked': self.close,
+                    'on_button_save_clicked': self.save }
+        
+        self._glade.signal_autoconnect(signals)
+        
+        self._window = self._glade.get_widget('dialog_save_patch')
+        self._scrolledwindow = self._glade.get_widget('scrolledwindow_patch')
+        
+        if have_gtksourceview:
+            self._buffer = gtksourceview.SourceBuffer()
+            slm = gtksourceview.SourceLanguagesManager()
+            gsl = slm.get_language_from_mime_type("text/x-patch")
+            self._buffer.set_language(gsl)
+            self._buffer.set_highlight(True)
+            
+            self._textview = gtksourceview.SourceView(self._buffer)
+        else:
+            self._buffer = gtk.TextBuffer()
+            self._textview = gtk.TextView(self._buffer)
+        
+        self._textview.set_editable(False)
+        self._textview.modify_font(pango.FontDescription("Monospace"))
+        self._scrolledwindow.add(self._textview)
+        
+        # Load the contents of the temporary file into the view
+        f = open(self._tempfile, 'r')
+        self._buffer.set_text(f.read())
+        f.close()
+   
+    def close(self, widget=None):
+        """ Close button clicked handler. """
+        self._window.destroy()
+    
+    def save(self, widget):
+        """ Save button clicked handler. """
+        save_buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+                        gtk.STOCK_SAVE, gtk.RESPONSE_OK)
+        
+        filter_diff = gtk.FileFilter()
+        filter_diff.set_name(_("Patches and diffs"))
+        filter_diff.add_pattern('*.patch')
+        filter_diff.add_pattern('*.diff')
+        filter_all = gtk.FileFilter()
+        filter_all.set_name(_("All files"))
+        filter_all.add_pattern('*.*')
+        
+        dialog = gtk.FileChooserDialog(title=_("Save Patch"),
+                                       action=gtk.FILE_CHOOSER_ACTION_SAVE,
+                                       buttons=save_buttons)
+        dialog.set_default_response(gtk.RESPONSE_OK)
+        dialog.add_filter(filter_diff)
+        dialog.add_filter(filter_all)
+        
+        response = dialog.run()
+        
+        fn = None
+        
+        if response != gtk.RESPONSE_NONE:
+            if response == gtk.RESPONSE_OK:
+                fn = dialog.get_filename()
+            
+            dialog.destroy()
+        
+        if fn is not None:
+            if os.path.exists(fn):
+                # We have a problem: file already exists
+                dialog = AskOverwriteDialog(fn, self._window)
+                
+                response = dialog.run()
+                
+                if response != gtk.RESPONSE_NONE:
+                    dialog.destroy()
+                    
+                    if response == gtk.RESPONSE_CANCEL:
+                        return
+                else:
+                    return
+            
+            f = open(fn, 'w')
+            (start, end) = self._buffer.get_bounds()
+            f.write(self._buffer.get_text(start, end))
+            f.close()
+        
+        self.close()
+    
+    def show(self):
+        """ Show all contents of the dialog. """
+        self._window.show_all()

Added: trunk/src/foiegras/windows/preferences.py
==============================================================================
--- (empty file)
+++ trunk/src/foiegras/windows/preferences.py	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,297 @@
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os
+
+import pygtk
+pygtk.require('2.0')
+import gobject
+import gtk
+import gtk.glade
+
+from foiegras.windows.dialog import error_dialog
+
+def _(str):
+    """ Dummy gettext replacement. """
+    return str
+
+class PreferencesDialog:
+    """ A wrapper class around the Preferences dialog. """
+    
+    def __init__(self, app):
+        """ Constructor for the PreferencesDialog. """
+        self._app = app
+        self._conf = self._app.get_conf()
+        
+        gladefile = self._app.get_datadir() + os.sep + 'preferences.glade'
+        self._glade = gtk.glade.XML(gladefile, 'dialog_preferences', 'foiegras')
+        
+        signals = { 'on_button_close_clicked': self.close,
+                    'on_button_vcs_add_clicked': self.add_vcs,
+                    'on_button_vcs_remove_clicked': self.remove_vcs,
+                    'on_button_vcs_edit_clicked': self.edit_vcs }
+        
+        self._glade.signal_autoconnect(signals)
+        
+        self._window = self._glade.get_widget('dialog_preferences')
+        self._treeview_vcs = self._glade.get_widget('treeview_vcs')
+        
+        # Add a column to the VCS profiles list
+        cell = gtk.CellRendererText()
+        self._column_vcs_name = gtk.TreeViewColumn(_("Profile Name"))
+        self._column_vcs_name.pack_start(cell, True)
+        self._column_vcs_name.add_attribute(cell, 'text', 1)
+        self._treeview_vcs.append_column(self._column_vcs_name)
+        
+        # Register callback for the VCS profiles
+        self._conf.add_notify('vcsprofiles', self._notify_callback)
+    
+    def _get_selected_vcs(self):
+        """ Returns the ID of the selected VCS profile. """
+        treeselection = self._treeview_vcs.get_selection()
+        (model, iter) = treeselection.get_selected()
+        
+        if iter is None:
+            return None
+        else:
+            return model.get_value(iter, 0)
+    
+    def _load_profiles(self):
+        """ This method creates an appropriate ListStore and loads the Version
+        Control profiles into it. """
+        # model = [ id, name ]
+        self._model_vcs = gtk.ListStore(gobject.TYPE_STRING,
+                                        gobject.TYPE_STRING)
+        
+        # Set the model
+        self._treeview_vcs.set_model(self._model_vcs)
+        
+        # Retrieve profiles
+        profiles = self._conf.get_vcs_profiles()
+        
+        # Fill up the ListStore
+        for p in profiles:
+            if p['name'] is not None:
+                self._model_vcs.append([ p['id'], p['name'] ])
+            while gtk.events_pending():
+                gtk.main_iteration()
+    
+    def _notify_callback(self, *args):
+        """ Callback function for notifications (reloads profiles). """
+        self._load_profiles()
+    
+    def add_vcs(self, widget):
+        """ Add VCS profile button handler. """
+        dialog = VCSProfileDialog(self._app)
+        dialog.show()
+    
+    def close(self, widget):
+        """ Close button clicked handler. """
+        self._window.destroy()
+    
+    def edit_vcs(self, widget):
+        """ Edit VCS profile button handler. """
+        sel_id = self._get_selected_vcs()
+        if sel_id is not None:
+            dialog = VCSProfileDialog(self._app, sel_id)
+            dialog.show()
+    
+    def remove_vcs(self, widget):
+        """ Delete VCS profile button handler. """
+        if self._get_selected_vcs() is not None:
+            dialog = AskRemoveDialog(self._get_selected_vcs, self._window)
+            response = dialog.run()
+            if response != gtk.RESPONSE_NONE:
+                dialog.destroy()
+                if response == gtk.RESPONSE_CANCEL:
+                    return
+            else:
+                return
+            
+            self._conf.remove_vcs_profile(self._get_selected_vcs())
+    
+    def show(self):
+        """ Show all contents of the dialog. """
+        self._load_profiles()
+        
+        self._window.show_all()
+
+
+from foiegras.vcs import FOIE_GRAS_VCS_TYPES
+
+class VCSProfileDialog:
+    """ VCS profile edit/add dialog. """
+    
+    def __init__(self, app, id=None):
+        """ Constructor. If id is None, we'll add a new profile, else edit. """
+        self._app = app
+        self._conf = self._app.get_conf()
+        self._add = True
+        
+        gladefile = self._app.get_datadir() + os.sep + 'preferences.glade'
+        self._glade = gtk.glade.XML(gladefile, 'dialog_vcs_profile', 'foiegras')
+        
+        signals = { 'on_button_vcs_cancel_clicked': self.close,
+                    'on_button_vcs_save_clicked': self.save }
+        
+        self._glade.signal_autoconnect(signals)
+        
+        self._window = self._glade.get_widget('dialog_vcs_profile')
+        self._entry_id = self._glade.get_widget('entry_vcs_id')
+        self._entry_name = self._glade.get_widget('entry_vcs_name')
+        self._combo_type = self._glade.get_widget('combobox_vcs_type')
+        self._entry_uri = self._glade.get_widget('entry_vcs_uri')
+        self._check_readonly = self._glade.get_widget('checkbutton_vcs_readonly')
+        
+        type = None
+        if id is not None:
+            # We are in Edit mode
+            self._add = False
+            # Fetch data
+            data = self._conf.get_vcs_profile(id)
+            self._entry_id.set_text(data['id'])
+            self._entry_name.set_text(data['name'])
+            type = data['type']
+            self._entry_uri.set_text(data['uri'])
+            if data['readonly']:
+                self._check_readonly.set_active(True)
+        
+        if not self._add:
+            # Deactivate ID entry, we already have an ID
+            self._entry_id.set_sensitive(False)
+        
+        self._construct_types(type)
+    
+    def _construct_types(self, selected=None):
+        """ Construct the ComboBox model. """        
+        self._model_types = gtk.ListStore(gobject.TYPE_STRING)
+        for type in FOIE_GRAS_VCS_TYPES:
+            self._model_types.append([ type ])
+        
+        cell = gtk.CellRendererText()
+        self._combo_type.pack_start(cell, True)
+        self._combo_type.add_attribute(cell, 'text', 0)
+        self._combo_type.set_model(self._model_types)
+        
+        if selected is not None:
+            self._combo_type.set_active(FOIE_GRAS_VCS_TYPES.index(selected))
+    
+    def close(self, widget=None):
+        """ Cancel button clicked handler. """
+        self._window.destroy()
+    
+    def save(self, widget):
+        """ Save button clicked handler. """
+        # Check the entries (they shouldn't be empty)
+        if len(self._entry_id.get_text().strip()) == 0:
+            error_dialog(_("Missing ID"),
+                         _("Please provide an ID for the profile."),
+                         self._window)
+            return
+        if len(self._entry_name.get_text().strip()) == 0:
+            error_dialog(_("Missing Name"),
+                         _("Please provide a name for the profile."),
+                         self._window)
+            return
+        if self._combo_type.get_active() == -1:
+            error_dialog(_("Missing Type"),
+                         _("Please select a type for the profile."),
+                         self._window)
+            return
+        if len(self._entry_uri.get_text().strip()) == 0:
+            error_dialog(_("Missing URI"),
+                         _("Please provide an URI for the profile."),
+                         self._window)
+            return
+        
+        if self._add:
+            id = self._entry_id.get_text()
+            if not id.isalnum():
+                error_dialog(_("Invalid ID"),
+                             _("The ID must contain only alphanumeric characters (no special ones)."),
+                             self._window)
+                return
+            if self._conf.exists_vcs_profile(id):
+                error_dialog(_("Existing ID"),
+                             _("The ID already exists, please choose another one."),
+                             self._window)
+                return
+            
+        data = {}
+        data['id'] = self._entry_id.get_text()
+        data['name'] = self._entry_name.get_text()
+        data['type'] = FOIE_GRAS_VCS_TYPES[self._combo_type.get_active()]
+        data['uri'] = self._entry_uri.get_text()
+        data['readonly'] = self._check_readonly.get_active()
+        
+        if not self._conf.add_vcs_profile(data):
+            error_dialog(_("Adding the profile failed"),
+                         _("An unknown error happened while adding the profile. Please try again."),
+                         self._window)
+            return
+        
+        self.close()
+    
+    def show(self):
+        """ Show all contents of the dialog. """
+        self._window.show_all()
+
+
+class AskRemoveDialog(gtk.Dialog):
+    """ This class implements a dialog that asks the user if s/he wants to
+    remove the selected profile. """
+    def __init__(self, name, parent):
+        """ Initialize the question dialog. """
+        gtk.Dialog.__init__(self,
+                            title=_("Do you want to remove?") + ' - Foie Gras',
+                            parent=parent,
+                            flags=gtk.DIALOG_MODAL
+                        )
+        
+        # Create the widgets
+        self._image_question = gtk.image_new_from_stock(gtk.STOCK_DIALOG_QUESTION,
+                                                        gtk.ICON_SIZE_DIALOG)
+        self._button_cancel = gtk.Button(stock=gtk.STOCK_CANCEL)
+        self._button_remove = gtk.Button(stock=gtk.STOCK_REMOVE)
+        self._hbox = gtk.HBox()
+        self._label_question = gtk.Label()
+        
+        # Set properties
+        self._hbox.set_spacing(3)
+        self._label_question.set_markup(_("<big><b>Do you want to remove the selected profile?</b></big>"))
+        
+        # Set callbacks
+        self._button_cancel.connect('clicked', self._cancel)
+        self._button_remove.connect('clicked', self._remove)
+        
+        # Pack widgets
+        self._hbox.pack_start(self._image_question)
+        self._hbox.pack_start(self._label_question)
+        self.vbox.add(self._hbox)
+        self.action_area.pack_start(self._button_cancel)
+        self.action_area.pack_start(self._button_remove)
+        
+        # Show all widgets
+        self.vbox.show_all()
+        self.action_area.show_all()
+    
+    def _cancel(self, widget):
+        """ Cancel button clicked. """
+        self.response(gtk.RESPONSE_CANCEL)
+    
+    def _remove(self, widget):
+        """ Save button click handler. """
+        self.response(gtk.RESPONSE_YES)

Added: trunk/start-foiegras
==============================================================================
--- (empty file)
+++ trunk/start-foiegras	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2007 by Szilveszter Farkas (Phanatic) <szilveszter farkas 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 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 os
+import sys
+
+try:
+    import pygtk
+    pygtk.require('2.0')
+    import gtk
+except ImportError:
+    print "PyGTK not found."
+    sys.exit(1)
+
+from foiegras.application import FoieGrasApplication
+
+app = FoieGrasApplication('/usr/share/foiegras')
+
+gtk.main()

Added: trunk/testing.xml
==============================================================================
--- (empty file)
+++ trunk/testing.xml	Mon Jan 28 19:26:58 2008
@@ -0,0 +1,73 @@
+<page id="el-synopsis">
+<info>
+  <anchor id="mal_block_synopsis"><title>mal_block_synopsis</title></anchor>
+  <link type="embed" xref="set-block"/>
+</info>
+
+<title>Synopses</title>
+
+<synopsis><code>mal_block_synopsis =
+element synopsis {
+  mal_attr_common,
+  <link xref="mal_block_title"/>?
+  (
+    <link xref="mal_block_code"/>,
+    <link xref="mal_block_p"/>
+  )+
+}</code></synopsis>
+<em>Strong type</em>
+
+<figure>
+  <media type="image" mime="image/png" href="mallard.png"/>
+  <caption>Drake, the Mallard mascot</caption>
+</figure>
+
+<table frame="all" rules="rows">
+  <tr>
+    <td>GNOME 2.6</td>
+    <td>2004-03-15</td>
+    <td>Development</td>
+    <td>Release Notes</td>
+  </tr>
+  <tr>
+    <td>GNOME 2.8</td>
+    <td>2004-09-15</td>
+    <td>Development</td>
+    <td>Release Notes</td>
+  </tr>
+  <tr>
+    <td>GNOME 2.10</td>
+    <td>2005-03-09</td>
+    <td>Development</td>
+    <td>Release Notes</td>
+  </tr>
+</table>
+
+<p>The <code>synopsis</code> element allows you to mark up a block as
+providing an overview of the material being presented.  It is useful
+for providing a listing functions, commands, or options in reference
+material, or for enumerating the items in a menu or other graphical
+control element.</p>
+
+<comment>
+  <cite><name>Shaun McCance</name><date>2006-11-16</date></cite>
+  <p>Add explanation, examples</p>
+</comment>
+
+<section>
+  <title>Processing Expectations</title>
+
+  <p>A <code>synopsis</code> element should be rendered as a displayed
+  block, with each of its child elements interpreted as block elements.
+  Since a <code>synopsis</code> element often contains large blocks,
+  and is generally offset from the running text, processing tools may
+  opt to render it inside a colored or screened box, with a border, or
+  otherwise differently from the surrounding text.</p>
+
+  <p>If a <code xref="mal_block_title">title</code> element is provided,
+  it should appear at the top of the block and be clearly marked as the
+  title using font variations or other stylistic means.</p>
+
+</section>
+
+</page>



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