Another batch of fixes for reparenting.
[straw.git] / straw / model / __init__.py
blobbbaa5c9923f91dd2e49600c9895b0398c2bc2dac
1 from bisect import insort
2 from gobject import GObject
3 from straw.error import debug
4 import gobject
5 import straw
7 class Node(GObject):
8 """
9 Represents a base of single node in the model tree. This class is meant
10 for subclassing only, Node instances should not be used.
11 """
13 persistent_properties = [ "id", "parent_id", "type", "norder" ]
14 persistent_table = "nodes"
15 primary_key = "id"
17 __gproperties__ = {
18 "norder": (int, "parent_id", "norder", 0, 999999, 0, gobject.PARAM_READWRITE),
19 "parent": (gobject.TYPE_PYOBJECT, "parent", "parent", gobject.PARAM_READWRITE),
20 "unread-count": (int, "unread-count", "unread-count", 0, 999999, 0, gobject.PARAM_READWRITE)
23 __gsignals__ = {
24 "parent-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
25 "norder-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
26 "unread-count-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT))
29 def __init__(self):
30 GObject.__init__(self)
31 self.id = None
32 self.parent_id = None
33 self.unread_count = 0
34 self.norder = 0
35 self.children = []
37 def __cmp__(self, other):
38 if not other:
39 return None
40 elif self.norder == other.norder:
41 return 0
42 elif self.norder < other.norder:
43 return -1
44 else:
45 return 1
47 def do_get_property(self, property):
48 if property.name == "norder":
49 return self.norder
50 elif property.name == "parent_id":
51 return self.parent_id
52 elif property.name == "unread-count":
53 return self.unread_count
55 def do_set_property(self, property, value):
56 if property.name == "unread-count":
57 if value == None:
58 value = 0
60 if self.unread_count != value:
61 delta = value - self.unread_count
62 old_value = self.unread_count
63 self.unread_count = value
64 self.emit("unread-count-changed", old_value, delta)
65 elif property.name == "norder":
66 if self.norder != value:
67 old_value = self.norder
68 self.norder = value
69 self.emit("norder-changed", old_value)
70 elif property.name == "parent":
71 if self.parent.id != value.id:
72 old_value = self.parent
73 self.parent = value
74 self.parent_id = value.id
75 self.emit("parent-changed", old_value)
77 def add_child(self, node, norder = None, allow_append = True):
78 if allow_append:
79 if not norder or norder >= len(self.children):
80 norder = len(self.children)
81 else:
82 if node.parent == self:
83 if norder > len(self.children):
84 norder = len(self.children)#raise AttributeError
86 if not norder:
87 norder = len(self.children) - 1
88 else:
89 if not norder:
90 norder = len(self.children)
91 elif norder > len(self.children):
92 norder = len(self.children)
94 if norder < len(self.children):
95 for child in self.children[norder:]:
96 child.props.norder += 1
98 node.props.norder = norder
100 self.append_child(node)
102 def append_child(self, node):
103 debug("appending %d to %d" % (node.id, self.id))
104 insort(self.children, node)
105 node.connect("unread-count-changed", self.on_unread_count_changed)
106 self.props.unread_count += node.unread_count
108 def remove_child(self, node):
109 debug("removing %d from %d" % (node.id, self.id))
110 for child in self.children[(node.norder + 1):]:
111 child.props.norder -= 1
113 self.children.remove(node)
114 self.props.unread_count -= node.unread_count
116 def move(self, new_parent, new_norder = None):
117 debug("moving %d to %d (new_norder = %d)" % (self.id, new_parent.id, new_norder))
119 self.parent.remove_child(self)
120 new_parent.add_child(self, norder = new_norder, allow_append = False)
121 self.props.parent = new_parent
122 return
123 old_parent = self.parent
125 if new_parent != self.parent:
126 print "need to reparent %d -> %d" % (self.parent.id, new_parent.id)
127 self.props.parent = new_parent
128 print "reparented %d -> %d" % (old_parent.id, new_parent.id)
129 else:
130 for child in old_parent.children[(self.norder + 1):]:
131 child.props.norder -= 1
133 self.parent.children.remove(self)
135 if not new_norder or new_norder >= len(self.parent.children):
136 new_norder = len(self.parent.children) - 1
138 for child in self.parent.children[new_norder:]:
139 child.props.norder += 1
141 self.props.norder = new_norder
142 insort(self.parent.children, self)
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):
219 pass
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