class TestGui4(MyGui): def initVars(self): self.collection = SimpleCollection(filename="simple_test.db") it = self.collection.get() for i in it: print(">>", i) def setupUi(self): super().setupUi() self.lis = TestList(collection=self.collection) self.lis.widget.setParent(self.w) self.lay.addWidget(self.lis.widget) self.formset = TestEditFormSet(collection=self.collection) self.formset.widget.setParent(self.w) self.lay.addWidget(self.formset.widget) self.lis.widget.currentItemChanged.connect( self.formset.chooseForm_slot ) # inform formset about the item in question self.formset.signals.new_record.connect( self.lis.update_slot ) # inform list that a new entry has been added def closeEvent(self, e): print("close event!") self.collection.close() e.accept()
class TestGui2(MyGui): def initVars(self): self.collection = SimpleCollection(filename="simple_test.db") it = self.collection.get() for i in it: print(">>", i) def setupUi(self): super().setupUi() self.lis = TestList(collection=self.collection) self.lis.widget.setParent(self.w) self.lay.addWidget(self.lis.widget) def closeEvent(self, e): print("close event!") self.collection.close() e.accept()
def define(self): """Define column patterns and collections """ self.collections = [] self.camera_collection = \ SimpleCollection(filename=os.path.join(self.directory, "devices.dat"), row_classes=[ DataModel.EmptyRow, DataModel.RTSPCameraRow, DataModel.USBCameraRow ] ) self.collections.append(self.camera_collection) self.config_collection = \ SimpleCollection(filename=os.path.join(self.directory, "config.dat"), row_classes=[ # we could dump here all kinds of info related to different kind of configuration forms DataModel.MemoryConfigRow ] ) self.collections.append(self.config_collection)
def define(self): """Define column patterns and collections """ self.collections = [] self.camera_collection = \ SimpleCollection(filename=os.path.join(self.directory, "devices.dat"), row_classes=[ EmptyRow, RTSPCameraRow, USBCameraRow, SDPFileRow ] ) self.collections.append(self.camera_collection) self.config_collection = \ SimpleCollection(filename=os.path.join(self.directory, "config.dat"), row_classes=[ # we could dump here all kinds of info related to different kind of configuration forms MemoryConfigRow ] ) self.collections.append(self.config_collection) self.valkkafs_collection = \ SimpleCollection(filename=os.path.join(self.directory, "valkkafs.dat"), row_classes=[ ValkkaFSConfigRow ] ) self.collections.append(self.valkkafs_collection) """ self.layout_collection = \ SimpleCollection(filename=os.path.join(self.directory, "layout.dat"), row_classes=[ VideoContainerNxMRow, PlayVideoContainerNxMRow, CameraListWindowRow, MainWindowRow ] ) """ self.layout_collection = \ SimpleCollection(filename=os.path.join(self.directory, "layout.dat"), row_classes=[ LayoutContainerRow ] ) self.collections.append(self.layout_collection)
def initVars(self): # users self.collection1 = SimpleCollection(filename="simple_test6a.db") self.collection1.clear() # cars self.collection2 = SimpleCollection(filename="simple_test6b.db") self.collection2.clear() # permissions self.collection3 = SimpleCollection(filename="simple_test6c.db") self.collection3.clear()
def initVars(self): self.collection = SimpleCollection(filename="simple_test.db") it = self.collection.get() for i in it: print(">>", i)
class TestGui6(MyGui): """Left: list of records (users). Right: list of cards. Rightmost: user rights. """ # LineEditColumn(field_name="firstname",label_name="First Name", ..) # ComboBoxColum(collection=.., key_column_name=..,field_name=..,label_name="Car model") def initVars(self): # users self.collection1 = SimpleCollection(filename="simple_test6a.db") self.collection1.clear() # cars self.collection2 = SimpleCollection(filename="simple_test6b.db") self.collection2.clear() # permissions self.collection3 = SimpleCollection(filename="simple_test6c.db") self.collection3.clear() def setupUi(self): super().setupUi() # we need self.side_collection, hence the definitions here class Row1(Row): columns = [ ColumnSpec(LineEditColumn, key_name="name", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Last Name") ] class Row2(Row): columns = [ ColumnSpec(LineEditColumn, key_name="brand", label_name="Brand"), ColumnSpec(LineEditColumn, key_name="year", label_name="Year") ] class LinkRow(Row): columns = [ ColumnSpec(ForeignKeyColumn, key_name="user_key"), ColumnSpec(ForeignKeyColumn, key_name="car_key"), ColumnSpec(CheckBoxColumn, key_name="drive", label_name="Can drive"), ColumnSpec(CheckBoxColumn, key_name="sell", label_name="Can sell") ] class TestList1(List): def makeLabel(self, entry): return entry["name"] + " " + entry["surname"] class TestList2(List): def makeLabel(self, entry): return entry["brand"] class TestFormSet1(FormSet): row_classes = [Row1] class TestFormSet2(FormSet): row_classes = [Row2] class TestFormSet3(PermissionFormSet): row_classes = [LinkRow] self.collection1.new(Row1, {"name": "Antti", "surname": "Mykkanen"}) self.collection1.new(Row1, {"name": "Jonne", "surname": "Paananen"}) self.collection1.new(Row1, {"name": "Juho", "surname": "Kokkonen"}) self.collection1.new(Row1, {"name": "Janne", "surname": "Suhonen"}) self.collection2.new(Row2, {"brand": "Ford", "year": 2000}) self.collection2.new(Row2, {"brand": "Audi", "year": 1996}) self.collection2.new(Row2, {"brand": "Seat", "year": 2004}) self.collection2.new(Row2, {"brand": "Yugo", "year": 1985}) self.collection2.new(Row2, {"brand": "BMW", "year": 2016}) self.lis1 = TestList1(collection=self.collection1) self.lis1.widget.setParent(self.w) self.lay.addWidget(self.lis1.widget) self.formset1 = TestFormSet1(collection=self.collection1) self.formset1.widget.setParent(self.w) self.lay.addWidget(self.formset1.widget) self.lis2 = TestList2(collection=self.collection2) self.lis2.widget.setParent(self.w) self.lay.addWidget(self.lis2.widget) self.formset2 = TestFormSet2(collection=self.collection2) self.formset2.widget.setParent(self.w) self.lay.addWidget(self.formset2.widget) self.formset3 = TestFormSet3(collection=self.collection3, key1_name="user_key", key2_name="car_key") self.formset3.widget.setParent(self.w) self.lay.addWidget(self.formset3.widget) self.lis1.widget.currentItemChanged.connect( self.formset1.chooseForm_slot ) # inform formset about the item in question self.lis2.widget.currentItemChanged.connect( self.formset2.chooseForm_slot ) # inform formset about the item in question # connect the user/car pair to the permission form self.lis1.widget.currentItemChanged.connect( self.formset3.pingCol1_slot ) # inform formset about the item in question self.lis2.widget.currentItemChanged.connect( self.formset3.pingCol2_slot ) # inform formset about the item in question # self.formset1.signals.new_record. connect(self.lis1.update_slot) # inform list that a new entry has been added def closeEvent(self, e): print("close event!") self.collection1.close() self.collection2.close() e.accept()
def setupUi(self): super().setupUi() class AddresRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="address", label_name="Address") ] self.side_collection = SimpleCollection(filename="simple_side.db", row_classes=[AddresRow]) """ self.side_collection.clear() self.side_collection.new(AddresRow, {"address":"Main Street"}) self.side_collection.new(AddresRow, {"address":"Side Street"}) """ def get_devices(): return [("Sda device", "/dev/sda"), ("Sdb device", "/dev/sdb")] multichoice = [("Choice 1", "eka"), ("Choice 2", "toka")] mc_label = "MultiChoice" # mc_label = "" class TestRow_(Row): columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="secondname", label_name="Second Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(ComboBoxColumn, key_name="address", label_name="Address", collection=self.side_collection, foreign_label_name="address"), ColumnSpec(ConstantComboBoxColumn, key_name="device", label_name="Device", callback=get_devices), ColumnSpec(ConstantRadioButtonColumn, key_name="multichoice", label_name=mc_label, list=multichoice) # foreigh_label_name = which key is taken for the drop-down list ] # TODO: see that initial values are loaded correctly from the db # TODO: ConstantRadioButtonColumn: rewrite createWidget self.collection = SimpleCollection(filename="simple_test.db", row_classes=[TestRow_]) it = self.collection.get() for i in it: print(">>", i) class TestList_(List): def makeLabel(self, entry): return entry["firstname"] + " " + entry["surname"] class TestFormSet_(FormSet): row_classes = [ TestRow, TestRow_, ] class TestEditFormSet_(EditFormSet): row_classes = [TestRow, TestRow_] self.lis = TestList_(collection=self.collection) self.formset = TestEditFormSet_(collection=self.collection) self.lis.widget.setParent(self.w) self.lay.addWidget(self.lis.widget) self.formset.widget.setParent(self.w) self.lay.addWidget(self.formset.widget) self.lis.widget.currentItemChanged.connect( self.formset.chooseForm_slot ) # inform formset about the item in question self.formset.signals.new_record.connect( self.lis.update_slot ) # inform list that a new entry has been added
def define(self): """Define column patterns and databases """ class FoodRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="name", label_name="Name"), ColumnSpec(LineEditColumn, key_name="price", label_name="Price"), ColumnSpec(CheckBoxColumn, key_name="spicy", label_name="Is spicy") ] self.FoodRow = FoodRow self.food_collection = SimpleCollection(filename="food_test.db", row_classes=[self.FoodRow]) class PersonRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(LineEditColumn, key_name="address", label_name="Address"), ColumnSpec(CheckBoxColumn, key_name="married", label_name="Is married") ] self.PersonRow = PersonRow class PersonRowExtended(Row): columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="secondname", label_name="Second Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(LineEditColumn, key_name="address", label_name="Address"), # in the following, we're referring to self.food_collection and there, to the columns with keys "_id" and "name". The ListEditColumn itself is a list of foreign_keys ColumnSpec(ListEditColumn, key_name="foods", label_name="Favorite foods", collection=self.food_collection, foreign_label_name="name") ] self.PersonRowExtended = PersonRowExtended self.collection = SimpleCollection( filename="simple_test.db", row_classes=[PersonRow, PersonRowExtended]) class PersonList(List): def makeLabel(self, entry): try: st = entry["firstname"] + " " + entry["surname"] except KeyError: st = "?" return st self.PersonList = PersonList class FoodList(List): def makeLabel(self, entry): try: st = entry["name"] + " (" + str(entry["price"]) + " EUR)" except KeyError: st = "?" return st self.FoodList = FoodList
class DataModel: def __init__(self): self.define() self.initDB() def define(self): """Define column patterns and databases """ class FoodRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="name", label_name="Name"), ColumnSpec(LineEditColumn, key_name="price", label_name="Price"), ColumnSpec(CheckBoxColumn, key_name="spicy", label_name="Is spicy") ] self.FoodRow = FoodRow self.food_collection = SimpleCollection(filename="food_test.db", row_classes=[self.FoodRow]) class PersonRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(LineEditColumn, key_name="address", label_name="Address"), ColumnSpec(CheckBoxColumn, key_name="married", label_name="Is married") ] self.PersonRow = PersonRow class PersonRowExtended(Row): columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="secondname", label_name="Second Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(LineEditColumn, key_name="address", label_name="Address"), # in the following, we're referring to self.food_collection and there, to the columns with keys "_id" and "name". The ListEditColumn itself is a list of foreign_keys ColumnSpec(ListEditColumn, key_name="foods", label_name="Favorite foods", collection=self.food_collection, foreign_label_name="name") ] self.PersonRowExtended = PersonRowExtended self.collection = SimpleCollection( filename="simple_test.db", row_classes=[PersonRow, PersonRowExtended]) class PersonList(List): def makeLabel(self, entry): try: st = entry["firstname"] + " " + entry["surname"] except KeyError: st = "?" return st self.PersonList = PersonList class FoodList(List): def makeLabel(self, entry): try: st = entry["name"] + " (" + str(entry["price"]) + " EUR)" except KeyError: st = "?" return st self.FoodList = FoodList def initDB(self): """Write some entries to databases """ self.collection.new( self.PersonRow, { "firstname": "Paavo", "surname": "Vayrynen", "address": "Koukkusaarentie 1", "married": True }) self.collection.new( self.PersonRow, { "firstname": "Martti", "surname": "Ahtisaari", "address": "Lokkisaarentie 1", "married": True }) # add some foods self.food_collection.new(self.FoodRow, { "name": "Hamburger", "price": 10, "spicy": False }) self.food_collection.new(self.FoodRow, { "name": "Hotdog", "price": 50, "spicy": False }) self.food_collection.new(self.FoodRow, { "name": "Freedom Fries", "price": 10, "spicy": False }) self.food_collection.new(self.FoodRow, { "name": "Bacalao", "price": 100, "spicy": False }) self.food_collection.new(self.FoodRow, { "name": "Piparra", "price": 1, "spicy": True }) # get ids of some foods .. bacalao = list( self.food_collection.get(query={"name": "Bacalao"}))[0]["_id"] piparra = list( self.food_collection.get(query={"name": "Piparra"}))[0]["_id"] self.collection.new( self.PersonRowExtended, { "firstname": "Juho", "secondname": "Kustaa", "surname": "Paasikivi", "address": "Kontulankaari 1", "foods": [] }) self.collection.new( self.PersonRowExtended, { "firstname": "Esko", "secondname": "Iiro", "surname": "Seppänen", "address": "Mellunraitti 3", "foods": [bacalao, piparra] })
class DataModel: def __init__(self, directory="."): """DataModel ctor """ self.directory = directory self.define() def __del__(self): # self.close() pass def close(self): # print("close: ",self.area_rights_collection) for collection in self.collections: collection.close() def clearAll(self): # print("DataModel", "clearAll") self.clearCameraCollection() self.config_collection.clear() self.valkkafs_collection.clear() self.layout_collection.clear() def saveAll(self): for collection in self.collections: collection.save() def clearCameraCollection(self): self.camera_collection.clear() for i in range(1, constant.max_devices + 1): self.camera_collection.new(EmptyRow, {"slot": i}) def checkCameraCollection(self): c = 0 for c, device in enumerate(self.camera_collection.get()): pass if (c != constant.max_devices - 1): return False return True def autoGenerateCameraCollection(self, base_address, nstart, n, port, tail, username, password): """ :param: base_address str, e.g. "192.168.1" :param: nstart int, e.g. 24 :param: n int, how many ips generated """ self.camera_collection.clear() self.camera_collection.save() cc = nstart for i in range(1, min((n + 1, constant.max_devices + 1))): print(i) self.camera_collection.new( RTSPCameraRow, { "slot": i, "address": base_address + "." + str(cc), "username": username, "password": password, "port": port, "tail": tail, "subaddress_main": "", "live_main": True, "rec_main": False, "subaddress_sub": "", "live_sub": False, "rec_sub": False }) cc += 1 print("Camera addesses now:") for c, device in enumerate(self.camera_collection.get()): print(c + 1, RTSPCameraRow.getMainAddressFromDict(device)) for i in range(n + 1, constant.max_devices + 1): self.camera_collection.new(EmptyRow, {"slot": i}) self.camera_collection.save() print("Camera collection now:") for c, device in enumerate(self.camera_collection.get()): print(c + 1, device) def purge(self): """For migrations / cleanup. Collections should be in correct order. """ for collection in self.collections: # print("purging",collection) collection.purge() def define(self): """Define column patterns and collections """ self.collections = [] self.camera_collection = \ SimpleCollection(filename=os.path.join(self.directory, "devices.dat"), row_classes=[ EmptyRow, RTSPCameraRow, USBCameraRow ] ) self.collections.append(self.camera_collection) self.config_collection = \ SimpleCollection(filename=os.path.join(self.directory, "config.dat"), row_classes=[ # we could dump here all kinds of info related to different kind of configuration forms MemoryConfigRow ] ) self.collections.append(self.config_collection) self.valkkafs_collection = \ SimpleCollection(filename=os.path.join(self.directory, "valkkafs.dat"), row_classes=[ ValkkaFSConfigRow ] ) self.collections.append(self.valkkafs_collection) """ self.layout_collection = \ SimpleCollection(filename=os.path.join(self.directory, "layout.dat"), row_classes=[ VideoContainerNxMRow, PlayVideoContainerNxMRow, CameraListWindowRow, MainWindowRow ] ) """ self.layout_collection = \ SimpleCollection(filename=os.path.join(self.directory, "layout.dat"), row_classes=[ LayoutContainerRow ] ) self.collections.append(self.layout_collection) def getDeviceList(self): return DeviceList(collection=self.camera_collection) def getDeviceListAndForm(self, parent): device_list = DeviceList(collection=self.camera_collection) device_form = SlotFormSet(collection=self.camera_collection) return ListAndForm(device_list, device_form, title="Camera configuration", parent=parent) def getConfigForm(self): return MemoryConfigForm(row_class=MemoryConfigRow, collection=self.config_collection) def getValkkaFSForm(self): return ValkkaFSForm(row_class=ValkkaFSConfigRow, collection=self.valkkafs_collection) def getRowsById(self, query): rows = self.camera_collection.get(query) rows_by_id = {} for row in rows: rows_by_id[row["_id"]] = row return rows_by_id def getDevicesById(self): # , query): """ rows = self.camera_collection.get(query) devices_by_id = {} for row in rows: row.pop("classname") device = RTSPCameraDevice(**row) devices_by_id[device._id] = device return devices_by_id """ rows = self.camera_collection.get() devices_by_id = {} for row in rows: classname = row.pop("classname") if (classname == "RTSPCameraRow"): device = RTSPCameraDevice(**row) elif (classname == "USBCameraRow"): device = USBCameraDevice(**row) else: device = None if (device): devices_by_id[device._id] = device return devices_by_id def writeDefaultValkkaFSConfig(self): self.valkkafs_collection.new( ValkkaFSConfigRow, { # "dirname" : default.valkkafs_config["dirname"], # not written to db for the moment "n_blocks": default.get_valkkafs_config()["n_blocks"], "blocksize": default.get_valkkafs_config()["blocksize"], "fs_flavor": default.get_valkkafs_config()["fs_flavor"], "record": default.get_valkkafs_config()["record"], "partition_uuid": default.get_valkkafs_config()["partition_uuid"] }) def writeDefaultMemoryConfig(self): self.config_collection.new(MemoryConfigRow, default.get_memory_config())
columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="secondname", label_name="Second Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(LineEditColumn, key_name="address", label_name="Address") ] """<rtf> Create collection. SimpleCollection is a simple test database (just a python dictionary), but the interface to MongoDB works with the same API <rtf>""" collection = SimpleCollection(filename="simple_test.db", row_classes=[PersonRow, PersonRowExtended]) """<rtf> Next we create a list of database entries. The List class is Row agnostic. It only knows how to create a label, using a Row entry. The only method we need to overwrite is the one used to create a label: <rtf>""" class PersonList(List): def makeLabel(self, entry): try: st = entry["firstname"] + " " + entry["surname"] except KeyError: st = "?" return st """<rtf>
from cute_mongo_forms.row import ColumnSpec, Row from cute_mongo_forms.container import List, FormSet, EditFormSet, PermissionFormSet from cute_mongo_forms.db import SimpleCollection """<rtf> Create the column patters (Rows) for each collection. <rtf>""" class PersonRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="name", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Last Name") ] person_collection = SimpleCollection(filename="persons.db", row_classes=[PersonRow]) person_collection.clear() class CarRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="brand", label_name="Brand"), ColumnSpec(LineEditColumn, key_name="year", label_name="Year") ] car_collection = SimpleCollection(filename="cars.db", row_classes=[CarRow]) car_collection.clear() """<rtf> Here we are referencing to foreign keys. The *ForeignKeyColumn* column type is a special column that's not visualized in the form widget ("label_name" is missing). It's only used for referencing records in other collections: <rtf>"""
def defineSchema(self): """Define column patterns and databases """ class FoodRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="name", label_name="Name"), ColumnSpec(LineEditColumn, key_name="price", label_name="Price"), ColumnSpec(CheckBoxColumn, key_name="spicy", label_name="Is spicy") ] self.FoodRow = FoodRow self.food_collection = SimpleCollection(filename="food_test.db", row_classes=[self.FoodRow]) class PersonRow(Row): columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(LineEditColumn, key_name="address", label_name="Address"), ColumnSpec(CheckBoxColumn, key_name="married", label_name="Is married") ] self.PersonRow = PersonRow class PersonRowExtended(Row): columns = [ ColumnSpec(LineEditColumn, key_name="firstname", label_name="First Name"), ColumnSpec(LineEditColumn, key_name="secondname", label_name="Second Name"), ColumnSpec(LineEditColumn, key_name="surname", label_name="Surname"), ColumnSpec(LineEditColumn, key_name="address", label_name="Address"), # in the following, we're referring to self.food_collection and there, to the columns with keys "_id" and "name". The ListEditColumn itself is a list of foreign_keys ColumnSpec(ListEditColumn, key_name="foods", label_name="Favorite foods", collection=self.food_collection, foreign_label_name="name") ] self.PersonRowExtended = PersonRowExtended self.collection = SimpleCollection( filename="simple_test.db", row_classes=[self.PersonRow, self.PersonRowExtended])
class DataModel: # Device collection: RTSP Cameras, SDP files, etc. class EmptyRow(Row): name = "<Empty>" columns = [ ColumnSpec(ConstantIntegerColumn, key_name="slot", label_name="Slot"), ] def isActive(self): """Is this row class visible in the form drop-down menu """ return True class USBCameraRow(Row): name = "H264 USB Camera" columns = [ ColumnSpec(ConstantIntegerColumn, key_name="slot", label_name="Slot"), ColumnSpec(USBCameraColumn, key_name="address", label_name="Device") ] def isActive(self): """Show only if there are USB cams """ return len(tools.getH264V4l2()) > 0 class RTSPCameraRow(Row): name = "RTSP Camera" columns = [ ColumnSpec(ConstantIntegerColumn, key_name="slot", label_name="Slot"), ColumnSpec(IPv4AddressColumn, key_name="address", label_name="IP Address"), ColumnSpec(LineEditColumn, key_name="username", label_name="Username"), ColumnSpec(LineEditColumn, key_name="password", label_name="Password"), ColumnSpec(LineEditColumn, key_name="port", label_name="Port"), ColumnSpec(LineEditColumn, key_name="tail", label_name="Tail"), ColumnSpec(LineEditColumn, key_name="subaddress_main", label_name="Subaddress"), ColumnSpec(CheckBoxColumn, key_name="live_main", label_name="Use stream", def_value=True), ColumnSpec(CheckBoxColumn, key_name="rec_main", label_name="Record stream", def_value=False), ColumnSpec(LineEditColumn, key_name="subaddress_sub", label_name="Subaddress"), ColumnSpec(CheckBoxColumn, key_name="live_sub", label_name="Use stream", def_value=False), ColumnSpec(CheckBoxColumn, key_name="rec_sub", label_name="Record stream", def_value=False) ] def isActive(self): return True @classmethod def getMainAddressFromDict(cls, dic): st = "rtsp://" st += dic["username"] + ":" st += dic["password"] + "@" st += dic["address"] if (dic["port"].strip() != ""): st += ":" + dic["port"].strip() if (len(dic["tail"]) > 0): st += "/" + dic["tail"] if (len(dic["subaddress_main"]) > 0): st += "/" + dic["subaddress_main"] return st @classmethod def getSubAddressFromDict(cls, dic): st = "rtsp://" st += dic["username"] + ":" st += dic["password"] + "@" st += dic["address"] if (dic["port"].strip() != ""): st += ":" + dic["port"].strip() if (len(dic["tail"]) > 0): st += "/" + dic["tail"] if (len(dic["subaddress_main"]) > 0): st += "/" + dic["subaddress_sub"] return st def makeWidget(self): """Subclassed from Row : custom form. Add a summary RTSP address in the end of the form, etc. """ # super().makeWidget() # do all by hand class FormWidget(QtWidgets.QWidget): """Just a QWidget that sends a signal when its shown """ class Signals(QtCore.QObject): show = QtCore.Signal() def __init__(self, parent=None): super().__init__(parent) self.signals = self.Signals() def showEvent(self, e): self.signals.show.emit() e.accept() self.widget = FormWidget() self.lay = QtWidgets.QGridLayout(self.widget) cc = 0 self.placeWidget(cc, "slot") cc += 1 self.placeWidget(cc, "address") cc += 1 self.placeWidget(cc, "username") cc += 1 self.placeWidget(cc, "password") cc += 1 self.placeWidget(cc, "port") cc += 1 self.placeWidget(cc, "tail") cc += 1 # Mainstream self.label_mainstream = QtWidgets.QLabel("Mainstream", self.widget) self.label_mainstream.setStyleSheet(style.form_highlight) self.placeWidgetPair(cc, (self.label_mainstream, None)) cc += 1 self.placeWidget(cc, "subaddress_main") cc += 1 # complete RTSP address self.label_mainstream_address = QtWidgets.QLabel( "RTSP address", self.widget) self.mainstream_address = QtWidgets.QLabel("", self.widget) self.placeWidgetPair( cc, (self.label_mainstream_address, self.mainstream_address)) cc += 1 # live and rec self.placeWidget(cc, "live_main") cc += 1 self.placeWidget(cc, "rec_main") cc += 1 # Substream self.label_substream = QtWidgets.QLabel("Substream", self.widget) self.label_substream.setStyleSheet(style.form_highlight) self.placeWidgetPair(cc, (self.label_substream, None)) cc += 1 self.placeWidget(cc, "subaddress_sub") cc += 1 # complete RTSP address self.label_substream_address = QtWidgets.QLabel( "RTSP address", self.widget) self.substream_address = QtWidgets.QLabel("", self.widget) self.placeWidgetPair( cc, (self.label_substream_address, self.substream_address)) cc += 1 # live and rec self.placeWidget(cc, "live_sub") cc += 1 self.placeWidget(cc, "rec_sub") cc += 1 """ # definitely NOT here! # self.copy_label = QtWidgets.QLabel("Copy this camera", self.widget) self.copy_button = QtWidgets.QPushButton("Copy", self.widget) self.placeWidgetPair(cc, (self.copy_button, None)) self.copy_button.clicked.connect(self.copy_slot) """ self.connectNotifications() def rec_main_clicked(): if not self["live_main"].widget.isChecked( ): # rec requires live print("live_main is NOT checked") self["rec_main"].widget.setChecked(False) if self["rec_main"].widget.isChecked( ): # rec main excludes rec sub self["rec_sub"].widget.setChecked(False) def rec_sub_clicked(): if not self["live_sub"].widget.isChecked( ): # rec requires live print("live_sub is NOT checked") self["rec_sub"].widget.setChecked(False) if self["rec_sub"].widget.isChecked( ): # rec sub excludes rec main self["rec_main"].widget.setChecked(False) self["rec_main"].widget.clicked.connect(rec_main_clicked) self["rec_sub"].widget.clicked.connect(rec_sub_clicked) self.widget.signals.show.connect(self.show_slot) # TODO: remove these restrictions once functional: self["subaddress_main"].widget.setEnabled(False) self["subaddress_sub"].widget.setEnabled(False) self["live_main"].widget.setEnabled(False) self["rec_main"].widget.setEnabled(False) self["live_sub"].widget.setEnabled(False) self["rec_sub"].widget.setEnabled(False) """ def get(self, collection, _id): #Subclassed from Row : Load one entry from db to QtWidgets super().get(collection, _id) self.update_notify_slot() """ def getMainAddress(self): # e.g. : rtsp://admin:[email protected]/tail dic = self.__collect__() # returns a dictionary of column values return DataModel.RTSPCameraRow.getMainAddressFromDict(dic) def getSubAddress(self): # e.g. : rtsp://admin:[email protected]/tail dic = self.__collect__() # returns a dictionary of column values return DataModel.RTSPCameraRow.getSubAddressFromDict(dic) def update_notify_slot(self): """This slot gets pinged always when the form fields have been updated """ # pass # print("RTSPCameraRow: value changed") self.mainstream_address.setText(self.getMainAddress()) self.substream_address.setText(self.getSubAddress()) # self.copy_button.setEnabled(False) # must save before can copy # nopes .. # rec main and sub exclude each other # rec requires live def show_slot(self): self.mainstream_address.setText(self.getMainAddress()) self.substream_address.setText(self.getSubAddress()) class RTSPCameraDevice: """Device class used in drag'n'drop. Copies the members of RTSPCameraRow """ parameter_defs = { "_id": int, "slot": int, "address": str, "username": str, "password": str, "port": (str, ""), "tail": (str, ""), "subaddress_main": (str, ""), "live_main": (bool, True), "rec_main": (bool, False), "subaddress_sub": (str, ""), "live_sub": (bool, False), "rec_sub": (bool, False) } def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check for input parameters, attach them to this instance as # attributes parameterInitCheck(DataModel.RTSPCameraDevice.parameter_defs, kwargs, self) def __eq__(self, other): return self._id == other._id def getMainAddress(self): st = "rtsp://" + self.username + ":" + self.password + "@" + self.address if (len(self.tail) > 0): st += "/" + self.tail if (len(self.subaddress_main) > 0): st += "/" + self.subaddress_main return st def getSubAddress(self): st = "rtsp://" + self.username + ":" + self.password + "@" + self.address if (len(self.tail) > 0): st += "/" + self.tail if (len(self.subaddress_sub) > 0): st += "/" + self.subaddress_main return st def getLabel(self): st = "rtsp://" + self.address if (len(self.tail) > 0): st += "/" + self.tail return st # the following methods give the true slot numbers used by Valkka # one slot for main, sub and recorded stream per camera # 1..3, 4..6, 7..9, etc. def getLiveMainSlot(self): return (self.slot - 1) * 3 + 1 def getLiveSubSlot(self): return (self.slot - 1) * 3 + 2 def getRecSlot(self): return (self.slot - 1) * 3 + 3 class USBCameraDevice: """Device class used in drag'n'drop. Copies the members of RTSPCameraRow """ parameter_defs = {"_id": int, "slot": int, "address": str} def __init__(self, **kwargs): # auxiliary string for debugging output self.pre = self.__class__.__name__ + " : " # check for input parameters, attach them to this instance as # attributes parameterInitCheck(DataModel.USBCameraDevice.parameter_defs, kwargs, self) def __eq__(self, other): return self._id == other._id def getMainAddress(self): return self.address def getSubAddress(self): return self.address def getLabel(self): return "usb:" + self.address # the following methods give the true slot numbers used by Valkka # one slot for main, sub and recorded stream per camera # 1..3, 4..6, 7..9, etc. def getLiveMainSlot(self): return (self.slot - 1) * 3 + 1 def getLiveSubSlot(self): return (self.slot - 1) * 3 + 2 def getRecSlot(self): return (self.slot - 1) * 3 + 3 # A general collection for misc. stuff: configuration, etc. class MemoryConfigRow(Row): columns = [ ColumnSpec(IntegerColumn, key_name="msbuftime", label_name="Buffering time (ms)", min_value=50, max_value=1000, def_value=default.memory_config["msbuftime"]), ColumnSpec(IntegerColumn, key_name="n_720p", label_name="Number of 720p streams", min_value=0, max_value=1024, def_value=default.memory_config["n_720p"]), ColumnSpec(IntegerColumn, key_name="n_1080p", label_name="Number of 1080p streams", min_value=0, max_value=1024, def_value=default.memory_config["n_1080p"]), ColumnSpec(IntegerColumn, key_name="n_1440p", label_name="Number of 2K streams", min_value=0, max_value=1024, def_value=default.memory_config["n_1440p"]), ColumnSpec(IntegerColumn, key_name="n_4K", label_name="Number of 4K streams", min_value=0, max_value=1024, def_value=default.memory_config["n_4K"]), ColumnSpec(CheckBoxColumn, key_name="bind", label_name="Bind Valkka threads to cores", def_value=default.memory_config["bind"]) ] def getNFrames(self, key): """Get number of necessary frames for certain camera resolution :param key: n720p, n1080p, etc. """ buftime = self["buftime"] ncam = self[key] # assume 25 fps cameras return int((buftime / 1000) * 25 * ncam) # *** Simple lists *** class DeviceList(List): class SortableWidgetItem(QtWidgets.QListWidgetItem): """A sortable listwidget item class """ def __init__(self): super().__init__() # self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) def __lt__(self, other): try: return int(self.slot) < int(other.slot) except Exception: return QListWidgetItem.__lt__(self, other) def makeWidget(self): super().makeWidget() # self.widget.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) def update(self): # Fills the root and subwidgets with data. self.widget.clear() self.items_by_id = {} for entry in self.collection.get(): item = self.createItem() label = self.makeLabel(entry) item.setText(label) item._id = entry["_id"] item.slot = int(entry["slot"]) # add an extra attribute try: item.classname = entry["classname"] except KeyError: raise ( KeyError("Your database contains crap. Do a purge")) self.items_by_id[item._id] = item self.widget.addItem(item) self.widget.sortItems() self.widget.setMinimumWidth(self.widget.sizeHintForColumn(0)) def createItem(self): """Overwrite in child classes to create custom items (say, sortable items, etc.) """ return self.SortableWidgetItem() def makeLabel(self, entry): # print("DataModel : makeLabel :", entry["classname"]) st = str(entry["slot"]) if (entry["classname"] == "RTSPCameraRow"): st += " RTSP (" + entry["address"] + ")" elif (entry["classname"] == "USBCameraRow"): st += " USB (" + str( entry["address"]) + ")" # could be NoneType return st # *** A stand-alone form for MemoryConfigRow *** class MemoryConfigForm(SimpleForm): class Signals(QtCore.QObject): save = QtCore.Signal() parameter_defs = {"row_class": RowWatcher, "collection": None} def __init__(self, **kwargs): super().__init__(**kwargs) self.signals = self.Signals() self.load() def makeWidget(self): super().makeWidget() self.button_row = QtWidgets.QWidget(self.widget) self.button_lay = QtWidgets.QHBoxLayout(self.button_row) self.lay.addWidget(self.button_row) self.reset_button = QtWidgets.QPushButton("Reset", self.button_row) self.save_button = QtWidgets.QPushButton("Save", self.button_row) self.button_lay.addWidget(self.reset_button) self.button_lay.addWidget(self.save_button) self.info_label = QtWidgets.QLabel( "Saving restarts all Valkka services", self.widget) self.lay.addWidget(self.info_label) self.reset_button.clicked.connect(self.row_instance.clear) self.save_button.clicked.connect(self.save_slot) def load(self): try: el = next( self.collection.get( {"classname": DataModel.MemoryConfigRow.__name__})) except StopIteration: print(self.pre, "no row!") else: print(self.pre, "reading saved") self.row_instance.get(self.collection, el["_id"]) def save_slot(self): try: el = next( self.collection.get( {"classname": DataModel.MemoryConfigRow.__name__})) except StopIteration: print(self.pre, "new row") _id = self.row_instance.new( self.collection) # create a new instance else: print(self.pre, "update row") _id = el["_id"] self.row_instance.update(self.collection, _id) self.signals.save.emit() def __init__(self, directory="."): self.directory = directory self.define() def __del__(self): # self.close() pass def close(self): # print("close: ",self.area_rights_collection) for collection in self.collections: collection.close() def clearAll(self): # print("DataModel", "clearAll") self.clearCameraCollection() self.config_collection.clear() def saveAll(self): self.camera_collection.save() self.config_collection.save() def clearCameraCollection(self): self.camera_collection.clear() for i in range(1, constant.max_devices + 1): self.camera_collection.new(self.EmptyRow, {"slot": i}) def checkCameraCollection(self): c = 0 for c, device in enumerate(self.camera_collection.get()): pass if (c != constant.max_devices - 1): return False return True def autoGenerateCameraCollection(self, base_address, nstart, n, port, tail, username, password): """ :param: base_address str, e.g. "192.168.1" :param: nstart int, e.g. 24 :param: n int, how many ips generated """ self.camera_collection.clear() self.camera_collection.save() cc = nstart for i in range(1, min((n + 1, constant.max_devices + 1))): print(i) self.camera_collection.new( self.RTSPCameraRow, { "slot": i, "address": base_address + "." + str(cc), "username": username, "password": password, "port": port, "tail": tail, "subaddress_main": "", "live_main": True, "rec_main": False, "subaddress_sub": "", "live_sub": False, "rec_sub": False }) cc += 1 print("Camera addesses now:") for c, device in enumerate(self.camera_collection.get()): print(c + 1, self.RTSPCameraRow.getMainAddressFromDict(device)) for i in range(n + 1, constant.max_devices + 1): self.camera_collection.new(self.EmptyRow, {"slot": i}) self.camera_collection.save() print("Camera collection now:") for c, device in enumerate(self.camera_collection.get()): print(c + 1, device) def purge(self): """For migrations / cleanup. Collections should be in correct order. """ for collection in self.collections: # print("purging",collection) collection.purge() def define(self): """Define column patterns and collections """ self.collections = [] self.camera_collection = \ SimpleCollection(filename=os.path.join(self.directory, "devices.dat"), row_classes=[ DataModel.EmptyRow, DataModel.RTSPCameraRow, DataModel.USBCameraRow ] ) self.collections.append(self.camera_collection) self.config_collection = \ SimpleCollection(filename=os.path.join(self.directory, "config.dat"), row_classes=[ # we could dump here all kinds of info related to different kind of configuration forms DataModel.MemoryConfigRow ] ) self.collections.append(self.config_collection) def getDeviceList(self): return DataModel.DeviceList(collection=self.camera_collection) def getDeviceListAndForm(self, parent): device_list = DataModel.DeviceList(collection=self.camera_collection) device_form = SlotFormSet(collection=self.camera_collection) return ListAndForm(device_list, device_form, title="Camera configuration", parent=parent) def getConfigForm(self): return DataModel.MemoryConfigForm(row_class=DataModel.MemoryConfigRow, collection=self.config_collection) def getRowsById(self, query): rows = self.camera_collection.get(query) rows_by_id = {} for row in rows: rows_by_id[row["_id"]] = row return rows_by_id def getDevicesById(self): # , query): """ rows = self.camera_collection.get(query) devices_by_id = {} for row in rows: row.pop("classname") device = DataModel.RTSPCameraDevice(**row) devices_by_id[device._id] = device return devices_by_id """ rows = self.camera_collection.get() devices_by_id = {} for row in rows: classname = row.pop("classname") if (classname == "RTSPCameraRow"): device = DataModel.RTSPCameraDevice(**row) elif (classname == "USBCameraRow"): device = DataModel.USBCameraDevice(**row) else: device = None if (device): devices_by_id[device._id] = device return devices_by_id