Cleaned up item view.
[straw.git] / straw / model / __init__.py
blobe00687ebd9b128405c8846da9956ad6b00552753
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"
23 pdict_table = "node_pdict_entries"
25 __gproperties__ = {
26 "norder": (int, "parent_id", "norder", 0, 999999, 0, gobject.PARAM_READWRITE),
27 "parent": (gobject.TYPE_PYOBJECT, "parent", "parent", gobject.PARAM_READWRITE),
28 "unread-count": (int, "unread-count", "unread-count", 0, 999999, 0, gobject.PARAM_READWRITE)
31 __gsignals__ = {
32 "parent-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
33 "norder-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
34 "unread-count-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
35 "mark-all-items-as-read": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())
38 def __init__(self):
39 GObject.__init__(self)
40 self.id = None
41 self.parent_id = None
42 self.unread_count = 0
43 self.norder = 0
44 self.children = []
45 self.handler_ids_unread_changed = {}
46 self.pdict = {}
48 def __cmp__(self, other):
49 if other == None:
50 return -1
51 elif self.norder == other.norder:
52 return 0
53 elif self.norder < other.norder:
54 return -1
55 else:
56 return 1
58 def do_get_property(self, property):
59 if property.name == "norder":
60 return self.norder
61 elif property.name == "parent_id":
62 return self.parent_id
63 elif property.name == "unread-count":
64 return self.unread_count
66 def do_set_property(self, property, value):
67 if property.name == "unread-count":
68 if value == None:
69 value = 0
71 if self.unread_count != value:
72 delta = value - self.unread_count
73 old_value = self.unread_count
74 self.unread_count = value
75 self.emit("unread-count-changed", old_value, delta)
76 elif property.name == "norder":
77 if self.norder != value:
78 old_value = self.norder
79 self.norder = value
80 self.emit("norder-changed", old_value)
81 elif property.name == "parent":
82 if self.parent.id != value.id:
83 old_value = self.parent
84 self.parent = value
85 self.parent_id = value.id
86 self.emit("parent-changed", old_value)
88 def is_parent(self):
89 raise NotImplementedError
91 def add_child(self, node, norder = None, allow_append = True, emit_changes = True):
92 debug("adding %d to %d with node.norder = %d, norder = %s" % (node.id, self.id, node.norder, str(norder)))
93 if allow_append:
94 if norder == None or norder >= len(self.children):
95 norder = len(self.children)
96 else:
97 if node.parent == self:
98 if norder > len(self.children):
99 norder = len(self.children)#raise AttributeError
101 if norder == None:
102 norder = len(self.children) - 1
103 else:
104 if norder == None:
105 norder = len(self.children)
106 elif norder > len(self.children):
107 norder = len(self.children)
109 if norder < len(self.children):
110 for child in self.children[norder:]:
111 child.props.norder += 1
113 debug("calculated norder = %d" % (norder))
115 node.props.norder = norder
117 self.append_child(node, emit_changes = emit_changes)
119 def append_child(self, node, emit_changes = True):
120 #debug("appending %d to %d with norder = %d" % (node.id, self.id, node.norder))
121 insort(self.children, node)
122 self.handler_ids_unread_changed[node.id] = node.connect("unread-count-changed", self.on_unread_count_changed)
124 if emit_changes:
125 self.props.unread_count += node.unread_count
127 def remove_child(self, node, emit_changes = True):
128 debug("removing %d from %d with norder = %d" % (node.id, self.id, node.norder))
129 for child in self.children[(node.norder + 1):]:
130 child.props.norder -= 1
132 self.children.remove(node)
134 node.disconnect(self.handler_ids_unread_changed[node.id])
136 if emit_changes:
137 self.props.unread_count -= node.unread_count
139 def move(self, new_parent, new_norder = None):
140 debug("moving %d to %d (new_norder = %d)" % (self.id, new_parent.id, new_norder))
141 old_parent = self.parent
142 self.parent.remove_child(self, emit_changes = False)
143 new_parent.add_child(self, norder = new_norder, allow_append = False, emit_changes = False)
144 self.props.parent = new_parent
145 debug("changing unread count (old_parent %d: %d -> %d)" % (old_parent.id, old_parent.unread_count, old_parent.unread_count - self.unread_count))
146 debug("changing unread count (new_parent %d: %d -> %d)" % (new_parent.id, new_parent.unread_count, new_parent.unread_count + self.unread_count))
147 old_parent.props.unread_count -= self.unread_count
148 self.parent.props.unread_count += self.unread_count
150 def get_by_path(self, path):
151 #print "sss %d | %s | %s" % (self.id, str(path), str(len(self.children)))
152 if len(path) == 0:
153 return self
154 elif path[0] < len(self.children):
155 return self.children[path[0]].get_by_path(path[1:])
156 else:
157 return None
159 def all_children(self):
160 for child_node in self.children:
161 yield child_node
163 for _child_node in child_node.all_children():
164 yield _child_node
166 def on_unread_count_changed(self, obj, old_value, delta):
167 pass
169 class Category(Node):
171 Represents a category - a node that can have child nodes.
174 persistent_properties = [ "id", "name" ]
175 persistent_table = "categories"
176 primary_key = None
177 inheritance = True
179 def __init__(self):
180 GObject.__init__(self)
181 Node.__gobject_init__(self)
182 Node.__init__(self)
184 self.id = None
185 self.name = ""
186 self.type = "C"
188 def is_parent(self):
189 return True
191 def do_get_property(self, property):
192 if property.name == "title":
193 return self.title
194 else:
195 return Node.do_get_property(self, property)
197 def do_set_property(self, property, value):
198 if property.name == "title":
199 self.title = value
200 else:
201 Node.do_set_property(self, property, value)
203 def on_unread_count_changed(self, obj, old_value, delta):
204 self.props.unread_count += delta
206 def mark_items_as_read(self):
207 for child in self.children:
208 child.mark_items_as_read()
210 class Feed(Node):
212 Represents a feed - a node that can contain items. Feeds cannot have
213 child nodes.
216 persistent_properties = [ "id", "title", "location", "link", "description",
217 "copyright" ]
218 persistent_table = "feeds"
219 primary_key = None
220 inheritance = True
222 __gproperties__ = {
223 "title": (str, "title", "title", "", gobject.PARAM_READWRITE),
224 "location": (str, "location", "location", "", gobject.PARAM_READWRITE),
225 "status": (int, "status", "status", 0, 9999, 0, gobject.PARAM_READWRITE),
228 def __init__(self):
229 GObject.__init__(self)
230 Node.__gobject_init__(self)
231 Node.__init__(self)
233 self.id = None
234 self.type = "F"
235 self.items = []
236 self.description = ""
237 self.copyright = ""
239 def do_get_property(self, property):
240 if property.name == "title":
241 return self.title
242 elif property.name == "location":
243 return self.title
244 elif property.name == "status":
245 return self.status
246 else:
247 return Node.do_get_property(self, property)
249 def do_set_property(self, property, value):
250 if property.name == "title":
251 self.title = value
252 elif property.name == "location":
253 self.location = value
254 elif property.name == "status":
255 self.status = value
256 else:
257 Node.do_set_property(self, property, value)
259 def is_parent(self):
260 return False
262 def add_child(self, node, norder = None, allow_append = True):
263 debug("tried to add child to a feed %d!" % self.id)
265 def on_unread_count_changed(self, obj, old_value, delta):
266 pass
268 def add_item(self, item):
269 self.items.append(item)
271 def on_is_read_changed(self, obj, is_read):
272 if is_read:
273 self.props.unread_count -= 1
274 else:
275 self.props.unread_count += 1
277 def mark_items_as_read(self):
278 self.emit("mark-all-items-as-read")
280 class Item(GObject):
281 persistent_properties = [ "id", "title", "feed_id", "is_read", "link", "pub_date", "description" ]
282 persistent_table = "items"
283 primary_key = "id"
285 __gproperties__ = {
286 "title": (str, "title", "title", "", gobject.PARAM_READWRITE),
287 "location": (str, "location", "location", "", gobject.PARAM_READWRITE),
288 "is-read": (gobject.TYPE_BOOLEAN, "is-read", "is-read", False, gobject.PARAM_READWRITE)
291 __gsignals__ = {
292 "is-read-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
295 def __init__(self):
296 GObject.__init__(self)
297 self.id = None
298 self.title = ""
299 self.feed_id = None
300 self.is_read = False
302 self.link = ""
303 self.pub_date = None
304 self.description = ""
305 self.source = None
306 self.guid = ""
307 self.guidislink = False
309 self.publication_name = ""
310 self.publication_volume = ""
311 self.publication_number = ""
312 self.publication_section = ""
313 self.publication_starting_page = ""
315 self.fm_license = ""
316 self.fm_changes = ""
318 self.creator = ""
320 self.contributors = []
321 self.enclosures = []
322 self.license_urls = []
324 def do_get_property(self, property):
325 if property.name == "title":
326 return self.title
327 elif property.name == "is-read":
328 return self.is_read
329 else:
330 raise AttributeError, "unknown property %s" % property.name
332 def do_set_property(self, property, value):
333 if property.name == "title":
334 self.title = value
335 elif property.name == "is-read":
336 old_value = bool(self.is_read)
337 self.is_read = value
339 if old_value != value:
340 self.emit("is-read-changed", bool(value))
341 else:
342 raise AttributeError, "unknown property %s" % property.name