mirror of
https://github.com/gryf/pygtktalog.git
synced 2025-12-17 11:30:19 +01:00
* New version using pygtkmvc framework.
This commit is contained in:
130
mvc/glade/foo.glade
Normal file
130
mvc/glade/foo.glade
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-interface>
|
||||||
|
|
||||||
|
<widget class="GtkWindow" id="window1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="title" translatable="yes">window1</property>
|
||||||
|
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||||
|
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||||
|
<property name="modal">False</property>
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="destroy_with_parent">False</property>
|
||||||
|
<property name="decorated">True</property>
|
||||||
|
<property name="skip_taskbar_hint">False</property>
|
||||||
|
<property name="skip_pager_hint">False</property>
|
||||||
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||||
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
|
<signal name="delete_event" handler="on_window1_delete_event" last_modification_time="Mon, 30 Apr 2007 10:09:49 GMT"/>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkFrame" id="frame1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="label_yalign">0.5</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xscale">1</property>
|
||||||
|
<property name="yscale">1</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">label2</property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">False</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
<property name="width_chars">-1</property>
|
||||||
|
<property name="single_line_mode">False</property>
|
||||||
|
<property name="angle">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkHSeparator" id="hseparator1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="button1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label" translatable="yes">button1</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><b>frame1</b></property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
<property name="width_chars">-1</property>
|
||||||
|
<property name="single_line_mode">False</property>
|
||||||
|
<property name="angle">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="type">label_item</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</glade-interface>
|
||||||
588
mvc/glade/main.glade
Normal file
588
mvc/glade/main.glade
Normal file
@@ -0,0 +1,588 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-interface>
|
||||||
|
|
||||||
|
<widget class="GtkWindow" id="main">
|
||||||
|
<property name="title" translatable="yes">mainW</property>
|
||||||
|
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||||
|
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||||
|
<property name="modal">False</property>
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="destroy_with_parent">False</property>
|
||||||
|
<property name="decorated">True</property>
|
||||||
|
<property name="skip_taskbar_hint">False</property>
|
||||||
|
<property name="skip_pager_hint">False</property>
|
||||||
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||||
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
|
<signal name="destroy" handler="on_main_destroy_event" last_modification_time="Tue, 22 Aug 2006 19:12:49 GMT"/>
|
||||||
|
<signal name="delete_event" handler="on_main_destroy_event" last_modification_time="Mon, 30 Apr 2007 10:54:10 GMT"/>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuBar" id="mainMenubar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="pack_direction">GTK_PACK_DIRECTION_LTR</property>
|
||||||
|
<property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="menuitem1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_File</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="menuitem1_menu">
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="new1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-new</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_new1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="open1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-open</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_open1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="save1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-save</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_save1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="save_as1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-save-as</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_save_as1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSeparatorMenuItem" id="separator1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="recent_files1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Recent files</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<signal name="activate" handler="on_recent_files1_activate" last_modification_time="Thu, 23 Nov 2006 18:29:26 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="quit1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-quit</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_quit1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="menuitem2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_Edit</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="menuitem2_menu">
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="cut1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-cut</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_cut1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="copy1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-copy</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_copy1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="paste1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-paste</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_paste1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="delete1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-delete</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_delete1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSeparatorMenuItem" id="separator2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="properties1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-preferences</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_preferences_activate" last_modification_time="Mon, 30 Apr 2007 11:32:52 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="catalog1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_Catalog</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="catalog1_menu">
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="add_cd">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Add CD/DVD</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<signal name="activate" handler="on_add_cd_activate" last_modification_time="Fri, 24 Nov 2006 14:12:30 GMT"/>
|
||||||
|
<accelerator key="a" modifiers="GDK_CONTROL_MASK" signal="activate"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="add_directory1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Add Directory</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<signal name="activate" handler="on_add_directory1_activate" last_modification_time="Fri, 24 Nov 2006 14:12:30 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="menuitem3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_View</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="menuitem3_menu">
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkCheckMenuItem" id="toolbar1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Toolbar</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="active">False</property>
|
||||||
|
<signal name="activate" handler="on_toolbar1_activate" last_modification_time="Fri, 01 Dec 2006 18:23:32 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkCheckMenuItem" id="status_bar1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Status bar</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="active">False</property>
|
||||||
|
<signal name="activate" handler="on_status_bar1_activate" last_modification_time="Fri, 01 Dec 2006 18:23:32 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="menuitem4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_Help</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="menuitem4_menu">
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="about1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label">gtk-about</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_about1_activate" last_modification_time="Wed, 09 Aug 2006 17:12:54 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolbar" id="maintoolbar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||||
|
<property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
|
||||||
|
<property name="tooltips">True</property>
|
||||||
|
<property name="show_arrow">True</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolButton" id="tb_new">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip" translatable="yes">Create new catalog</property>
|
||||||
|
<property name="stock_id">gtk-new</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
<signal name="clicked" handler="on_tb_new_clicked" last_modification_time="Fri, 01 Dec 2006 16:59:03 GMT"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolButton" id="tb_open">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip" translatable="yes">Open catalog file</property>
|
||||||
|
<property name="stock_id">gtk-open</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
<signal name="clicked" handler="on_tb_open_clicked" last_modification_time="Fri, 01 Dec 2006 16:59:14 GMT"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolButton" id="tb_save">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip" translatable="yes">Save catalog</property>
|
||||||
|
<property name="stock_id">gtk-save</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
<signal name="clicked" handler="on_tb_save_clicked" last_modification_time="Fri, 01 Dec 2006 16:59:20 GMT"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolItem" id="toolitem2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVSeparator" id="vseparator1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolButton" id="tb_addcd">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip" translatable="yes">Add CD/DVD to catalog</property>
|
||||||
|
<property name="label" translatable="yes">Add CD</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="stock_id">gtk-cdrom</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
<signal name="clicked" handler="on_tb_addcd_clicked" last_modification_time="Fri, 01 Dec 2006 16:59:25 GMT"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolButton" id="tb_find">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip" translatable="yes">Find file</property>
|
||||||
|
<property name="stock_id">gtk-find</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
<signal name="clicked" handler="on_tb_find_clicked" last_modification_time="Fri, 01 Dec 2006 16:59:29 GMT"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolItem" id="toolitem3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVSeparator" id="vseparator2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkToolButton" id="tb_quit">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="tooltip" translatable="yes">Quit pyGTKtalog</property>
|
||||||
|
<property name="stock_id">gtk-quit</property>
|
||||||
|
<property name="visible_horizontal">True</property>
|
||||||
|
<property name="visible_vertical">True</property>
|
||||||
|
<property name="is_important">False</property>
|
||||||
|
<signal name="clicked" handler="on_tb_quit_clicked" last_modification_time="Fri, 01 Dec 2006 16:57:57 GMT"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkHPaned" id="hpaned1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</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>
|
||||||
|
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTreeView" id="discs">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="headers_visible">False</property>
|
||||||
|
<property name="rules_hint">True</property>
|
||||||
|
<property name="reorderable">False</property>
|
||||||
|
<property name="enable_search">True</property>
|
||||||
|
<property name="fixed_height_mode">False</property>
|
||||||
|
<property name="hover_selection">False</property>
|
||||||
|
<property name="hover_expand">False</property>
|
||||||
|
<signal name="cursor_changed" handler="on_discs_cursor_changed" last_modification_time="Thu, 07 Dec 2006 16:47:17 GMT"/>
|
||||||
|
<signal name="row_activated" handler="on_discs_row_activated" last_modification_time="Thu, 21 Dec 2006 19:25:39 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
<property name="resize">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVPaned" id="vpaned1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="scrolledwindow2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</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>
|
||||||
|
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTreeView" id="files">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="headers_visible">True</property>
|
||||||
|
<property name="rules_hint">True</property>
|
||||||
|
<property name="reorderable">False</property>
|
||||||
|
<property name="enable_search">True</property>
|
||||||
|
<property name="fixed_height_mode">False</property>
|
||||||
|
<property name="hover_selection">False</property>
|
||||||
|
<property name="hover_expand">False</property>
|
||||||
|
<signal name="cursor_changed" handler="on_files_cursor_changed" last_modification_time="Thu, 07 Dec 2006 16:48:04 GMT"/>
|
||||||
|
<signal name="row_activated" handler="on_files_row_activated" last_modification_time="Thu, 21 Dec 2006 19:25:53 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
<property name="resize">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="detailplace">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</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>
|
||||||
|
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTextView" id="details">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="editable">False</property>
|
||||||
|
<property name="overwrite">False</property>
|
||||||
|
<property name="accepts_tab">False</property>
|
||||||
|
<property name="justification">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap_mode">GTK_WRAP_NONE</property>
|
||||||
|
<property name="cursor_visible">False</property>
|
||||||
|
<property name="pixels_above_lines">0</property>
|
||||||
|
<property name="pixels_below_lines">0</property>
|
||||||
|
<property name="pixels_inside_wrap">0</property>
|
||||||
|
<property name="left_margin">0</property>
|
||||||
|
<property name="right_margin">0</property>
|
||||||
|
<property name="indent">0</property>
|
||||||
|
<property name="text" translatable="yes"></property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
<property name="resize">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="shrink">False</property>
|
||||||
|
<property name="resize">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkHBox" id="statusprogress">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkStatusbar" id="mainStatus">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="has_resize_grip">False</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkProgressBar" id="progressbar1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
|
||||||
|
<property name="fraction">0</property>
|
||||||
|
<property name="pulse_step">0.10000000149</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</glade-interface>
|
||||||
48
mvc/gtkmvc/__init__.py
Normal file
48
mvc/gtkmvc/__init__.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["model", "view", "controller", "observable", "observer"]
|
||||||
|
|
||||||
|
__version = (1,0,0)
|
||||||
|
|
||||||
|
from model import Model, TreeStoreModel, ListStoreModel, TextBufferModel
|
||||||
|
from model_mt import ModelMT
|
||||||
|
from controller import Controller
|
||||||
|
from view import View
|
||||||
|
from observer import Observer
|
||||||
|
import observable
|
||||||
|
|
||||||
|
|
||||||
|
def get_version(): return __version
|
||||||
|
|
||||||
|
def require(ver):
|
||||||
|
if isinstance(ver, str): ver = ver.split(".")
|
||||||
|
ver = tuple(map(int, ver))
|
||||||
|
|
||||||
|
if get_version() < ver:
|
||||||
|
raise AssertionError("gtkmvc required version '%s', found '%s'"\
|
||||||
|
% (ver, get_version()))
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
46
mvc/gtkmvc/controller.py
Normal file
46
mvc/gtkmvc/controller.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
from gtkmvc.observer import Observer
|
||||||
|
|
||||||
|
class Controller (Observer):
|
||||||
|
"""We put all of our gtk signal handlers into a class. This lets us bind
|
||||||
|
all of them at once, because their names are in the class dict.
|
||||||
|
This class automatically register its instances as observers into the
|
||||||
|
corresponding model.
|
||||||
|
Also, when a view is created, the view calls method register_view,
|
||||||
|
which can be oveloaded in order to connect signals and perform other
|
||||||
|
specific operation"""
|
||||||
|
|
||||||
|
def __init__(self, model):
|
||||||
|
Observer.__init__(self, model)
|
||||||
|
|
||||||
|
self.view = None
|
||||||
|
return
|
||||||
|
|
||||||
|
def register_view(self, view):
|
||||||
|
assert(self.view is None)
|
||||||
|
self.view = view
|
||||||
|
return
|
||||||
|
|
||||||
|
pass # end of class Controller
|
||||||
316
mvc/gtkmvc/model.py
Normal file
316
mvc/gtkmvc/model.py
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
import support.metaclasses
|
||||||
|
from support.wrappers import ObsWrapperBase
|
||||||
|
from observable import Signal
|
||||||
|
|
||||||
|
|
||||||
|
class Model (object):
|
||||||
|
"""This class is the application model base class.
|
||||||
|
It handles a set of observable properties which you are interested
|
||||||
|
in showing by one ore more view - via one or more observers of course.
|
||||||
|
The mechanism is the following:
|
||||||
|
1. You are interested in showing a set of model property, that you can
|
||||||
|
declare in the __properties__ member map.
|
||||||
|
2. You define one or more observers that observe one or more properties
|
||||||
|
you registered. When someone changes a property value the model notifies
|
||||||
|
the changing to each listening controller. The property-observer[s]
|
||||||
|
association is given by the implicit rule in observers method names: if
|
||||||
|
you want the model notified the changing event of the property 'p'
|
||||||
|
you must define the method called 'property_p_change_notification' in
|
||||||
|
each listening observer class.
|
||||||
|
Notice that tipically 'controllers' implement the observer pattern.
|
||||||
|
The notification method gets the
|
||||||
|
emitting model, the old value for the property and the new one.
|
||||||
|
Properties functionalities are automatically provided by the
|
||||||
|
ObservablePropertyMeta meta-class."""
|
||||||
|
|
||||||
|
__metaclass__ = support.metaclasses.ObservablePropertyMeta
|
||||||
|
__properties__ = {} # override this
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
object.__init__(self)
|
||||||
|
self.__observers = []
|
||||||
|
# keys are properties names, values are methods inside the observer:
|
||||||
|
self.__value_notifications = {}
|
||||||
|
self.__instance_notif_before = {}
|
||||||
|
self.__instance_notif_after = {}
|
||||||
|
self.__signal_notif = {}
|
||||||
|
|
||||||
|
for key in (self.__properties__.keys() + self.__derived_properties__.keys()):
|
||||||
|
self.register_property(key)
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def register_property(self, name):
|
||||||
|
"""Registers an existing property to be monitored, and sets up
|
||||||
|
notifiers for notifications"""
|
||||||
|
if not self.__value_notifications.has_key(name):
|
||||||
|
self.__value_notifications[name] = []
|
||||||
|
pass
|
||||||
|
|
||||||
|
# registers observable wrappers
|
||||||
|
prop = getattr(self, "_prop_%s" % name)
|
||||||
|
|
||||||
|
if isinstance(prop, ObsWrapperBase):
|
||||||
|
prop.__set_model__(self, name)
|
||||||
|
|
||||||
|
if isinstance(prop, Signal):
|
||||||
|
if not self.__signal_notif.has_key(name):
|
||||||
|
self.__signal_notif[name] = []
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if not self.__instance_notif_before.has_key(name):
|
||||||
|
self.__instance_notif_before[name] = []
|
||||||
|
pass
|
||||||
|
if not self.__instance_notif_after.has_key(name):
|
||||||
|
self.__instance_notif_after[name] = []
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def register_observer(self, observer):
|
||||||
|
if observer in self.__observers: return # not already registered
|
||||||
|
|
||||||
|
self.__observers.append(observer)
|
||||||
|
for key in (self.__properties__.keys() + self.__derived_properties__.keys()):
|
||||||
|
self.__add_observer_notification(observer, key)
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def unregister_observer(self, observer):
|
||||||
|
if observer not in self.__observers: return
|
||||||
|
|
||||||
|
for key in (self.__properties__.keys() + self.__derived_properties__.keys()):
|
||||||
|
self.__remove_observer_notification(observer, key)
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.__observers.remove(observer)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def _reset_property_notification(self, prop_name):
|
||||||
|
"""Called when it has done an assignment that changes the type
|
||||||
|
of a property, so it must be unregistered and registered again"""
|
||||||
|
|
||||||
|
self.register_property(prop_name)
|
||||||
|
|
||||||
|
for observer in self.__observers:
|
||||||
|
self.__remove_observer_notification(observer, prop_name)
|
||||||
|
self.__add_observer_notification(observer, prop_name)
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def __add_observer_notification(self, observer, prop_name):
|
||||||
|
"""Searches in the observer for any possible listener, and
|
||||||
|
stores the notification methods to be called later"""
|
||||||
|
|
||||||
|
method_name = "property_%s_value_change" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method not in self.__value_notifications[prop_name]:
|
||||||
|
list.append(self.__value_notifications[prop_name], method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
# is it a signal?
|
||||||
|
orig_prop = getattr(self, "_prop_%s" % prop_name)
|
||||||
|
if isinstance(orig_prop, Signal):
|
||||||
|
method_name = "property_%s_signal_emit" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method not in self.__signal_notif[prop_name]:
|
||||||
|
list.append(self.__signal_notif[prop_name], method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
# is it an instance change notification type?
|
||||||
|
elif isinstance(orig_prop, ObsWrapperBase):
|
||||||
|
method_name = "property_%s_before_change" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method not in self.__instance_notif_before[prop_name]:
|
||||||
|
list.append(self.__instance_notif_before[prop_name], method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
method_name = "property_%s_after_change" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method not in self.__instance_notif_after[prop_name]:
|
||||||
|
list.append(self.__instance_notif_after[prop_name], method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def __remove_observer_notification(self, observer, prop_name):
|
||||||
|
if self.__value_notifications.has_key(prop_name):
|
||||||
|
method_name = "property_%s_value_change" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method in self.__value_notifications[prop_name]:
|
||||||
|
self.__value_notifications[prop_name].remove(method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
orig_prop = getattr(self, "_prop_%s" % prop_name)
|
||||||
|
# is it a signal?
|
||||||
|
if isinstance(orig_prop, Signal):
|
||||||
|
method_name = "property_%s_signal_emit" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method in self.__signal_notif[prop_name]:
|
||||||
|
self.__signal_notif[prop_name].remove(method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
# is it an instance change notification type?
|
||||||
|
elif isinstance(orig_prop, ObsWrapperBase):
|
||||||
|
if self.__instance_notif_before.has_key(prop_name):
|
||||||
|
method_name = "property_%s_before_change" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method in self.__instance_notif_before[prop_name]:
|
||||||
|
self.__instance_notif_before[prop_name].remove(method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
if self.__instance_notif_after.has_key(prop_name):
|
||||||
|
method_name = "property_%s_after_change" % prop_name
|
||||||
|
if hasattr(observer, method_name):
|
||||||
|
method = getattr(observer, method_name)
|
||||||
|
if method in self.__instance_notif_after[prop_name]:
|
||||||
|
self.__instance_notif_after[prop_name].remove(method)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def __notify_observer__(self, observer, method, *args, **kwargs):
|
||||||
|
"""This can be overridden by derived class in order to call
|
||||||
|
the method in a different manner (for example, in
|
||||||
|
multithreading, or a rpc, etc.) This implementation simply
|
||||||
|
calls the given method with the given arguments"""
|
||||||
|
return method(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------- Notifiers:
|
||||||
|
|
||||||
|
def notify_property_value_change(self, prop_name, old, new):
|
||||||
|
assert(self.__value_notifications.has_key(prop_name))
|
||||||
|
for method in self.__value_notifications[prop_name] :
|
||||||
|
self.__notify_observer__(method.im_self, method,
|
||||||
|
self, old, new) # notifies the change
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
def notify_method_before_change(self, prop_name, instance, meth_name,
|
||||||
|
args, kwargs):
|
||||||
|
assert(self.__instance_notif_before.has_key(prop_name))
|
||||||
|
for method in self.__instance_notif_before[prop_name] :
|
||||||
|
self.__notify_observer__(method.im_self, method, self, instance,
|
||||||
|
meth_name, args, kwargs) # notifies the change
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
def notify_method_after_change(self, prop_name, instance, meth_name,
|
||||||
|
res, args, kwargs):
|
||||||
|
assert(self.__instance_notif_after.has_key(prop_name))
|
||||||
|
for method in self.__instance_notif_after[prop_name] :
|
||||||
|
self.__notify_observer__(method.im_self, method, self, instance,
|
||||||
|
meth_name, res, args, kwargs) # notifies the change
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
def notify_signal_emit(self, prop_name, args, kwargs):
|
||||||
|
assert(self.__signal_notif.has_key(prop_name))
|
||||||
|
for method in self.__signal_notif[prop_name] :
|
||||||
|
self.__notify_observer__(method.im_self, method, self,
|
||||||
|
args, kwargs) # notifies the signal emit
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
pass # end of class Model
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class TreeStoreModel (Model, gtk.TreeStore):
|
||||||
|
"""Use this class as base class for your model derived by
|
||||||
|
gtk.TreeStore"""
|
||||||
|
__metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta
|
||||||
|
|
||||||
|
def __init__(self, column_type, *args):
|
||||||
|
Model.__init__(self)
|
||||||
|
gtk.TreeStore.__init__(self, column_type, *args)
|
||||||
|
return
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ListStoreModel (Model, gtk.ListStore):
|
||||||
|
"""Use this class as base class for your model derived by
|
||||||
|
gtk.ListStore"""
|
||||||
|
__metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta
|
||||||
|
|
||||||
|
def __init__(self, column_type, *args):
|
||||||
|
Model.__init__(self)
|
||||||
|
gtk.ListStore.__init__(self, column_type, *args)
|
||||||
|
return
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class TextBufferModel (Model, gtk.TextBuffer):
|
||||||
|
"""Use this class as base class for your model derived by
|
||||||
|
gtk.TextBuffer"""
|
||||||
|
__metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta
|
||||||
|
|
||||||
|
def __init__(self, table=None):
|
||||||
|
Model.__init__(self)
|
||||||
|
gtk.TextBuffer.__init__(self, table)
|
||||||
|
return
|
||||||
|
pass
|
||||||
|
|
||||||
119
mvc/gtkmvc/model_mt.py
Normal file
119
mvc/gtkmvc/model_mt.py
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
from gtkmvc.model import Model
|
||||||
|
import support.metaclasses
|
||||||
|
|
||||||
|
try: import threading as _threading
|
||||||
|
except ImportError: import dummy_threading as _threading
|
||||||
|
|
||||||
|
import gobject
|
||||||
|
if hasattr(gobject, "threads_init"): gobject.threads_init()
|
||||||
|
else: import gtk; gtk.threads_init()
|
||||||
|
|
||||||
|
|
||||||
|
class ModelMT (Model):
|
||||||
|
"""A base class for models whose observable properties can be
|
||||||
|
changed by threads different than gtk main thread. Notification is
|
||||||
|
performed by exploiting the gtk idle loop only if needed,
|
||||||
|
otherwise the standard notification system (direct method call) is
|
||||||
|
used."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Model.__init__(self)
|
||||||
|
self.__observer_threads = {}
|
||||||
|
return
|
||||||
|
|
||||||
|
def register_observer(self, observer):
|
||||||
|
Model.register_observer(self, observer)
|
||||||
|
self.__observer_threads[observer] = _threading.currentThread()
|
||||||
|
return
|
||||||
|
|
||||||
|
def unregister_observer(self, observer):
|
||||||
|
Model.unregister_observer(self, observer)
|
||||||
|
del self.__observer_threads[observer]
|
||||||
|
return
|
||||||
|
|
||||||
|
# ---------- Notifiers:
|
||||||
|
|
||||||
|
def __notify_observer__(self, observer, method, *args, **kwargs):
|
||||||
|
"""This makes a call either through the gtk.idle list or a
|
||||||
|
direct method call depending whether the caller's thread is
|
||||||
|
different from the observer's thread"""
|
||||||
|
|
||||||
|
assert self.__observer_threads.has_key(observer)
|
||||||
|
if _threading.currentThread() == self.__observer_threads[observer]:
|
||||||
|
# standard call
|
||||||
|
return Model.__notify_observer__(self, observer, method,
|
||||||
|
args, kwargs)
|
||||||
|
|
||||||
|
# multi-threading call
|
||||||
|
gobject.idle_add(self.__idle_callback, observer, method, args, kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
|
def __idle_callback(self, observer, method, args, kwargs):
|
||||||
|
method(*args, **kwargs)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
pass # end of class
|
||||||
|
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class TreeStoreModelMT (ModelMT, gtk.TreeStore):
|
||||||
|
"""Use this class as base class for your model derived by
|
||||||
|
gtk.TreeStore"""
|
||||||
|
__metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta
|
||||||
|
|
||||||
|
def __init__(self, column_type, *args):
|
||||||
|
ModelMT.__init__(self)
|
||||||
|
gtk.TreeStore.__init__(self, column_type, *args)
|
||||||
|
return
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ListStoreModelMT (ModelMT, gtk.ListStore):
|
||||||
|
"""Use this class as base class for your model derived by
|
||||||
|
gtk.ListStore"""
|
||||||
|
__metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta
|
||||||
|
|
||||||
|
def __init__(self, column_type, *args):
|
||||||
|
ModelMT.__init__(self)
|
||||||
|
gtk.ListStore.__init__(self, column_type, *args)
|
||||||
|
return
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class TextBufferModelMT (ModelMT, gtk.TextBuffer):
|
||||||
|
"""Use this class as base class for your model derived by
|
||||||
|
gtk.TextBuffer"""
|
||||||
|
__metaclass__ = support.metaclasses.ObservablePropertyGObjectMeta
|
||||||
|
|
||||||
|
def __init__(self, table=None):
|
||||||
|
ModelMT.__init__(self)
|
||||||
|
gtk.TextBuffer.__init__(self, table)
|
||||||
|
return
|
||||||
|
pass
|
||||||
68
mvc/gtkmvc/observable.py
Normal file
68
mvc/gtkmvc/observable.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author <cavada@irst.itc.it>.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
from support import decorators
|
||||||
|
from support.wrappers import ObsWrapperBase
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class Observable (ObsWrapperBase):
|
||||||
|
def __init__(self):
|
||||||
|
ObsWrapperBase.__init__(self)
|
||||||
|
return
|
||||||
|
pass # end of class
|
||||||
|
|
||||||
|
|
||||||
|
@decorators.good_decorator
|
||||||
|
def observed(func):
|
||||||
|
"""Use this decorator to make your class methods observable.
|
||||||
|
|
||||||
|
Your observer will receive at most two notifications:
|
||||||
|
- property_<name>_before_change
|
||||||
|
- property_<name>_after_change
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
self = args[0]
|
||||||
|
assert(isinstance(self, Observable))
|
||||||
|
|
||||||
|
self._notify_method_before(self, func.__name__, args, kwargs)
|
||||||
|
res = func(*args, **kwargs)
|
||||||
|
self._notify_method_after(self, func.__name__, res, args, kwargs)
|
||||||
|
return res
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class Signal (Observable):
|
||||||
|
"""Base class for signals properties"""
|
||||||
|
def __init__(self):
|
||||||
|
Observable.__init__(self)
|
||||||
|
return
|
||||||
|
|
||||||
|
def emit(self, *args, **kwargs):
|
||||||
|
return self.__get_model__().notify_signal_emit(
|
||||||
|
self.__get_prop_name__(), args, kwargs)
|
||||||
|
pass # end of class
|
||||||
|
|
||||||
56
mvc/gtkmvc/observer.py
Normal file
56
mvc/gtkmvc/observer.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class Observer (object):
|
||||||
|
"""Use this class as base class of all observers"""
|
||||||
|
|
||||||
|
def __init__(self, model=None):
|
||||||
|
self.model = None
|
||||||
|
self.register_model(model)
|
||||||
|
return
|
||||||
|
|
||||||
|
def register_model(self, model):
|
||||||
|
self.unregister_model()
|
||||||
|
self.model = model
|
||||||
|
if self.model: self.model.register_observer(self)
|
||||||
|
return
|
||||||
|
|
||||||
|
def unregister_model(self):
|
||||||
|
if self.model:
|
||||||
|
self.model.unregister_observer(self)
|
||||||
|
self.model = None
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.unregister_model()
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_model(self): return self.model
|
||||||
|
|
||||||
|
pass # end of class
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
24
mvc/gtkmvc/support/__init__.py
Normal file
24
mvc/gtkmvc/support/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["metaclass_base", "metaclasses", "wrappers", "decorators"]
|
||||||
43
mvc/gtkmvc/support/decorators.py
Normal file
43
mvc/gtkmvc/support/decorators.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# This file contains decorators to be used (privately) by other parts
|
||||||
|
# of the framework
|
||||||
|
|
||||||
|
def good_decorator(decorator):
|
||||||
|
"""This decorator makes decorators behave well wrt to decorated
|
||||||
|
functions names, doc, etc."""
|
||||||
|
def new_decorator(f):
|
||||||
|
g = decorator(f)
|
||||||
|
g.__name__ = f.__name__
|
||||||
|
g.__doc__ = f.__doc__
|
||||||
|
g.__dict__.update(f.__dict__)
|
||||||
|
return g
|
||||||
|
|
||||||
|
new_decorator.__name__ = decorator.__name__
|
||||||
|
new_decorator.__doc__ = decorator.__doc__
|
||||||
|
new_decorator.__dict__.update(decorator.__dict__)
|
||||||
|
return new_decorator
|
||||||
244
mvc/gtkmvc/support/metaclass_base.py
Normal file
244
mvc/gtkmvc/support/metaclass_base.py
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
import new
|
||||||
|
import re
|
||||||
|
import types
|
||||||
|
|
||||||
|
import gtkmvc.support.wrappers as wrappers
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERBOSE_LEVEL = 5
|
||||||
|
|
||||||
|
class PropertyMeta (type):
|
||||||
|
"""This is a meta-class that provides auto-property support.
|
||||||
|
The idea is to allow programmers to define some properties which
|
||||||
|
will be automatically connected to auto-generated code which handles
|
||||||
|
access to those properties.
|
||||||
|
How can you use this meta-class?
|
||||||
|
First, '__metaclass__ = PropertyMeta' must be class member of the class
|
||||||
|
you want to make the automatic properties handling.
|
||||||
|
Second, '__properties__' must be a map containing the properties names
|
||||||
|
as keys, values will be initial values for properties.
|
||||||
|
That's all: after the instantiation, your class will contain all properties
|
||||||
|
you named inside '__properties__'. Each of them will be also associated
|
||||||
|
to a couple of automatically-generated functions which get and set the
|
||||||
|
property value inside a generated member variable.
|
||||||
|
About names: suppose the property is called 'x'. The generated variable
|
||||||
|
(which keeps the real value of the property x) is called _prop_x.
|
||||||
|
The getter is called get_prop_x(self), and the setter is called
|
||||||
|
'set_prop_x(self, value)'.
|
||||||
|
|
||||||
|
Customization:
|
||||||
|
The base implementation of getter is to return the value stored in the
|
||||||
|
variable associate to the property. The setter simply sets its value.
|
||||||
|
Programmers can override basic behaviour for getters or setters simply by
|
||||||
|
defining their getters and setters (see at the names convention above).
|
||||||
|
The customized function can lie everywhere in the user classes hierarchy.
|
||||||
|
Every overrided function will not be generated by the metaclass.
|
||||||
|
|
||||||
|
To supply your own methods is good for few methods, but can result in a
|
||||||
|
very unconfortable way for many methods. In this case you can extend
|
||||||
|
the meta-class, and override methods get_[gs]etter_source with your
|
||||||
|
implementation (this can be probably made better).
|
||||||
|
An example is provided in meta-class PropertyMetaVerbose below.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(cls, name, bases, dict):
|
||||||
|
"""class constructor"""
|
||||||
|
properties = {}
|
||||||
|
type.__init__(cls, name, bases, dict)
|
||||||
|
|
||||||
|
props = getattr(cls, '__properties__', {})
|
||||||
|
setattr(cls, '__derived_properties__', {})
|
||||||
|
der_props = getattr(cls, '__derived_properties__')
|
||||||
|
|
||||||
|
# Calculates derived properties:
|
||||||
|
for base in bases:
|
||||||
|
maps = ( getattr(base, '__properties__', {}),
|
||||||
|
getattr(base, '__derived_properties__', {}) )
|
||||||
|
for map in maps:
|
||||||
|
for p in map.keys():
|
||||||
|
if not props.has_key(p) and not der_props.has_key(p):
|
||||||
|
der_props[p] = map[p]
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Generates code for all properties (but not for derived props):
|
||||||
|
props = getattr(cls, '__properties__', {})
|
||||||
|
for prop in props.keys():
|
||||||
|
type(cls).__create_prop_accessors__(cls, prop, props[prop])
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def __msg__(cls, msg, level):
|
||||||
|
"""if level is less or equal to VERBOSE_LEVEL, ths message will
|
||||||
|
be printed"""
|
||||||
|
if level <= VERBOSE_LEVEL: print msg
|
||||||
|
return
|
||||||
|
|
||||||
|
def __create_prop_accessors__(cls, prop_name, default_val):
|
||||||
|
"""Private method that creates getter and setter, and the
|
||||||
|
corresponding property"""
|
||||||
|
getter_name = "get_prop_%s" % prop_name
|
||||||
|
setter_name = "set_prop_%s" % prop_name
|
||||||
|
|
||||||
|
members_names = cls.__dict__.keys()
|
||||||
|
|
||||||
|
# checks if accessors are already defined:
|
||||||
|
if getter_name not in members_names:
|
||||||
|
src = type(cls).get_getter_source(cls, getter_name, prop_name)
|
||||||
|
code = type(cls).get_func_code_from_func_src(cls, src)
|
||||||
|
type(cls).add_method_from_func_code(cls, getter_name, code)
|
||||||
|
else:
|
||||||
|
cls.__msg__("Warning: Custom member '%s' overloads generated accessor of property '%s'" \
|
||||||
|
% (getter_name, prop_name), 2)
|
||||||
|
pass
|
||||||
|
|
||||||
|
if setter_name not in members_names:
|
||||||
|
src = type(cls).get_setter_source(cls, setter_name, prop_name)
|
||||||
|
code = type(cls).get_func_code_from_func_src(cls, src)
|
||||||
|
type(cls).add_method_from_func_code(cls, setter_name, code)
|
||||||
|
else:
|
||||||
|
cls.__msg__("Warning: Custom member '%s' overloads generated accessor of property '%s'" \
|
||||||
|
% (setter_name, prop_name), 2)
|
||||||
|
pass
|
||||||
|
|
||||||
|
prop = property(getattr(cls, getter_name), getattr(cls, setter_name))
|
||||||
|
|
||||||
|
if prop_name in members_names:
|
||||||
|
cls.__msg__("Warning: automatic property builder is overriding property %s in class %s" \
|
||||||
|
% (prop_name, cls.__name__), 2)
|
||||||
|
pass
|
||||||
|
setattr(cls, prop_name, prop)
|
||||||
|
|
||||||
|
varname = "_prop_%s" % prop_name
|
||||||
|
if not varname in members_names: cls.__create_property(varname, default_val)
|
||||||
|
else: cls.__msg__("Warning: automatic property builder found a possible clashing for variable %s inside class %s" \
|
||||||
|
% (varname, cls.__name__), 2)
|
||||||
|
return
|
||||||
|
|
||||||
|
def __create_property(cls, name, default_val):
|
||||||
|
setattr(cls, name, cls.create_value(name, default_val))
|
||||||
|
return
|
||||||
|
|
||||||
|
def create_value(cls, prop_name, val, model=None):
|
||||||
|
"""This is used to create a value to be assigned to a
|
||||||
|
property. Depending on the type of the value, different values
|
||||||
|
are created and returned. For example, for a list, a
|
||||||
|
ListWrapper is created to wrap it, and returned for the
|
||||||
|
assignment. model is different from model when the value is
|
||||||
|
changed (a model exists). Otherwise, during property creation
|
||||||
|
model is None"""
|
||||||
|
|
||||||
|
if isinstance(val, tuple):
|
||||||
|
# this might be a class instance to be wrapped
|
||||||
|
if len(val) == 3 and \
|
||||||
|
isinstance(val[1], val[0]) and \
|
||||||
|
(isinstance(val[2], tuple) or isinstance(val[2], list)):
|
||||||
|
res = wrappers.ObsUserClassWrapper(val[1], val[2])
|
||||||
|
if model: res.__set_model__(model, prop_name)
|
||||||
|
return res
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif isinstance(val, list):
|
||||||
|
res = wrappers.ObsListWrapper(val)
|
||||||
|
if model: res.__set_model__(model, prop_name)
|
||||||
|
return res
|
||||||
|
|
||||||
|
elif isinstance(val, dict):
|
||||||
|
res = wrappers.ObsMapWrapper(val)
|
||||||
|
if model: res.__set_model__(model, prop_name)
|
||||||
|
return res
|
||||||
|
|
||||||
|
return val
|
||||||
|
|
||||||
|
# Services:
|
||||||
|
def add_method_from_func_code(cls, meth_name, code):
|
||||||
|
"""Use this to add a code that is a new method for the class"""
|
||||||
|
|
||||||
|
func = new.function(code, globals(), meth_name)
|
||||||
|
meth = new.instancemethod(func, cls, cls.__name__)
|
||||||
|
setattr(cls, meth_name, func)
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_func_code_from_func_src(cls, source):
|
||||||
|
"""Public service that provided code object from function source"""
|
||||||
|
m = re.compile("def\s+(\w+)\s*\(.*\):").match(source)
|
||||||
|
if m is None: raise BadFuncSource(source)
|
||||||
|
|
||||||
|
func_name = m.group(1)
|
||||||
|
exec source
|
||||||
|
code = eval("%s.func_code" % func_name)
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
# Override these:
|
||||||
|
def get_getter_source(cls, getter_name, prop_name):
|
||||||
|
"""This must be overrided if you need a different implementation.
|
||||||
|
Simply the generated implementation returns the variable name
|
||||||
|
_prop_name"""
|
||||||
|
|
||||||
|
return "def %s(self): return self._prop_%s" % (getter_name, prop_name)
|
||||||
|
|
||||||
|
def get_setter_source(cls, setter_name, prop_name):
|
||||||
|
"""This must be overrided if you need a different implementation.
|
||||||
|
Simply the generated implementation sets the variable _prop_name"""
|
||||||
|
return "def %s(self, val): self._prop_%s = val" \
|
||||||
|
% (setter_name, prop_name)
|
||||||
|
|
||||||
|
pass # end of class
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# What follows underneath is a set of examples of usage
|
||||||
|
|
||||||
|
## class PropertyMetaVerbose (PropertyMeta):
|
||||||
|
## """An example of customization"""
|
||||||
|
## def get_getter_source(cls, getter_name, prop_name):
|
||||||
|
## return "def %s(self): print 'Calling %s!'; return self._prop_%s" \
|
||||||
|
## % (getter_name, getter_name, prop_name)
|
||||||
|
|
||||||
|
## def get_setter_source(cls, setter_name, prop_name):
|
||||||
|
## return "def %s(self, val): print 'Calling %s!'; self._prop_%s = val;" \
|
||||||
|
## % (setter_name, setter_name, prop_name)
|
||||||
|
## pass #end of class
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
## class User:
|
||||||
|
## """An example of usage"""
|
||||||
|
## __metaclass__ = PropertyMetaVerbose
|
||||||
|
## __properties__ = {'x':10, 'y':20}
|
||||||
|
|
||||||
|
## def __init__(self):
|
||||||
|
## print self.x # x is 10
|
||||||
|
## self.x = self.y + 10 # x is now 30
|
||||||
|
## return
|
||||||
|
## pass
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
54
mvc/gtkmvc/support/metaclasses.py
Normal file
54
mvc/gtkmvc/support/metaclasses.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
from metaclass_base import PropertyMeta
|
||||||
|
import types
|
||||||
|
|
||||||
|
|
||||||
|
class ObservablePropertyMeta (PropertyMeta):
|
||||||
|
"""Classes instantiated by this meta-class must provide a method named
|
||||||
|
notify_property_change(self, prop_name, old, new)"""
|
||||||
|
def __init__(cls, name, bases, dict):
|
||||||
|
PropertyMeta.__init__(cls, name, bases, dict)
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_setter_source(cls, setter_name, prop_name):
|
||||||
|
return """def %(setter)s(self, val):
|
||||||
|
old = self._prop_%(prop)s
|
||||||
|
self._prop_%(prop)s = type(self).create_value('%(prop)s', val, self)
|
||||||
|
if type(old) != type(self._prop_%(prop)s): self._reset_property_notification('%(prop)s')
|
||||||
|
self.notify_property_value_change('%(prop)s', old, val)
|
||||||
|
return
|
||||||
|
""" % {'setter':setter_name, 'prop':prop_name}
|
||||||
|
|
||||||
|
pass #end of class
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from gobject import GObjectMeta
|
||||||
|
class ObservablePropertyGObjectMeta (ObservablePropertyMeta, GObjectMeta): pass
|
||||||
|
except:
|
||||||
|
class ObservablePropertyGObjectMeta (ObservablePropertyMeta): pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
152
mvc/gtkmvc/support/wrappers.py
Normal file
152
mvc/gtkmvc/support/wrappers.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
import new
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ObsWrapperBase (object):
|
||||||
|
def __init__(self):
|
||||||
|
self.__prop_name = None
|
||||||
|
self.__gtkmvc_model = None
|
||||||
|
return
|
||||||
|
|
||||||
|
def __set_model__(self, model, prop_name):
|
||||||
|
self.__prop_name = prop_name
|
||||||
|
self.__gtkmvc_model = model
|
||||||
|
return
|
||||||
|
|
||||||
|
def __get_prop_name__(self): return self.__prop_name
|
||||||
|
def __get_model__(self): return self.__gtkmvc_model
|
||||||
|
|
||||||
|
def _notify_method_before(self, instance, name, args, kwargs):
|
||||||
|
self.__get_model__().notify_method_before_change(self.__prop_name,
|
||||||
|
instance,
|
||||||
|
name, args, kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
|
def _notify_method_after(self, instance, name, res_val, args, kwargs):
|
||||||
|
self.__get_model__().notify_method_after_change(self.__prop_name,
|
||||||
|
instance,
|
||||||
|
name, res_val, args, kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ObsWrapper (ObsWrapperBase):
|
||||||
|
|
||||||
|
def __init__(self, obj, method_names):
|
||||||
|
ObsWrapperBase.__init__(self)
|
||||||
|
|
||||||
|
self._obj = obj
|
||||||
|
self.__doc__ = obj.__doc__
|
||||||
|
|
||||||
|
for name in method_names:
|
||||||
|
if hasattr(self._obj, name) and not hasattr(self, name):
|
||||||
|
src = self.__get_wrapper_code(name)
|
||||||
|
exec src
|
||||||
|
|
||||||
|
code = eval("%s.func_code" % name)
|
||||||
|
func = new.function(code, globals())
|
||||||
|
meth = new.instancemethod(func, self, type(self).__name__)
|
||||||
|
setattr(self, name, meth)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def __get_wrapper_code(self, name):
|
||||||
|
return """def %(name)s(self, *args, **kwargs):
|
||||||
|
self._notify_method_before(self._obj, "%(name)s", args, kwargs)
|
||||||
|
res = self._obj.%(name)s(*args, **kwargs)
|
||||||
|
self._notify_method_after(self._obj, "%(name)s", res, args, kwargs)
|
||||||
|
return res""" % {'name' : name}
|
||||||
|
|
||||||
|
# For all fall backs
|
||||||
|
def __getattr__(self, name): return self._obj.__getattr__(name)
|
||||||
|
def __repr__(self): return self._obj.__repr__()
|
||||||
|
def __str__(self): return self._obj.__str__()
|
||||||
|
|
||||||
|
pass #end of class
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ObsSeqWrapper (ObsWrapper):
|
||||||
|
def __init__(self, obj, method_names):
|
||||||
|
ObsWrapper.__init__(self, obj, method_names)
|
||||||
|
return
|
||||||
|
|
||||||
|
def __setitem__(self, key, val):
|
||||||
|
|
||||||
|
self._notify_method_before(self._obj, "__setitem__", (key,val), {})
|
||||||
|
res = self._obj.__setitem__(key, val)
|
||||||
|
self._notify_method_after(self._obj, res, "__setitem__", (key,val), {})
|
||||||
|
return res
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
self._notify_method_before(self._obj, "__delitem__", (key,), {})
|
||||||
|
res = self._obj.__delitem__(key)
|
||||||
|
self._notify_method_after(self._obj, res, "__delitem__", (key,), {})
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._obj.__getitem__(key)
|
||||||
|
|
||||||
|
pass #end of class
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ObsMapWrapper (ObsSeqWrapper):
|
||||||
|
def __init__(self, m):
|
||||||
|
methods = ("clear", "pop", "popitem", "update",
|
||||||
|
"setdefault")
|
||||||
|
ObsSeqWrapper.__init__(self, m, methods)
|
||||||
|
return
|
||||||
|
pass #end of class
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ObsListWrapper (ObsSeqWrapper):
|
||||||
|
def __init__(self, l):
|
||||||
|
methods = ("append", "extend", "insert",
|
||||||
|
"pop", "remove", "reverse", "sort")
|
||||||
|
ObsSeqWrapper.__init__(self, l, methods)
|
||||||
|
return
|
||||||
|
pass #end of class
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class ObsUserClassWrapper (ObsWrapper):
|
||||||
|
def __init__(self, user_class_instance, obs_method_names):
|
||||||
|
ObsWrapper.__init__(self, user_class_instance, obs_method_names)
|
||||||
|
return
|
||||||
|
pass #end of class
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
158
mvc/gtkmvc/view.py
Normal file
158
mvc/gtkmvc/view.py
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author Roberto Cavada <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
import gtk.glade
|
||||||
|
from controller import Controller
|
||||||
|
import types
|
||||||
|
|
||||||
|
class View (object):
|
||||||
|
|
||||||
|
def __init__(self, controller, glade_filename=None,
|
||||||
|
glade_top_widget_name=None, parent_view=None, register=True):
|
||||||
|
"""If register is False you *must* call 'controller.register_view(self)'
|
||||||
|
from the derived class constructor (i.e. registration is delayed)
|
||||||
|
If filename is not given (or None) all following parameters must be
|
||||||
|
not given (or None). In that case widgets must be connected manually.
|
||||||
|
glade_top_widget_name can be either a string name or list of names."""
|
||||||
|
self.manualWidgets = {}
|
||||||
|
self.xmlWidgets = []
|
||||||
|
|
||||||
|
if (( type(glade_top_widget_name) == types.StringType)
|
||||||
|
or (glade_top_widget_name is None) ):
|
||||||
|
wids = (glade_top_widget_name,)
|
||||||
|
else: wids = glade_top_widget_name # Already a list or tuple
|
||||||
|
|
||||||
|
if (glade_filename is not None):
|
||||||
|
for i in range(0,len(wids)):
|
||||||
|
self.xmlWidgets.append(gtk.glade.XML(glade_filename, wids[i]))
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
# top widget list or singleton:
|
||||||
|
if (glade_top_widget_name is not None):
|
||||||
|
if len(wids) > 1:
|
||||||
|
self.m_topWidget = []
|
||||||
|
for i in range(0, len(wids)):
|
||||||
|
self.m_topWidget.append(self[wids[i]])
|
||||||
|
pass
|
||||||
|
else: self.m_topWidget = self[wids[0]]
|
||||||
|
else: self.m_topWidget = None
|
||||||
|
|
||||||
|
if (glade_filename is not None): self.autoconnect_signals(controller)
|
||||||
|
if (register): controller.register_view(self)
|
||||||
|
if (not parent_view is None): self.set_parent_view(parent_view)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Gives us the ability to do: view['widget_name'].action()
|
||||||
|
# Returns None if no widget name has been found.
|
||||||
|
def __getitem__(self, key):
|
||||||
|
wid = None
|
||||||
|
for xml in self.xmlWidgets:
|
||||||
|
wid = xml.get_widget(key)
|
||||||
|
if wid is not None: break
|
||||||
|
pass
|
||||||
|
|
||||||
|
if (wid is None):
|
||||||
|
# try with manually-added widgets:
|
||||||
|
if (self.manualWidgets.has_key(key)):
|
||||||
|
wid = self.manualWidgets[key]
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
return wid
|
||||||
|
|
||||||
|
# You can also add a single widget:
|
||||||
|
def __setitem__(self, key, wid):
|
||||||
|
self.manualWidgets[key] = wid
|
||||||
|
if (self.m_topWidget is None): self.m_topWidget = wid
|
||||||
|
return
|
||||||
|
|
||||||
|
# performs Controller's signals auto-connection:
|
||||||
|
def autoconnect_signals(self, controller):
|
||||||
|
dict = {}
|
||||||
|
member_names = dir(controller)
|
||||||
|
for name in member_names:
|
||||||
|
method = getattr(controller, name)
|
||||||
|
if (not callable(method)): continue
|
||||||
|
assert(not dict.has_key(name)) # not already connected!
|
||||||
|
dict[name] = method
|
||||||
|
pass
|
||||||
|
|
||||||
|
for xml in self.xmlWidgets: xml.signal_autoconnect(dict)
|
||||||
|
return
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
ret = True
|
||||||
|
top = self.get_top_widget()
|
||||||
|
if type(top) in (types.ListType, types.TupleType):
|
||||||
|
for t in top:
|
||||||
|
if t is not None: ret = ret and t.show()
|
||||||
|
pass
|
||||||
|
elif (top is not None): ret = top.show_all()
|
||||||
|
else: ret = False
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def hide(self):
|
||||||
|
top = self.get_top_widget()
|
||||||
|
if type(top) in (types.ListType, types.TupleType):
|
||||||
|
for t in top:
|
||||||
|
if t is not None: t.hide_all()
|
||||||
|
pass
|
||||||
|
elif top is not None: top.hide_all()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Returns the top-level widget, or a list of top widgets
|
||||||
|
def get_top_widget(self):
|
||||||
|
return self.m_topWidget
|
||||||
|
|
||||||
|
|
||||||
|
# Set parent view:
|
||||||
|
def set_parent_view(self, parent_view):
|
||||||
|
top = self.get_top_widget()
|
||||||
|
if type(top) in (types.ListType, types.TupleType):
|
||||||
|
for t in top:
|
||||||
|
if t is not None:
|
||||||
|
t.set_transient_for(parent_view.get_top_widget())
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
elif (top is not None):
|
||||||
|
top.set_transient_for(parent_view.get_top_widget())
|
||||||
|
pass
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set the transient for the view:
|
||||||
|
def set_transient(self, transient_view):
|
||||||
|
top = self.get_top_widget()
|
||||||
|
if type(top) in (types.ListType, types.TupleType):
|
||||||
|
for t in top:
|
||||||
|
if t is not None:
|
||||||
|
transient_view.get_top_widget().set_transient_for(t)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
elif (top is not None):
|
||||||
|
transient_view.get_top_widget().set_transient_for(top)
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
pass # end of class View
|
||||||
BIN
mvc/img/notavail.gif
Normal file
BIN
mvc/img/notavail.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
24
mvc/main_window.py
Normal file
24
mvc/main_window.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# This Python file uses the following encoding: utf-8
|
||||||
|
def setup_path():
|
||||||
|
"""Sets up the python include paths to include src"""
|
||||||
|
import os.path; import sys
|
||||||
|
|
||||||
|
if sys.argv[0]:
|
||||||
|
top_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||||
|
sys.path = [os.path.join(top_dir, "src")] + sys.path
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
setup_path()
|
||||||
|
|
||||||
|
from models.m_main import MainModel
|
||||||
|
from controllers.c_main import MainController
|
||||||
|
from views.v_main import MainView
|
||||||
|
m = MainModel()
|
||||||
|
c = MainController(m)
|
||||||
|
v = MainView(c)
|
||||||
|
|
||||||
|
import gtk
|
||||||
|
gtk.main()
|
||||||
|
pass
|
||||||
BIN
mvc/pixmaps/mainicon.png
Normal file
BIN
mvc/pixmaps/mainicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
mvc/pixmaps/mainicon.xcf
Normal file
BIN
mvc/pixmaps/mainicon.xcf
Normal file
Binary file not shown.
BIN
mvc/pixmaps/mainicon2.xcf
Normal file
BIN
mvc/pixmaps/mainicon2.xcf
Normal file
Binary file not shown.
6
mvc/pyGTKtalog
Executable file
6
mvc/pyGTKtalog
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Simple wraper to launch python application from desired place.
|
||||||
|
cd ~/Python/pyGTKtalog/mvc
|
||||||
|
#export PYTHONPATH="$PYTHONPATH:/usr/lib/gajim"
|
||||||
|
#exec python -OO pyGTKtalog.py $@
|
||||||
|
exec python main_window.py $@
|
||||||
3
mvc/src/__init__.py
Normal file
3
mvc/src/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
__all__ = ["models", "views", "controllers", "utils"]
|
||||||
0
mvc/src/controllers/__init__.py
Normal file
0
mvc/src/controllers/__init__.py
Normal file
38
mvc/src/controllers/c_main.py
Normal file
38
mvc/src/controllers/c_main.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# This Python file uses the following encoding: utf-8
|
||||||
|
|
||||||
|
import utils._importer
|
||||||
|
import utils.globals
|
||||||
|
from gtkmvc import Controller
|
||||||
|
import gtk
|
||||||
|
|
||||||
|
class MainController(Controller):
|
||||||
|
"""Kontroler głównego okna aplikacji"""
|
||||||
|
def __init__(self, model):
|
||||||
|
Controller.__init__(self, model)
|
||||||
|
return
|
||||||
|
|
||||||
|
def register_view(self, view):
|
||||||
|
Controller.register_view(self, view)
|
||||||
|
|
||||||
|
# ustaw domyślne wartości dla poszczególnych widżetów
|
||||||
|
self.view['main'].set_title('pyGTKtalog');
|
||||||
|
self.view['main'].set_icon_list(gtk.gdk.pixbuf_new_from_file("pixmaps/mainicon.png"))
|
||||||
|
|
||||||
|
# pokaż główne okno
|
||||||
|
self.view['main'].show();
|
||||||
|
return
|
||||||
|
|
||||||
|
# Podłącz sygnały:
|
||||||
|
def on_main_destroy_event(self, window, event):
|
||||||
|
gtk.main_quit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def on_tb_quit_clicked(self,toolbutton):
|
||||||
|
gtk.main_quit()
|
||||||
|
|
||||||
|
def on_quit1_activate(self,button):
|
||||||
|
gtk.main_quit()
|
||||||
|
|
||||||
|
# Obserwowalne właściwości
|
||||||
|
|
||||||
|
pass # end of class
|
||||||
0
mvc/src/models/__init__.py
Normal file
0
mvc/src/models/__init__.py
Normal file
18
mvc/src/models/m_main.py
Normal file
18
mvc/src/models/m_main.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# This Python file uses the following encoding: utf-8
|
||||||
|
|
||||||
|
import utils._importer
|
||||||
|
import utils.globals
|
||||||
|
from gtkmvc import Model
|
||||||
|
|
||||||
|
class MainModel(Model):
|
||||||
|
"""Our model contains a numeric counter and a numeric value that
|
||||||
|
holds the value that the counter must be assigned to when we the
|
||||||
|
model is reset"""
|
||||||
|
|
||||||
|
__properties__ = {}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Model.__init__(self)
|
||||||
|
return
|
||||||
|
|
||||||
|
pass # end of class
|
||||||
3
mvc/src/utils/__init__.py
Normal file
3
mvc/src/utils/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
__all__ = ["globals", "_importer"]
|
||||||
44
mvc/src/utils/_importer.py
Normal file
44
mvc/src/utils/_importer.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ======================================================================
|
||||||
|
# This module is used only as a utility to import gtkmvc when not
|
||||||
|
# installed.
|
||||||
|
|
||||||
|
import utils.globals
|
||||||
|
|
||||||
|
if __name__ != "__main__":
|
||||||
|
try: import gtkmvc
|
||||||
|
except:
|
||||||
|
import os.path; import sys
|
||||||
|
|
||||||
|
rel_path = os.path.join(utils.globals.TOP_DIR, "..")
|
||||||
|
top_dir = os.path.dirname(os.path.abspath(rel_path))
|
||||||
|
sys.path = [top_dir] + sys.path
|
||||||
|
import gtkmvc
|
||||||
|
pass
|
||||||
|
|
||||||
|
gtkmvc.require("1.0.0")
|
||||||
|
pass
|
||||||
|
|
||||||
33
mvc/src/utils/globals.py
Normal file
33
mvc/src/utils/globals.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Author: Roberto Cavada <cavada@irst.itc.it>
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 by Roberto Cavada
|
||||||
|
#
|
||||||
|
# pygtkmvc is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# pygtkmvc 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
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
#
|
||||||
|
# For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
|
||||||
|
# or email to the author <cavada@irst.itc.it>.
|
||||||
|
# Please report bugs to <cavada@irst.itc.it>.
|
||||||
|
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.argv[0]: top_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||||
|
else: top_dir = "."
|
||||||
|
|
||||||
|
|
||||||
|
# A set of global vars
|
||||||
|
TOP_DIR = top_dir
|
||||||
|
GLADE_DIR = os.path.join(TOP_DIR, "glade")
|
||||||
0
mvc/src/views/__init__.py
Normal file
0
mvc/src/views/__init__.py
Normal file
17
mvc/src/views/v_main.py
Normal file
17
mvc/src/views/v_main.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# This Python file uses the following encoding: utf-8
|
||||||
|
|
||||||
|
import utils._importer
|
||||||
|
import utils.globals
|
||||||
|
from gtkmvc import View
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
class MainView(View):
|
||||||
|
"""This handles only the graphical representation of the
|
||||||
|
application. The widgets set is loaded from glade file"""
|
||||||
|
|
||||||
|
GLADE = os.path.join(utils.globals.GLADE_DIR, "main.glade")
|
||||||
|
def __init__(self, ctrl):
|
||||||
|
View.__init__(self, ctrl, self.GLADE)
|
||||||
|
return
|
||||||
|
|
||||||
|
pass # end of class
|
||||||
Reference in New Issue
Block a user