1
# Copyright (C) 2005 Dan Loda <danloda@gmail.com>
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from gi.repository import GObject
19
from gi.repository import Gtk
25
SPAN_IS_SEPARATOR_COL,
30
class SpanSelector(Gtk.HBox):
31
"""Encapsulates creation and functionality of widgets used for changing
34
Note that calling any activate_* methods will emit "span-changed".
41
def __init__(self, homogeneous=False, spacing=6):
42
super(SpanSelector, self).__init__(
43
homogeneous=homogeneous, spacing=spacing)
45
self.model = self._create_model()
46
self.combo = self._create_combobox(self.model)
47
self.entry = self._create_custom_entry()
49
label = Gtk.Label(label="Highlighting spans:")
52
self.pack_start(label, False, True, True, 0)
53
self.pack_start(self.combo, False, False, True, 0)
54
self.pack_start(self.entry, False, False, True, 0)
56
def set_to_oldest_span(self, span):
57
"""Set the span associated with the "to Oldest Revision" entry."""
58
self.model.set_value(self.oldest_iter, SPAN_DAYS_COL, span)
60
def set_newest_to_oldest_span(self, span):
61
"""Set the span associated with the "Newest to Oldset" entry."""
62
self.model.set_value(self.newest_iter, SPAN_DAYS_COL, span)
64
def set_max_custom_spans(self, n):
65
"""Store up to n custom span entries in the combo box."""
66
self.max_custom_spans = n
68
def activate(self, iter):
69
"""Activate the row pointed to by Gtk.TreeIter iter."""
70
index = self._get_index_from_iter(iter)
71
self.combo.set_active(index)
73
def activate_last_selected(self):
74
"""Activate the previously selected row.
76
Expected to be used when cancelling custom entry or revieved bad
79
if self.last_selected:
80
self.activate(self.last_selected)
82
def activate_default(self):
83
"""Activate the default row."""
84
# TODO allow setting of default?
85
self.activate(self.oldest_iter)
87
def _get_index_from_iter(self, iter):
88
"""Returns a row index integer from iterator."""
89
return int(self.model.get_string_from_iter(iter))
91
def _combo_changed_cb(self, w):
93
iter = w.get_active_iter()
95
if model.get_value(iter, SPAN_IS_CUSTOM_COL):
96
self._request_custom_span()
98
self.last_selected = iter
99
self.emit("span-changed", model.get_value(iter, SPAN_DAYS_COL))
101
def _activate_custom_span_cb(self, w):
105
span = float(w.get_text())
108
# FIXME this works as "cancel", returning to the previous span,
109
# but it emits "span-changed", which isn't necessary.
110
self.activate_last_selected()
113
self.add_custom_span(span)
114
self.emit("custom-span-added", span)
116
self.activate(self.custom_iter)
118
def add_custom_span(self, span):
119
if not len(self.custom_spans):
120
self.custom_iter = self.model.insert_after(self.custom_iter,
122
self.custom_iter_top = self.custom_iter.copy()
124
if len(self.custom_spans) == self.max_custom_spans:
125
self.custom_spans.pop(0)
126
self.model.remove(self.model.iter_next(self.custom_iter_top))
128
self.custom_spans.append(span)
129
self.custom_iter = self.model.insert_after(
130
self.custom_iter, [span, "%.2f Days" % span, False, False])
132
def _request_custom_span(self):
134
self.entry.show_all()
136
def _create_model(self):
137
# [span in days, span as string, row is seperator?, row is select
139
m = Gtk.ListStore(GObject.TYPE_FLOAT,
141
GObject.TYPE_BOOLEAN,
142
GObject.TYPE_BOOLEAN)
144
self.separator = [0., "", True, False]
146
self.oldest_iter = m.append([0., "to Oldest Revision", False, False])
147
self.newest_iter = m.append([0., "Newest to Oldest", False, False])
148
m.append(self.separator)
149
m.append([1., "1 Day", False, False])
150
m.append([7., "1 Week", False, False])
151
m.append([30., "1 Month", False, False])
152
self.custom_iter = m.append([365., "1 Year", False, False])
153
m.append(self.separator)
154
m.append([0., "Custom...", False, True])
158
def _create_combobox(self, model):
159
cb = Gtk.ComboBox(model)
160
cb.set_row_separator_func(
161
lambda m, i: m.get_value(i, SPAN_IS_SEPARATOR_COL))
162
cell = Gtk.CellRendererText()
163
cb.pack_start(cell, False)
164
cb.add_attribute(cell, "text", SPAN_STR_COL)
165
cb.connect("changed", self._combo_changed_cb)
170
def _create_custom_entry(self):
171
entry = Gtk.HBox(False, 6)
173
spin = Gtk.SpinButton(digits=2)
174
spin.set_numeric(True)
175
spin.set_increments(1., 10.)
176
spin.set_range(0., 100 * 365) # I presume 100 years is sufficient
177
spin.connect("activate", self._activate_custom_span_cb)
178
spin.connect("show", lambda w: w.grab_focus())
180
label = Gtk.Label(label="Days")
182
entry.pack_start(spin, False, False, True, 0)
183
entry.pack_start(label, False, False, True, 0)
188
"""The "span-changed" signal is emitted when a new span has been selected or
191
Callback signature: def callback(SpanSelector, span, [user_param, ...])
193
GObject.signal_new("span-changed", SpanSelector,
194
GObject.SignalFlags.RUN_LAST,
196
(GObject.TYPE_FLOAT,))
198
"""The "custom-span-added" signal is emitted after a custom span has been
199
added, but before it has been selected.
201
Callback signature: def callback(SpanSelector, span, [user_param, ...])
203
GObject.signal_new("custom-span-added", SpanSelector,
204
GObject.SignalFlags.RUN_LAST,
206
(GObject.TYPE_FLOAT,))