foiegras r47 - in trunk: . data doc src src/foiegras src/foiegras/buffer src/foiegras/vcs src/foiegras/windows
- From: dscorgie svn gnome org
- To: svn-commits-list gnome org
- Subject: foiegras r47 - in trunk: . data doc src src/foiegras src/foiegras/buffer src/foiegras/vcs src/foiegras/windows
- Date: Mon, 28 Jan 2008 19:26:59 +0000 (GMT)
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]