Example #1
0
    def setupUi(self):

        self.__dataMapper = QDataWidgetMapper(self)

        self.__dataMapper.setModel(self.__titleModel)

        propertyText = QByteArray(b'text')
        self.__dataMapper.addMapping(self.ui.tituloLineEdit, 0, propertyText)
        self.__dataMapper.addMapping(self.ui.grupoLineEdit, 1, propertyText)
        self.__dataMapper.addMapping(self.ui.yearLineEdit, 2, propertyText)

        QObject.connect(self.ui.titlesListView.selectionModel(),
                        SIGNAL('currentRowChanged(QModelIndex,QModelIndex)'),
                        self,
                        SLOT('changeSelectedTitle(QModelIndex,QModelIndex)'))

        #Dialogo de configuracion

        self.dialogoConfiguracion = ConfigDialog(self)

        self.ui.actionConfiguracion.triggered.connect(
            self.dialogoConfiguracion.open)

        self.dialogoConfiguracion.finished.connect(self.reloadModelos)

        self.ui.playButton.clicked.connect(self.launchCurrentVideo)
        self.ui.stopButton.clicked.connect(self.__ytPlayer.stopVideo)
        self.ui.pauseButton.clicked.connect(self.__ytPlayer.pauseVideo)
    def __init__(self):
        super().__init__()

        form = QFormLayout()

        self.track_id = QSpinBox()
        self.track_id.setRange(0, 2147483647)
        self.track_id.setDisabled(True)
        self.name = QLineEdit()
        self.album = QComboBox()
        self.media_type = QComboBox()
        self.genre = QComboBox()
        self.composer = QLineEdit()

        self.milliseconds = QSpinBox()
        self.milliseconds.setRange(0, 2147483647)  # <1>
        self.milliseconds.setSingleStep(1)

        self.bytes = QSpinBox()
        self.bytes.setRange(0, 2147483647)
        self.bytes.setSingleStep(1)

        self.unit_price = QDoubleSpinBox()
        self.unit_price.setRange(0, 999)
        self.unit_price.setSingleStep(0.01)
        self.unit_price.setPrefix("$")

        form.addRow(QLabel("Track ID"), self.track_id)
        form.addRow(QLabel("Track name"), self.name)
        form.addRow(QLabel("Composer"), self.composer)
        form.addRow(QLabel("Milliseconds"), self.milliseconds)
        form.addRow(QLabel("Bytes"), self.bytes)
        form.addRow(QLabel("Unit Price"), self.unit_price)

        self.model = QSqlTableModel(db=db)

        self.mapper = QDataWidgetMapper()  # <2>
        self.mapper.setModel(self.model)

        self.mapper.addMapping(self.track_id, 0)  # <3>
        self.mapper.addMapping(self.name, 1)
        self.mapper.addMapping(self.composer, 5)
        self.mapper.addMapping(self.milliseconds, 6)
        self.mapper.addMapping(self.bytes, 7)
        self.mapper.addMapping(self.unit_price, 8)

        self.model.setTable("Track")
        self.model.select()  # <4>

        self.mapper.toFirst()  # <5>

        self.setMinimumSize(QSize(400, 400))

        widget = QWidget()
        widget.setLayout(form)
        self.setCentralWidget(widget)
    def _init_db(self, table_name):
        self.table_name = table_name
        self.model = QSqlTableModel(parent=self, db=db_connection())
        self.model.setTable(table_name)
        self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)

        self.mapper = QDataWidgetMapper(self.model)
        self.mapper.setModel(self.model)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

        self.model.dataChanged.connect(self.onDataChange)
        self.commit_button.clicked.connect(self.saveChanges)
        self.revert_button.clicked.connect(self.revertChanges)
Example #4
0
def ConfigureDataMappers(model, mappings, delegate):
    mapper = QDataWidgetMapper(model)
    mapper.setModel(model)
    mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)
    mapper.setItemDelegate(delegate(mapper))
    for mapping in mappings:
        if hasattr(mapping[map_idx.WIDGET], "isCustom"):
            mapping[map_idx.WIDGET].init_db(model.database())
            mapping[map_idx.WIDGET].changed.connect(mapper.submit)
        # if no USER property we should use QByteArray().setRawData("account_id", 10)) here
        mapper.addMapping(mapping[map_idx.WIDGET],
                          model.fieldIndex(mapping[map_idx.DB_NAME]))
        # adjust width of QDateTimeEdits to show full date-time string
        if isinstance(mapping[map_idx.WIDGET], QDateTimeEdit):
            mapping[map_idx.WIDGET].setFixedWidth(mapping[
                map_idx.WIDGET].fontMetrics().width("00/00/0000 00:00:00") *
                                                  1.25)
    return mapper
