1
0
mirror of https://github.com/gryf/pygtktalog.git synced 2025-12-17 19:40:21 +01:00

* New version using pygtkmvc framework.

This commit is contained in:
2007-05-01 19:30:22 +00:00
parent 45859e1a3d
commit f695f82c1f
30 changed files with 2232 additions and 0 deletions

130
mvc/glade/foo.glade Normal file
View 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">&lt;b&gt;frame1&lt;/b&gt;</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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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"]

View 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

View 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
# ----------------------------------------------------------------------

View 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

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

24
mvc/main_window.py Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
mvc/pixmaps/mainicon.xcf Normal file

Binary file not shown.

BIN
mvc/pixmaps/mainicon2.xcf Normal file

Binary file not shown.

6
mvc/pyGTKtalog Executable file
View 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
View File

@@ -0,0 +1,3 @@
__all__ = ["models", "views", "controllers", "utils"]

View File

View 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

View File

18
mvc/src/models/m_main.py Normal file
View 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

View File

@@ -0,0 +1,3 @@
__all__ = ["globals", "_importer"]

View 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
View 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")

View File

17
mvc/src/views/v_main.py Normal file
View 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