Yet another fixes to tree view manipulation...
[straw.git] / straw / model / __init__.py
blobda06345c26af8fc1f796bcab41b2d5ec7ffb7176
1 from bisect import insort
2 from gobject import GObject
3 from straw.error import debug
4 import gobject
5 import straw
7 class AsyncGObject(gobject.GObject):
8 def __init__(self):
9 gobject.GObject.__init__(self)
11 def emit(self, *args):
12 gobject.idle_add(gobject.GObject.emit, self, *args)
14 class Node(gobject.GObject):
15 """
16 Represents a base of single node in the model tree. This class is meant
17 for subclassing only, Node instances should not be used.
18 """
20 persistent_properties = [ "id", "parent_id", "type", "norder" ]
21 persistent_table = "nodes"
22 primary_key = "id"
24 __gproperties__ = {
25 "norder": (int, "parent_id", "norder", 0, 999999, 0, gobject.PARAM_READWRITE),
26 "parent": (gobject.TYPE_PYOBJECT, "parent", "parent", gobject.PARAM_READWRITE),
27 "unread-count": (int, "unread-count", "unread-count", 0, 999999, 0, gobject.PARAM_READWRITE)
30 __gsignals__ = {
31 "parent-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
32 "norder-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
33 "unread-count-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT))
36 def __init__(self):
37 GObject.__init__(self)
38 self.id = None
39 self.parent_id = None
40 self.unread_count = 0
41 self.norder = 0
42 self.children = []
43 self.handler_ids_unread_changed = {}
45 def __cmp__(self, other):
46 if other == None:
47 return -1
48 elif self.norder == other.norder:
49 return 0
50 elif self.norder < other.norder:
51 return -1
52 else:
53 return 1
55 def do_get_property(self, property):
56 if property.name == "norder":
57 return self.norder
58 elif property.name == "parent_id":
59 return self.parent_id
60 elif property.name == "unread-count":
61 return self.unread_count
63 def do_set_property(self, property, value):
64 if property.name == "unread-count":
65 if value == None:
66 value = 0
68 if self.unread_count != value:
69 delta = value - self.unread_count
70 old_value = self.unread_count
71 self.unread_count = value
72 self.emit("unread-count-changed", old_value, delta)
73 elif property.name == "norder":
74 if self.norder != value:
75 old_value = self.norder
76 self.norder = value
77 self.emit("norder-changed", old_value)
78 elif property.name == "parent":
79 if self.parent.id != value.id:
80 old_value = self.parent
81 self.parent = value
82 self.parent_id = value.id
83 self.emit("parent-changed", old_value)
85 def add_child(self, node, norder = None, allow_append = True, emit_changes = True):
86 debug("adding %d to %d with node.norder = %d, norder = %s" % (node.id, self.id, node.norder, str(norder)))
87 if allow_append:
88 if norder == None or norder >= len(self.children):
89 norder = len(self.children)
90 else:
91 if node.parent == self:
92 if norder > len(self.children):
93 norder = len(self.children)#raise AttributeError
95 if norder == None:
96 norder = len(self.children) - 1
97 else:
98 if norder == None:
99 norder = len(self.children)
100 elif norder > len(self.children):
101 norder = len(self.children)
103 if norder < len(self.children):
104 for child in self.children[norder:]:
105 child.props.norder += 1
107 debug("calculated norder = %d" % (norder))
109 node.props.norder = norder
111 self.append_child(node, emit_changes = emit_changes)
113 def append_child(self, node, emit_changes = True):
114 debug("appending %d to %d with norder = %d" % (node.id, self.id, node.norder))
115 insort(self.children, node)
116 self.handler_ids_unread_changed[node.id] = node.connect("unread-count-changed", self.on_unread_count_changed)
118 if emit_changes:
119 self.props.unread_count += node.unread_count
121 def remove_child(self, node, emit_changes = True):
122 debug("removing %d from %d with norder = %d" % (node.id, self.id, node.norder))
123 for child in self.children[(node.norder + 1):]:
124 child.props.norder -= 1
126 self.children.remove(node)
128 node.disconnect(self.handler_ids_unread_changed[node.id])
130 if emit_changes:
131 self.props.unread_count -= node.unread_count
133 def move(self, new_parent, new_norder = None):
134 debug("moving %d to %d (new_norder = %d)" % (self.id, new_parent.id, new_norder))
135 old_parent = self.parent
136 self.parent.remove_child(self, emit_changes = False)
137 new_parent.add_child(self, norder = new_norder, allow_append = False, emit_changes = False)
138 self.props.parent = new_parent
139 debug("changing unread count (old_parent %d: %d -> %d)" % (old_parent.id, old_parent.unread_count, old_parent.unread_count - self.unread_count))
140 debug("changing unread count (new_parent %d: %d -> %d)" % (new_parent.id, new_parent.unread_count, new_parent.unread_count + self.unread_count))
141 old_parent.props.unread_count -= self.unread_count
142 self.parent.props.unread_count += self.unread_count
144 def get_by_path(self, path):
145 #print "sss %d | %s | %s" % (self.id, str(path), str(len(self.children)))
146 if len(path) == 0:
147 return self
148 elif path[0] < len(self.children):
149 #print len(self.children)
150 #print self.children[path[0]].id
151 return self.children[path[0]].get_by_path(path[:-1])
152 else:
153 return None
155 def on_unread_count_changed(self, obj, old_value, delta):
156 pass
158 class Category(Node):
160 Represents a category - a node that can have child nodes.
163 persistent_properties = [ "id", "name" ]
164 persistent_table = "categories"
165 primary_key = None
166 inheritance = True
168 def __init__(self):
169 GObject.__init__(self)
170 Node.__gobject_init__(self)
171 Node.__init__(self)
173 self.id = None
174 self.name = ""
175 self.type = "C"
177 def do_get_property(self, property):
178 if property.name == "title":
179 return self.title
180 else:
181 return Node.do_get_property(self, property)
183 def do_set_property(self, property, value):
184 if property.name == "title":
185 self.title = value
186 else:
187 Node.do_set_property(self, property, value)
189 def on_unread_count_changed(self, obj, old_value, delta):
190 self.props.unread_count += delta
192 class Feed(Node):
194 Represents a feed - a node that can contain items. Feeds cannot have
195 child nodes.
198 persistent_properties = [ "id", "title", "location", "link" ]
199 persistent_table = "feeds"
200 primary_key = None
201 inheritance = True
203 __gproperties__ = {
204 "title": (str, "title", "title", "", gobject.PARAM_READWRITE),
205 "location": (str, "location", "location", "", gobject.PARAM_READWRITE),
206 "status": (int, "status", "status", 0, 9999, 0, gobject.PARAM_READWRITE),
209 def __init__(self):
210 GObject.__init__(self)
211 Node.__gobject_init__(self)
212 Node.__init__(self)
214 self.id = None
215 self.type = "F"
216 self.items = []
218 def add_child(self, node, norder = None, allow_append = True):
219 debug("tried to add child to a feed %d!" % self.id)
221 def do_get_property(self, property):
222 if property.name == "title":
223 return self.title
224 elif property.name == "location":
225 return self.title
226 elif property.name == "status":
227 return self.status
228 else:
229 return Node.do_get_property(self, property)
231 def do_set_property(self, property, value):
232 if property.name == "title":
233 self.title = value
234 elif property.name == "location":
235 self.location = value
236 elif property.name == "status":
237 self.status = value
238 else:
239 Node.do_set_property(self, property, value)
241 def on_unread_count_changed(self, obj, old_value, delta):
242 pass
244 def add_item(self, item):
245 self.items.append(item)
247 def on_is_read_changed(self, obj, is_read):
248 if is_read:
249 self.props.unread_count -= 1
250 else:
251 self.props.unread_count += 1
253 class Item(GObject):
254 persistent_properties = [ "id", "title", "feed_id", "is_read", "link", "pub_date", "description" ]
255 persistent_table = "items"
256 primary_key = "id"
258 __gproperties__ = {
259 "title": (str, "title", "title", "", gobject.PARAM_READWRITE),
260 "location": (str, "location", "location", "", gobject.PARAM_READWRITE),
261 "is-read": (gobject.TYPE_BOOLEAN, "is-read", "is-read", False, gobject.PARAM_READWRITE)
264 __gsignals__ = {
265 "is-read-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
268 def __init__(self):
269 GObject.__init__(self)
270 self.id = None
271 self.title = ""
272 self.feed_id = None
273 self.is_read = False
275 self.link = "link"
276 self.pub_date = None
277 self.description = "description"
278 self.source = None
279 self.guid = "guid"
280 self.guidislink = False
282 self.publication_name = "publication_name"
283 self.publication_volume = "publication_volume"
284 self.publication_number = "publication_number"
285 self.publication_section = "publication_section"
286 self.publication_starting_page = "publication_starting_page"
288 self.fm_license = "fm_license"
289 self.fm_changes = "fm_changes"
291 self.creator = "creator"
293 self.contributors = []
294 self.enclosures = []
295 self.license_urls = []
297 def do_get_property(self, property):
298 if property.name == "title":
299 return self.title
300 elif property.name == "is-read":
301 return self.is_read
302 else:
303 raise AttributeError, "unknown property %s" % property.name
305 def do_set_property(self, property, value):
306 if property.name == "title":
307 self.title = value
308 elif property.name == "is-read":
309 old_value = bool(self.is_read)
310 self.is_read = value
311 if old_value != value:
312 self.emit("is-read-changed", int(value))
313 else:
314 raise AttributeError, "unknown property %s" % property.name