Example #5
0
 def __init__(self, model, nodeFactory, fieldFactory):
     super(PropertyEditor, self).__init__()
     self._dataMapper = QDataWidgetMapper()
     self._dataMapper.setModel(model)
     self._dataMapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
     self._model = model
     self._currentIndex = None
     self._fieldFactory = fieldFactory
     self._nodeFactory = nodeFactory
     # setup ui
     self.setColumnCount(2)
     self.setHeaderLabels(['Name', 'Value'])
     self.setSelectionMode(QAbstractItemView.NoSelection)
     self.setAlternatingRowColors(True)
     self.setFocusPolicy(Qt.NoFocus)
     # create all items per component
     self._createAllItems()
     self.resizeColumnToContents(0)
     self.setColumnWidth(0, self.columnWidth(0) + 20)
Example #6
0
    def __init__(self, model, parent=None):
        super(Window, self).__init__(parent)

        self.model = model

        # Set up the widgets.
        nameLabel = QLabel("Na&me:")
        nameEdit = QLineEdit()

        # Set up the mapper.
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.model)
        self.mapper.addMapping(nameEdit, 0)

        layout = QGridLayout()
        layout.addWidget(nameLabel, 0, 0, 1, 1)
        layout.addWidget(nameEdit, 0, 1, 1, 1)
        self.setLayout(layout)

        self.mapper.toFirst()
Example #7
0
    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)

        # define tree view
        self.treeView = QTreeView(self)

        # insert line edit
        self.lineEdit1 = QLineEdit(self)
        self.lineEdit2 = QLineEdit(self)

        # insert a button group widget
        self.buttonGroupWidget1 = ButtonGroupWidget(self)
        self.buttonGroupWidget1.setTitle("Select option")
        self.buttonGroupWidget1.addRadioButton("Option 1", 1)
        self.buttonGroupWidget1.addRadioButton("Option 2", 2)
        self.buttonGroupWidget1.addRadioButton("Option 3", 3)

        layoutMain = QVBoxLayout(self)
        layoutMain.addWidget(self.treeView)
        layoutMain.addWidget(self.lineEdit1)
        layoutMain.addWidget(self.lineEdit2)
        layoutMain.addWidget(self.buttonGroupWidget1)

        # Create the data model and map the model to the widgets.
        self._model = DataModel()
        self.treeView.setModel(self._model)

        self._dataMapper = QDataWidgetMapper()
        self._dataMapper.setModel(self._model)
        # the mapping works fine for line edits and combo boxes
        self._dataMapper.addMapping(self.lineEdit1, 0)
        self._dataMapper.addMapping(self.lineEdit2, 1)
        # mapping to custom property
        self._dataMapper.addMapping(self.buttonGroupWidget1, 1,
                                    "selectedOption")

        self.treeView.selectionModel().currentChanged.connect(
            self.setSelection)
