99 |
99 |
100 if col == self.dsc.lstcolnames.index("QoS") and v not in QoS_values: |
100 if col == self.dsc.lstcolnames.index("QoS") and v not in QoS_values: |
101 self.log("{} is invalid for IdType\n".format(value)) |
101 self.log("{} is invalid for IdType\n".format(value)) |
102 return False |
102 return False |
103 |
103 |
104 self.data[row][col] = v |
104 line = self.data[row] |
|
105 line[col] = v |
|
106 self.data[row] = line |
105 return True |
107 return True |
106 |
108 |
107 # Report how many columns this model provides data for. |
109 # Report how many columns this model provides data for. |
108 def GetColumnCount(self): |
110 def GetColumnCount(self): |
109 return len(self.dsc.lstcolnames) |
111 return len(self.dsc.lstcolnames) |
236 super(MQTTClientList, self).__init__(self) |
238 super(MQTTClientList, self).__init__(self) |
237 self.log = log |
239 self.log = log |
238 self.change_callback = change_callback |
240 self.change_callback = change_callback |
239 self.dsc = lstcoldsc[direction] |
241 self.dsc = lstcoldsc[direction] |
240 |
242 |
241 def append(self, value): |
243 def _filter_line(self, value): |
242 v = dict(list(zip(self.dsc.lstcolnames, value))) |
244 v = dict(list(zip(self.dsc.lstcolnames, value))) |
243 |
245 |
244 if type(v["Location"]) != int: |
246 if type(v["Location"]) != int: |
245 if len(self) == 0: |
247 if len(self) == 0: |
246 v["Location"] = 0 |
248 v["Location"] = 0 |
248 iecnums = set(zip(*self)[self.dsc.Location_column]) |
250 iecnums = set(zip(*self)[self.dsc.Location_column]) |
249 greatest = max(iecnums) |
251 greatest = max(iecnums) |
250 holes = set(range(greatest)) - iecnums |
252 holes = set(range(greatest)) - iecnums |
251 v["Location"] = min(holes) if holes else greatest+1 |
253 v["Location"] = min(holes) if holes else greatest+1 |
252 |
254 |
253 if v["QoS"] not in QoS_values: |
|
254 self.log("Unknown QoS\n".format(value)) |
|
255 return False |
|
256 |
|
257 try: |
255 try: |
258 for t,n in zip(self.dsc.lstcoltypess, self.dsc.lstcolnames): |
256 for t,n in zip(self.dsc.lstcoltypess, self.dsc.lstcolnames): |
259 v[n] = t(v[n]) |
257 v[n] = t(v[n]) |
260 except ValueError: |
258 except ValueError: |
261 self.log("MQTT topic {} (Location={}) has invalid type\n".format(v["Topic"],v["Location"])) |
259 self.log("MQTT topic {} (Location={}) has invalid type\n".format(v["Topic"],v["Location"])) |
262 return False |
260 return None |
|
261 |
|
262 if v["QoS"] not in QoS_values: |
|
263 self.log("Unknown QoS\n".format(value)) |
|
264 return None |
263 |
265 |
264 if len(self)>0 and v["Topic"] in list(zip(*self))[self.dsc.lstcolnames.index("Topic")]: |
266 if len(self)>0 and v["Topic"] in list(zip(*self))[self.dsc.lstcolnames.index("Topic")]: |
265 self.log("MQTT topic {} (Location={}) already in the list\n".format(v["Topic"],v["Location"])) |
267 self.log("MQTT topic {} (Location={}) already in the list\n".format(v["Topic"],v["Location"])) |
266 return False |
268 return None |
267 |
269 |
268 list.append(self, [v[n] for n in self.dsc.lstcolnames]) |
270 return [v[n] for n in self.dsc.lstcolnames] |
269 |
271 |
|
272 def insert(self, row, value): |
|
273 v = self._filter_line(value) |
|
274 if v is not None: |
|
275 list.insert(self, row, v) |
|
276 self.change_callback() |
|
277 return True |
|
278 return False |
|
279 |
|
280 def append(self, value): |
|
281 v = self._filter_line(value) |
|
282 if v is not None: |
|
283 list.append(self, v) |
|
284 self.change_callback() |
|
285 return True |
|
286 return False |
|
287 |
|
288 def __setitem__(self, index, value): |
|
289 list.__setitem__(self, index, value) |
270 self.change_callback() |
290 self.change_callback() |
271 |
|
272 return True |
|
273 |
291 |
274 def __delitem__(self, index): |
292 def __delitem__(self, index): |
275 list.__delitem__(self, index) |
293 list.__delitem__(self, index) |
276 self.change_callback() |
294 self.change_callback() |
|
295 |
277 |
296 |
278 class MQTTClientModel(dict): |
297 class MQTTClientModel(dict): |
279 def __init__(self, log, change_callback = lambda : None): |
298 def __init__(self, log, change_callback = lambda : None): |
280 super(MQTTClientModel, self).__init__() |
299 super(MQTTClientModel, self).__init__() |
281 for direction in directions: |
300 for direction in directions: |
288 for direction, model in self.iteritems(): |
307 for direction, model in self.iteritems(): |
289 self[direction][:] = [] |
308 self[direction][:] = [] |
290 for row in reader: |
309 for row in reader: |
291 direction = row[0] |
310 direction = row[0] |
292 # avoids calling change callback when loading CSV |
311 # avoids calling change callback when loading CSV |
293 list.append(self[direction],row[1:]) |
312 l = self[direction] |
|
313 v = l._filter_line(row[1:]) |
|
314 if v is not None: |
|
315 list.append(l,v) |
|
316 # TODO be verbose in case of malformed CSV |
294 |
317 |
295 def SaveCSV(self,path): |
318 def SaveCSV(self,path): |
296 with open(path, 'w') as csvfile: |
319 with open(path, 'w') as csvfile: |
297 for direction, data in self.items(): |
320 for direction, data in self.items(): |
298 writer = csv.writer(csvfile, delimiter=',', |
321 writer = csv.writer(csvfile, delimiter=',', |