1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 # gpodder.gtkui.config -- Config object with GTK+ support (2009-08-24)
30 from gpodder
import util
31 from gpodder
import config
35 class ConfigModel(gtk
.ListStore
):
36 C_NAME
, C_TYPE_TEXT
, C_VALUE_TEXT
, C_TYPE
, C_EDITABLE
, C_FONT_STYLE
, \
37 C_IS_BOOLEAN
, C_BOOLEAN_VALUE
= range(8)
39 def __init__(self
, config
):
40 gtk
.ListStore
.__init
__(self
, str, str, str, object, \
41 bool, int, bool, bool)
46 self
._config
.add_observer(self
._on
_update
)
48 def _type_as_string(self
, type):
58 def _fill_model(self
):
60 for key
in sorted(self
._config
.Settings
):
61 fieldtype
, default
= self
._config
.Settings
[key
][:2]
62 value
= getattr(self
._config
, key
, default
)
65 style
= pango
.STYLE_NORMAL
67 style
= pango
.STYLE_ITALIC
69 self
.append((key
, self
._type
_as
_string
(fieldtype
), \
70 str(value
), fieldtype
, fieldtype
is not bool, style
, \
71 fieldtype
is bool, bool(value
)))
73 def _on_update(self
, name
, old_value
, new_value
):
75 if row
[self
.C_NAME
] == name
:
76 if new_value
== self
._config
.Settings
[name
][1]:
77 style
= pango
.STYLE_NORMAL
79 style
= pango
.STYLE_ITALIC
81 self
.C_VALUE_TEXT
, str(new_value
), \
82 self
.C_BOOLEAN_VALUE
, bool(new_value
), \
83 self
.C_FONT_STYLE
, style
)
86 def stop_observing(self
):
87 self
._config
.remove_observer(self
._on
_update
)
89 class UIConfig(config
.Config
):
90 def __init__(self
, filename
='gpodder.conf'):
91 config
.Config
.__init
__(self
, filename
)
92 self
.__ignore
_window
_events
= False
94 def connect_gtk_editable(self
, name
, editable
):
95 assert name
in self
.Settings
96 editable
.delete_text(0, -1)
97 editable
.insert_text(str(getattr(self
, name
)))
99 def _editable_changed(editable
):
100 setattr(self
, name
, editable
.get_chars(0, -1))
101 editable
.connect('changed', _editable_changed
)
103 def connect_gtk_spinbutton(self
, name
, spinbutton
):
104 assert name
in self
.Settings
105 spinbutton
.set_value(getattr(self
, name
))
107 def _spinbutton_changed(spinbutton
):
108 setattr(self
, name
, spinbutton
.get_value())
109 spinbutton
.connect('value-changed', _spinbutton_changed
)
111 def connect_gtk_paned(self
, name
, paned
):
112 assert name
in self
.Settings
113 paned
.set_position(getattr(self
, name
))
114 paned_child
= paned
.get_child1()
116 def _child_size_allocate(x
, y
):
117 setattr(self
, name
, paned
.get_position())
118 paned_child
.connect('size-allocate', _child_size_allocate
)
120 def connect_gtk_togglebutton(self
, name
, togglebutton
):
121 assert name
in self
.Settings
122 togglebutton
.set_active(getattr(self
, name
))
124 def _togglebutton_toggled(togglebutton
):
125 setattr(self
, name
, togglebutton
.get_active())
126 togglebutton
.connect('toggled', _togglebutton_toggled
)
128 def connect_gtk_filechooser(self
, name
, filechooser
, is_for_files
=False):
129 assert name
in self
.Settings
131 # FIXME: can we determine "is_for_files" by consulting the filechooser?
133 # A FileChooser for a single file
134 filechooser
.set_filename(getattr(self
, name
))
136 # A FileChooser for a folder
137 filechooser
.set_current_folder(getattr(self
, name
))
139 def _chooser_selection_changed(filechooser
):
140 filename
= filechooser
.get_filename()
141 if filename
is not None:
142 setattr(self
, name
, filename
)
144 filechooser
.connect('selection-changed', _chooser_selection_changed
)
146 def connect_gtk_window(self
, window
, config_prefix
, show_window
=False):
147 x
, y
, width
, height
, maximized
= map(lambda x
: config_prefix
+'_'+x
, \
148 ('x', 'y', 'width', 'height', 'maximized'))
150 if set((x
, y
, width
, height
)).issubset(set(self
.Settings
)):
151 window
.resize(getattr(self
, width
), getattr(self
, height
))
152 if getattr(self
, x
) == -1 or getattr(self
, y
) == -1:
153 window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
155 window
.move(getattr(self
, x
), getattr(self
, y
))
157 # Ignore events while we're connecting to the window
158 self
.__ignore
_window
_events
= True
160 def _receive_configure_event(widget
, event
):
161 x_pos
, y_pos
= widget
.get_position()
162 width_size
, height_size
= widget
.get_size()
163 if not self
.__ignore
_window
_events
and not \
164 (hasattr(self
, maximized
) and getattr(self
, maximized
)):
165 setattr(self
, x
, x_pos
)
166 setattr(self
, y
, y_pos
)
167 setattr(self
, width
, width_size
)
168 setattr(self
, height
, height_size
)
170 window
.connect('configure-event', _receive_configure_event
)
172 def _receive_window_state(widget
, event
):
173 new_value
= bool(event
.new_window_state
& \
174 gtk
.gdk
.WINDOW_STATE_MAXIMIZED
)
175 if hasattr(self
, maximized
):
176 setattr(self
, maximized
, new_value
)
178 window
.connect('window-state-event', _receive_window_state
)
180 # After the window has been set up, we enable events again
181 def _enable_window_events():
182 self
.__ignore
_window
_events
= False
183 util
.idle_add(_enable_window_events
)
187 if getattr(self
, maximized
, False):
190 raise ValueError('Cannot connect %s', config_prefix
, sender
=self
)