Example #8
0
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)

        #Initialize db
        createdb.init_db()

        model = QSqlRelationalTableModel(self.bookTable)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setTable("books")

        # Remember the indexes of the columns:
        author_idx = model.fieldIndex("author")
        genre_idx = model.fieldIndex("genre")

        # Set the relations to the other database tables:
        model.setRelation(author_idx, QSqlRelation("authors", "id", "name"))
        model.setRelation(genre_idx, QSqlRelation("genres", "id", "name"))

        # Set the localized header captions:
        model.setHeaderData(author_idx, Qt.Horizontal, self.tr("Author Name"))
        model.setHeaderData(genre_idx, Qt.Horizontal, self.tr("Genre"))
        model.setHeaderData(model.fieldIndex("title"), Qt.Horizontal,
                            self.tr("Title"))
        model.setHeaderData(model.fieldIndex("year"), Qt.Horizontal,
                            self.tr("Year"))
        model.setHeaderData(model.fieldIndex("rating"), Qt.Horizontal,
                            self.tr("Rating"))

        if not model.select():
            print(model.lastError())

        # Set the model and hide the ID column:
        self.bookTable.setModel(model)
        self.bookTable.setItemDelegate(BookDelegate(self.bookTable))
        self.bookTable.setColumnHidden(model.fieldIndex("id"), True)
        self.bookTable.setSelectionMode(QAbstractItemView.SingleSelection)

        # Initialize the Author combo box:
        self.authorEdit.setModel(model.relationModel(author_idx))
        self.authorEdit.setModelColumn(
            model.relationModel(author_idx).fieldIndex("name"))

        self.genreEdit.setModel(model.relationModel(genre_idx))
        self.genreEdit.setModelColumn(
            model.relationModel(genre_idx).fieldIndex("name"))

        # Lock and prohibit resizing of the width of the rating column:
        self.bookTable.horizontalHeader().setSectionResizeMode(
            model.fieldIndex("rating"), QHeaderView.ResizeToContents)

        mapper = QDataWidgetMapper(self)
        mapper.setModel(model)
        mapper.setItemDelegate(BookDelegate(self))
        mapper.addMapping(self.titleEdit, model.fieldIndex("title"))
        mapper.addMapping(self.yearEdit, model.fieldIndex("year"))
        mapper.addMapping(self.authorEdit, author_idx)
        mapper.addMapping(self.genreEdit, genre_idx)
        mapper.addMapping(self.ratingEdit, model.fieldIndex("rating"))

        selection_model = self.bookTable.selectionModel()
        selection_model.currentRowChanged.connect(mapper.setCurrentModelIndex)

        self.bookTable.setCurrentIndex(model.index(0, 0))
        self.create_menubar()
Example #9
0
    def __init__(self):
        super().__init__()

        layout = QVBoxLayout()

        form = QFormLayout()

        self.track_id = QSpinBox()
        self.track_id.setDisabled(True)
        self.name = QLineEdit()
        self.album = QComboBox()
        self.media_type = QComboBox()
        self.genre = QComboBox()
        self.composer = QLineEdit()

        self.milliseconds = QSpinBox()
        self.milliseconds.setRange(0, 2147483647)
        self.milliseconds.setSingleStep(1)

        self.bytes = QSpinBox()
        self.bytes.setRange(0, 2147483647)
        self.bytes.setSingleStep(1)

        self.unit_price = QDoubleSpinBox()
        self.unit_price.setRange(0, 999)
        self.unit_price.setSingleStep(0.01)
        self.unit_price.setPrefix("$")

        form.addRow(QLabel("Track ID"), self.track_id)
        form.addRow(QLabel("Track name"), self.name)
        form.addRow(QLabel("Composer"), self.composer)
        form.addRow(QLabel("Milliseconds"), self.milliseconds)
        form.addRow(QLabel("Bytes"), self.bytes)
        form.addRow(QLabel("Unit Price"), self.unit_price)

        self.model = QSqlTableModel(db=db)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.model)

        self.mapper.addMapping(self.track_id, 0)
        self.mapper.addMapping(self.name, 1)
        self.mapper.addMapping(self.composer, 5)
        self.mapper.addMapping(self.milliseconds, 6)
        self.mapper.addMapping(self.bytes, 7)
        self.mapper.addMapping(self.unit_price, 8)

        self.model.setTable("Track")
        self.model.select()

        self.mapper.toFirst()

        self.setMinimumSize(QSize(400, 400))

        controls = QHBoxLayout()

        # tag::controls[]
        prev_rec = QPushButton("Previous")
        prev_rec.clicked.connect(self.mapper.toPrevious)

        next_rec = QPushButton("Next")
        next_rec.clicked.connect(self.mapper.toNext)

        save_rec = QPushButton("Save Changes")
        save_rec.clicked.connect(self.mapper.submit)
        # end::controls[]

        controls.addWidget(prev_rec)
        controls.addWidget(next_rec)
        controls.addWidget(save_rec)

        layout.addLayout(form)
        layout.addLayout(controls)

        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
Example #10
0
class PropertyEditor(QTreeWidget):
    def __init__(self, model, nodeFactory, fieldFactory):
        super(PropertyEditor, self).__init__()
        self._dataMapper = QDataWidgetMapper()
        self._dataMapper.setModel(model)
        self._dataMapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self._model = model
        self._currentIndex = None
        self._fieldFactory = fieldFactory
        self._nodeFactory = nodeFactory
        # setup ui
        self.setColumnCount(2)
        self.setHeaderLabels(['Name', 'Value'])
        self.setSelectionMode(QAbstractItemView.NoSelection)
        self.setAlternatingRowColors(True)
        self.setFocusPolicy(Qt.NoFocus)
        # create all items per component
        self._createAllItems()
        self.resizeColumnToContents(0)
        self.setColumnWidth(0, self.columnWidth(0) + 20)

    def _createAllItems(self):
        for type, properties in self._allProperties().items():
            topItem = self._createComponentItem(type)
            if type == ComponentType.General:
                self._createNodeTypeItem(topItem)
            for property in properties:
                item = PropertyEditorItem(topItem)
                item.setText(0, property.label())
                field = self._fieldFactory.create(property)
                self.setItemWidget(item, 1, field)

    def _allProperties(self):
        result = {}
        for type in NodeType.All():
            node = self._nodeFactory.create(type)
            for component in node.components().values():
                result[component.type()] = component.propertyMap()
        return result

    def _createComponentItem(self, type):
        names = ComponentType.Names()
        item = PropertyEditorItem()
        item.setText(0, names[type])
        item.setData(0, Qt.UserRole, type)
        self.addTopLevelItem(item)
        item.setExpanded(True)
        return item

    def _createNodeTypeItem(self, topItem):
        self._nodeTypeItem = PropertyEditorItem(topItem)
        self._nodeTypeItem.setText(0, 'Type')
        font = self._nodeTypeItem.font(
            1
        )  # don't ask, this is how it will be the same size as in the editors
        font.setPointSize(font.pointSize())
        self._nodeTypeItem.setFont(1, font)

    def changeSelection(self, current, prev):
        node = current.internalPointer()
        self._currentIndex = current
        items = self._itemsForNode(node)
        self._setMapping(current, items)

    def _itemsForNode(self, node):
        result = []
        names = NodeType.Names()
        self._nodeTypeItem.setText(1, names[node.type()])
        for i in range(self.topLevelItemCount()):
            item = self.topLevelItem(i)
            type = item.data(0, Qt.UserRole)
            component = node.component(type)
            item.setHidden(not component)
            if component is None:
                continue
            result.extend(self._itemsForComponent(component, item))
        return result

    def _itemsForComponent(self, component, parentItem):
        result = []
        for column, property in enumerate(component.propertyMap()):
            offset = 1 if component.type(
            ) == ComponentType.General else 0  # the first item of General is Type
            item = parentItem.child(column + offset)
            item.setProperty(property)
            result.append(item)
        return result

    def _setMapping(self, current, items):
        self._dataMapper.clearMapping()
        fields = []
        for item in items:
            fields.append(self._mapField(current, item))
        parent = current.parent()
        self._dataMapper.setRootIndex(parent)
        self._dataMapper.setCurrentModelIndex(current)
        for field in fields:
            field.changed.connect(
                self._dataMapper.submit
            )  # this MUST be after the setCurrentModelIndex

    def _mapField(self, current, item):
        property = item.property()
        if not property:  # General/Type doesn't have a property
            return
        field = self.itemWidget(item, 1)
        parent = current.parent()
        readOnly = property.readOnly(
        ) or not parent.isValid()  # the top level nodes are read only
        field.setReadOnly(readOnly)
        self._dataMapper.addMapping(field, property.column(), b'valueProperty')
        return field
Example #11
0
class MainWindow(QMainWindow):
    def __init__(self, startWithConfig: None):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.__titleModel = None
        self.__dataMapper = None
        self.__ytPlayer = None

        self.__previousConfigFile = None

        self.__settings = QSettings('TallerQt', 'QtMetale')

        #Comprobar si el settings esta cargado o no

        if startWithConfig is not None:
            self.__settings.setValue('configFile', startWithConfig)

        if self.__settings.value('configFile') is None:
            CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

            PATH_TO_FILE = os.path.join(CURRENT_DIR, '../config.yaml')
            self.__settings.setValue('configFile', PATH_TO_FILE)

        self.__previousConfigFile = self.__settings.value('configFile')
        self.dialogoConfiguracion = None
        self.dialogoInforme = None

        self.ui.setupUi(self)

        self.__ytPlayer = YoutubePlayer(widgetToPlay=self.ui.videoPlayerWidget)

        self.prepareModels()
        self.setupUi()

    def setupUi(self):

        self.__dataMapper = QDataWidgetMapper(self)

        self.__dataMapper.setModel(self.__titleModel)

        propertyText = QByteArray(b'text')
        self.__dataMapper.addMapping(self.ui.tituloLineEdit, 0, propertyText)
        self.__dataMapper.addMapping(self.ui.grupoLineEdit, 1, propertyText)
        self.__dataMapper.addMapping(self.ui.yearLineEdit, 2, propertyText)

        QObject.connect(self.ui.titlesListView.selectionModel(),
                        SIGNAL('currentRowChanged(QModelIndex,QModelIndex)'),
                        self,
                        SLOT('changeSelectedTitle(QModelIndex,QModelIndex)'))

        #Dialogo de configuracion

        self.dialogoConfiguracion = ConfigDialog(self)

        self.ui.actionConfiguracion.triggered.connect(
            self.dialogoConfiguracion.open)

        self.dialogoConfiguracion.finished.connect(self.reloadModelos)

        self.ui.playButton.clicked.connect(self.launchCurrentVideo)
        self.ui.stopButton.clicked.connect(self.__ytPlayer.stopVideo)
        self.ui.pauseButton.clicked.connect(self.__ytPlayer.pauseVideo)

    def launchCurrentVideo(self):

        self.__ytPlayer.playVideo(self.__dataMapper.currentIndex())

    def prepareModels(self):

        list_titles = Title.readFromYAML(self.__settings.value('configFile'))

        self.__titleModel = TitlesTableModel(self, list_titles)

        self.ui.titlesListView.setModel(self.__titleModel)
        self.ui.titlesListView.setModelColumn(0)

        self.__ytPlayer.resetPlayList(list_titles)

    @Slot()
    def changeSelectedTitle(self, current: QModelIndex, previous: QModelIndex):
        self.__dataMapper.setCurrentIndex(current.row())

    @Slot()
    def reloadModelos(self, result):

        currentConfigFile = self.__settings.value('configFile')
        if currentConfigFile != self.__previousConfigFile:

            list_titles = Title.readFromYAML(
                self.__settings.value('configFile'))
            self.__titleModel.titles = list_titles
            self.__previousConfigFile = self.__settings.value('configFile')
class AbstractOperationDetails(QWidget):
    dbUpdated = Signal()

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.model = None
        self.table_name = ''
        self.mapper = None
        self.modified = False
        self.name = "N/A"

        self.layout = QGridLayout(self)
        self.layout.setContentsMargins(2, 2, 2, 2)

        self.bold_font = QFont()
        self.bold_font.setBold(True)
        self.bold_font.setWeight(75)

        self.main_label = QLabel(self)
        self.main_label.setFont(self.bold_font)
        self.layout.addWidget(self.main_label, 0, 0, 1, 1, Qt.AlignLeft)

        self.commit_button = QPushButton(self)
        self.commit_button.setEnabled(False)
        self.commit_button.setText("✔")
        self.commit_button.setFont(self.bold_font)
        self.commit_button.setFixedWidth(
            self.commit_button.fontMetrics().width("XXX"))
        self.revert_button = QPushButton(self)
        self.revert_button.setEnabled(False)
        self.revert_button.setText("✖️")
        self.revert_button.setFont(self.bold_font)
        self.revert_button.setFixedWidth(
            self.revert_button.fontMetrics().width("XXX"))

        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum,
                                          QSizePolicy.Expanding)
        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                            QSizePolicy.Minimum)

    def _init_db(self, table_name):
        self.table_name = table_name
        self.model = QSqlTableModel(parent=self, db=db_connection())
        self.model.setTable(table_name)
        self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)

        self.mapper = QDataWidgetMapper(self.model)
        self.mapper.setModel(self.model)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

        self.model.dataChanged.connect(self.onDataChange)
        self.commit_button.clicked.connect(self.saveChanges)
        self.revert_button.clicked.connect(self.revertChanges)

    def isCustom(self):
        return True

    def setId(self, id):
        self.model.setFilter(f"id={id}")
        self.mapper.setCurrentModelIndex(self.model.index(0, 0))

    @Slot()
    def onDataChange(self, _index_start, _index_stop, _role):
        self.modified = True
        self.commit_button.setEnabled(True)
        self.revert_button.setEnabled(True)

    @Slot()
    def saveChanges(self):
        if not self.model.submitAll():
            logging.fatal(
                g_tr('AbstractOperationDetails', "Operation submit failed: ") +
                self.model.lastError().text())
            return False
        self.modified = False
        self.commit_button.setEnabled(False)
        self.revert_button.setEnabled(False)
        self.dbUpdated.emit()
        return True

    @Slot()
    def revertChanges(self):
        self.model.revertAll()
        self.modified = False
        self.commit_button.setEnabled(False)
        self.revert_button.setEnabled(False)

    def createNew(self, account_id=0):
        self.mapper.submit(
        )  # FIXME there is check for uncommited call before - do we need submit() here?
        self.model.setFilter(f"{self.table_name}.id = 0")
        new_record = self.prepareNew(account_id)
        assert self.model.insertRows(0, 1)
        self.model.setRecord(0, new_record)
        self.mapper.toLast()

    def prepareNew(self, account_id):
        new_record = self.model.record()
        return new_record

    def copyNew(self):
        row = self.mapper.currentIndex()
        new_record = self.copyToNew(row)
        self.model.setFilter(f"{self.table_name}.id = 0")
        assert self.model.insertRows(0, 1)
        self.model.setRecord(0, new_record)
        self.mapper.toLast()

    def copyToNew(self, row):
        new_record = self.model.record(row)
        return new_record
Example #13
0
    def __init__(self):
        super().__init__()

        hlayout = QHBoxLayout()

        layout = QVBoxLayout()

        self.filtert = QLineEdit()
        self.filtert.setPlaceholderText("Search...")
        self.table = QTableView()

        vlayout = QVBoxLayout()
        vlayout.addWidget(self.filtert)
        vlayout.addWidget(self.table)

        # Left/right pane.
        hlayout.addLayout(vlayout)
        hlayout.addLayout(layout)

        form = QFormLayout()

        self.track_id = QSpinBox()
        self.track_id.setDisabled(True)
        self.track_id.setRange(0, 2147483647)
        self.name = QLineEdit()
        self.album = QComboBox()
        self.media_type = QComboBox()
        self.genre = QComboBox()
        self.composer = QLineEdit()

        self.milliseconds = QSpinBox()
        self.milliseconds.setRange(0, 2147483647)
        self.milliseconds.setSingleStep(1)

        self.bytes = QSpinBox()
        self.bytes.setRange(0, 2147483647)
        self.bytes.setSingleStep(1)

        self.unit_price = QDoubleSpinBox()
        self.unit_price.setRange(0, 999)
        self.unit_price.setSingleStep(0.01)
        self.unit_price.setPrefix("$")

        form.addRow(QLabel("Track ID"), self.track_id)
        form.addRow(QLabel("Track name"), self.name)
        form.addRow(QLabel("Composer"), self.composer)
        form.addRow(QLabel("Milliseconds"), self.milliseconds)
        form.addRow(QLabel("Bytes"), self.bytes)
        form.addRow(QLabel("Unit Price"), self.unit_price)

        self.model = QSqlTableModel(db=db)

        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.sort(1, Qt.AscendingOrder)
        self.proxy_model.setFilterKeyColumn(-1)  # all columns
        self.table.setModel(self.proxy_model)

        # Update search when filter changes.
        self.filtert.textChanged.connect(self.proxy_model.setFilterFixedString)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.proxy_model)

        self.mapper.addMapping(self.track_id, 0)
        self.mapper.addMapping(self.name, 1)
        self.mapper.addMapping(self.composer, 5)
        self.mapper.addMapping(self.milliseconds, 6)
        self.mapper.addMapping(self.bytes, 7)
        self.mapper.addMapping(self.unit_price, 8)

        self.model.setTable("Track")
        self.model.select()

        # Change the mapper selection using the table.
        self.table.selectionModel().currentRowChanged.connect(
            self.mapper.setCurrentModelIndex)

        self.mapper.toFirst()

        # tag::controls[]
        self.setMinimumSize(QSize(800, 400))

        controls = QHBoxLayout()

        prev_rec = QPushButton("Previous")
        prev_rec.clicked.connect(self.mapper.toPrevious)

        next_rec = QPushButton("Next")
        next_rec.clicked.connect(self.mapper.toNext)

        save_rec = QPushButton("Save Changes")
        save_rec.clicked.connect(self.mapper.submit)

        controls.addWidget(prev_rec)
        controls.addWidget(next_rec)
        controls.addWidget(save_rec)

        layout.addLayout(form)
        layout.addLayout(controls)

        widget = QWidget()
        widget.setLayout(hlayout)
        self.setCentralWidget(widget)