class AbstractReferenceSelector(ABC, QWidget, metaclass=SelectorMeta): changed = Signal() def __init__(self, parent=None): QWidget.__init__(self, parent) self.completer = None self.p_selected_id = 0 self.layout = QHBoxLayout() self.layout.setMargin(0) self.name = QLineEdit() self.name.setText("") self.layout.addWidget(self.name) self.details = QLabel() self.details.setText("") self.details.setVisible(False) self.layout.addWidget(self.details) self.button = QPushButton("...") self.button.setFixedWidth(self.button.fontMetrics().width("XXXX")) self.layout.addWidget(self.button) self.setLayout(self.layout) self.setFocusProxy(self.name) self.button.clicked.connect(self.on_button_clicked) if self.details_field: self.name.setFixedWidth(self.name.fontMetrics().width("X") * 15) self.details.setVisible(True) self.completer = QCompleter(self.dialog.model.completion_model) self.completer.setCompletionColumn( self.dialog.model.completion_model.fieldIndex(self.selector_field)) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.name.setCompleter(self.completer) self.completer.activated[QModelIndex].connect(self.on_completion) def getId(self): return self.p_selected_id def setId(self, selected_id): if self.p_selected_id == selected_id: return self.p_selected_id = selected_id self.name.setText( self.dialog.model.getFieldValue(selected_id, self.selector_field)) if self.details_field: self.details.setText( self.dialog.model.getFieldValue(selected_id, self.details_field)) selected_id = Property(int, getId, setId, notify=changed, user=True) def on_button_clicked(self): ref_point = self.mapToGlobal(self.name.geometry().bottomLeft()) self.dialog.setGeometry(ref_point.x(), ref_point.y(), self.dialog.width(), self.dialog.height()) res = self.dialog.exec_(enable_selection=True, selected=self.selected_id) if res: self.selected_id = self.dialog.selected_id self.changed.emit() @Slot(QModelIndex) def on_completion(self, index): model = index.model() self.selected_id = model.data(model.index(index.row(), 0), Qt.DisplayRole) self.changed.emit() def isCustom(self): return True
class TransferWidget(AbstractOperationDetails): def __init__(self, parent=None): AbstractOperationDetails.__init__(self, parent) self.name = "Transfer" self.from_date_label = QLabel(self) self.from_account_label = QLabel(self) self.from_amount_label = QLabel(self) self.to_date_label = QLabel(self) self.to_account_label = QLabel(self) self.to_amount_label = QLabel(self) self.fee_account_label = QLabel(self) self.fee_amount_label = QLabel(self) self.comment_label = QLabel(self) self.arrow_account = QLabel(self) self.copy_date_btn = QPushButton(self) self.copy_amount_btn = QPushButton(self) self.main_label.setText(g_tr("TransferWidget", "Transfer")) self.from_date_label.setText(g_tr("TransferWidget", "Date/Time")) self.from_account_label.setText(g_tr("TransferWidget", "From")) self.from_amount_label.setText(g_tr("TransferWidget", "Amount")) self.to_date_label.setText(g_tr("TransferWidget", "Date/Time")) self.to_account_label.setText(g_tr("TransferWidget", "To")) self.to_amount_label.setText(g_tr("TransferWidget", "Amount")) self.fee_account_label.setText(g_tr("TransferWidget", "Fee from")) self.fee_amount_label.setText(g_tr("TransferWidget", "Fee amount")) self.comment_label.setText(g_tr("TransferWidget", "Note")) self.arrow_account.setText(" ➜ ") self.copy_date_btn.setText("➜") self.copy_date_btn.setFixedWidth( self.copy_date_btn.fontMetrics().width("XXXX")) self.copy_amount_btn.setText("➜") self.copy_amount_btn.setFixedWidth( self.copy_amount_btn.fontMetrics().width("XXXX")) self.withdrawal_timestamp = QDateTimeEdit(self) self.withdrawal_timestamp.setCalendarPopup(True) self.withdrawal_timestamp.setTimeSpec(Qt.UTC) self.withdrawal_timestamp.setFixedWidth( self.withdrawal_timestamp.fontMetrics().width( "00/00/0000 00:00:00") * 1.25) self.withdrawal_timestamp.setDisplayFormat("dd/MM/yyyy hh:mm:ss") self.deposit_timestamp = QDateTimeEdit(self) self.deposit_timestamp.setCalendarPopup(True) self.deposit_timestamp.setTimeSpec(Qt.UTC) self.deposit_timestamp.setFixedWidth( self.deposit_timestamp.fontMetrics().width("00/00/0000 00:00:00") * 1.25) self.deposit_timestamp.setDisplayFormat("dd/MM/yyyy hh:mm:ss") self.from_account_widget = AccountSelector(self) self.to_account_widget = AccountSelector(self) self.fee_account_widget = AccountSelector(self) self.withdrawal = AmountEdit(self) self.withdrawal.setAlignment(Qt.AlignRight) self.deposit = AmountEdit(self) self.deposit.setAlignment(Qt.AlignRight) self.fee = AmountEdit(self) self.fee.setAlignment(Qt.AlignRight) self.comment = QLineEdit(self) self.layout.addWidget(self.from_date_label, 1, 0, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.from_account_label, 2, 0, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.from_amount_label, 3, 0, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.comment_label, 5, 0, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.withdrawal_timestamp, 1, 1, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.from_account_widget, 2, 1, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.withdrawal, 3, 1, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.comment, 5, 1, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.copy_date_btn, 1, 2, 1, 1) self.layout.addWidget(self.arrow_account, 2, 2, 1, 1, Qt.AlignCenter) self.layout.addWidget(self.copy_amount_btn, 3, 2, 1, 1) self.layout.addWidget(self.to_date_label, 1, 3, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.to_account_label, 2, 3, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.to_amount_label, 3, 3, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.fee_account_label, 4, 3, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.fee_amount_label, 5, 3, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.deposit_timestamp, 1, 4, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.to_account_widget, 2, 4, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.deposit, 3, 4, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.fee_account_widget, 4, 4, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.fee, 5, 4, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.commit_button, 0, 6, 1, 1) self.layout.addWidget(self.revert_button, 0, 7, 1, 1) self.layout.addItem(self.verticalSpacer, 6, 0, 1, 1) self.layout.addItem(self.horizontalSpacer, 1, 5, 1, 1) self.copy_date_btn.clicked.connect(self.onCopyDate) self.copy_amount_btn.clicked.connect(self.onCopyAmount) super()._init_db("transfers") self.mapper.setItemDelegate(TransferWidgetDelegate(self.mapper)) self.from_account_widget.changed.connect(self.mapper.submit) self.to_account_widget.changed.connect(self.mapper.submit) self.fee_account_widget.changed.connect(self.mapper.submit) self.mapper.addMapping(self.withdrawal_timestamp, self.model.fieldIndex("withdrawal_timestamp")) self.mapper.addMapping(self.from_account_widget, self.model.fieldIndex("withdrawal_account")) self.mapper.addMapping(self.withdrawal, self.model.fieldIndex("withdrawal")) self.mapper.addMapping(self.deposit_timestamp, self.model.fieldIndex("deposit_timestamp")) self.mapper.addMapping(self.to_account_widget, self.model.fieldIndex("deposit_account")) self.mapper.addMapping(self.deposit, self.model.fieldIndex("deposit")) self.mapper.addMapping(self.fee_account_widget, self.model.fieldIndex("fee_account")) self.mapper.addMapping(self.fee, self.model.fieldIndex("fee")) self.mapper.addMapping(self.comment, self.model.fieldIndex("note")) self.model.select() @Slot() def saveChanges(self): record = self.model.record(0) note = record.value(self.model.fieldIndex("note")) if not note: # If we don't have note - set it to NULL value # TODO - is it really needed? self.model.setData( self.model.index(0, self.model.fieldIndex("note")), None) # Set related fields NULL if we don't have fee. This is required for correct transfer processing fee_amount = record.value(self.model.fieldIndex("fee")) if not fee_amount: fee_amount = 0 if abs(float(fee_amount)) < Setup.CALC_TOLERANCE: self.model.setData( self.model.index(0, self.model.fieldIndex("fee_account")), None) self.model.setData( self.model.index(0, self.model.fieldIndex("fee")), None) super().saveChanges() def prepareNew(self, account_id): new_record = self.model.record() new_record.setNull("id") new_record.setValue( "withdrawal_timestamp", int(datetime.now().replace(tzinfo=tz.tzutc()).timestamp())) new_record.setValue("withdrawal_account", account_id) new_record.setValue("withdrawal", 0) new_record.setValue( "deposit_timestamp", int(datetime.now().replace(tzinfo=tz.tzutc()).timestamp())) new_record.setValue("deposit_account", 0) new_record.setValue("deposit", 0) new_record.setValue("fee_account", 0) new_record.setValue("fee", 0) new_record.setValue("asset", None) new_record.setValue("note", None) return new_record def copyToNew(self, row): new_record = self.model.record(row) new_record.setNull("id") new_record.setValue( "withdrawal_timestamp", int(datetime.now().replace(tzinfo=tz.tzutc()).timestamp())) new_record.setValue( "deposit_timestamp", int(datetime.now().replace(tzinfo=tz.tzutc()).timestamp())) return new_record @Slot() def onCopyDate(self): self.deposit_timestamp.setDateTime( self.withdrawal_timestamp.dateTime()) @Slot() def onCopyAmount(self): self.deposit.setText(self.withdrawal.text())
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
def __init__(self, app, parent=None): print("Window init") super().__init__(parent) # self.win_event_filter = WinEventFilter("window") # self.installNativeEventFilter(self.win_event_filter) self.app = app self.window_size = QtCore.QSize(400, 250) self.window_size_offset = QtCore.QSize(0, 150) self.window_position = QtCore.QPoint(0, 0) self.window_position_offset = QtCore.QPoint(0, 0) # self.setWindowFlags( # QtCore.Qt.Window | # QtCore.Qt.CustomizeWindowHint | # QtCore.Qt.WindowTitleHint | # QtCore.Qt.WindowCloseButtonHint | # QtCore.Qt.WindowStaysOnTopHint # ) self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint) self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) self.setWindowFlags( QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.Tool) # hlayout = QHBoxLayout() # hlayout.setMargin(0) # hlayout.setContentsMargins(0, 0, 0, 0) # hlayout.setSpacing(0) # buttonslayout = QVBoxLayout() self.labels = [] self.menuButton = QPushButton(u"\U00002261") self.menuLabel = QLabel("Menu") myFontBold = self.menuLabel.font() myFontBold.setBold(True) # buttons myFont = self.menuButton.font() myFont2 = self.menuButton.font() if (myFont.pointSize() > 0): myFont.setPointSizeF(1.25 * myFont.pointSizeF()) myFont2.setPointSizeF(1.4 * myFont.pointSizeF()) else: myFont.setPixelSize(1.25 * myFont.pixelSize()) myFont2.setPixelSize(1.4 * myFont.pixelSize()) self.menuLabel.setFont(myFontBold) width = self.menuButton.fontMetrics().boundingRect("OO").width() + 7 height = width # okButton.height() self.menuButton.setFont(myFont2) self.menuButton.setMaximumWidth(width) self.menuButton.setMinimumWidth(width) self.menuButton.setFlat(True) self.menuButton.clicked.connect(self.menuPressed) mainButton = QPushButton(u"\U0000239A") mainLabel = QLabel("Main") width = mainButton.fontMetrics().boundingRect("OO").width() + 7 height = width # okButton.height() mainButton.setFont(myFont2) mainButton.setMaximumWidth(width) mainButton.setMinimumWidth(width) mainButton.clicked.connect(self.main) mainButton.setFlat(True) setupButton = QPushButton(u"\U0001F527") setupLabel = QLabel("Setup") setupButton.setFont(myFont) setupButton.setFlat(True) setupButton.setMaximumWidth(width) setupButton.setMinimumWidth(width) setupButton.clicked.connect(self.setup) identifyButton = QPushButton(u"\U00002755") identifyLabel = QLabel("Identify") identifyButton.setFont(myFont) identifyButton.setFlat(True) identifyButton.setMaximumWidth(width) identifyButton.setMinimumWidth(width) identifyButton.clicked.connect(self.identify) self.refreshButton = QPushButton(u"\U000021BB") self.refreshLabel = QLabel("Detect") self.refreshButton.setFont(myFont) self.refreshButton.setFlat(True) self.refreshButton.setMaximumWidth(width) self.refreshButton.setMinimumWidth(width) self.refreshButton.clicked.connect(self.refreshPressed) aboutButton = QPushButton(u"\U00002754") aboutLabel = QLabel("About") aboutButton.setFont(myFont) aboutButton.setFlat(True) aboutButton.setMaximumWidth(width) aboutButton.setMinimumWidth(width) aboutButton.clicked.connect(self.about) # closeButton = QPushButton(u"\U00002573") closeButton = QPushButton(u"\U000026CC") closeLabel = QLabel("Close") closeButton.setFont(myFont) closeButton.setFlat(True) closeButton.setMaximumWidth(width) closeButton.setMinimumWidth(width) closeButton.clicked.connect(self.close_) buttongrid = QGridLayout() buttongrid.addWidget(self.menuButton, 0, 0) buttongrid.addWidget(mainButton, 1, 0) buttongrid.addWidget(setupButton, 2, 0) buttongrid.addWidget(self.refreshButton, 3, 0) buttongrid.addWidget(identifyButton, 4, 0) buttongrid.addWidget(aboutButton, 6, 0) buttongrid.addWidget(closeButton, 7, 0) buttongrid.addWidget(self.menuLabel, 0, 1) buttongrid.addWidget(mainLabel, 1, 1) buttongrid.addWidget(setupLabel, 2, 1) buttongrid.addWidget(self.refreshLabel, 3, 1) buttongrid.addWidget(identifyLabel, 4, 1) buttongrid.addWidget(aboutLabel, 6, 1) buttongrid.addWidget(closeLabel, 7, 1) self.labels.append(self.menuLabel) self.labels.append(mainLabel) self.labels.append(setupLabel) self.labels.append(self.refreshLabel) self.labels.append(identifyLabel) self.labels.append(aboutLabel) self.labels.append(closeLabel) self.menuLabel .mousePressEvent = self.menuLabelPressed mainLabel .mousePressEvent = self.mainLabel setupLabel.mousePressEvent = self.setupLabel self.refreshLabel.mousePressEvent = self.refreshLabelPressed identifyLabel.mousePressEvent = self.identifyLabel aboutLabel.mousePressEvent = self.aboutLabel closeLabel.mousePressEvent = self.closeLabel buttongrid.setRowStretch(0, 0) buttongrid.setRowStretch(1, 0) buttongrid.setRowStretch(2, 0) buttongrid.setRowStretch(3, 0) buttongrid.setRowStretch(4, 0) buttongrid.setRowStretch(5, 1) buttongrid.setRowStretch(6, 0) buttongrid.setRowStretch(7, 0) self.labels_set_visible(False) self.layout = QHBoxLayout() # buttonslayout.addWidget(mainButton) # buttonslayout.addWidget(setupButton) # buttonslayout.addStretch(1) # buttonslayout.addWidget(aboutButton) # hlayout.addLayout(buttonslayout) # hlayout.addLayout(buttongrid) # grid.addLayout(hlayout, 1, 1) buttongrid.setSpacing(0) self.layout.addLayout(buttongrid) self.body_layout = QVBoxLayout() self.body_layout.setContentsMargins(0, 0, 0, 1) self.body_layout.setSpacing(0) self.title_layout = QHBoxLayout() self.title_layout.setContentsMargins(0, 0, 0, 0) self.title_layout.setSpacing(0) self.titleLabel = QLabel("Monitor Control") self.titleLabel.setWordWrap(True) self.titleLabel.setSizeIncrement(10, 10) myFont = self.titleLabel.font() myFont.setBold(True) self.titleLabel.setFont(myFont) width = self.titleLabel.fontMetrics().boundingRect("OO").width() + 7 height = width # okButton.height() self.titleLabel.mousePressEvent = self.mainLabel self.backButton = QPushButton(u"\U00002190", self) myFont = self.backButton.font() myFont.setBold(True) self.backButton.setFont(myFont) self.backButton.setMaximumWidth(width) self.backButton.setMinimumWidth(width) self.backButton.setFlat(True) self.backButton.clicked.connect(self.main) self.titleLabel.setMinimumHeight(self.backButton.height()) self.title_layout.addWidget(self.backButton, 0, QtCore.Qt.AlignVCenter) self.title_layout.addSpacing(20) self.title_layout.addWidget(self.titleLabel, 1, QtCore.Qt.AlignVCenter) # self.backButton.setAlignment(Qt.AlignTop) self.title_layout.setAlignment(QtCore.Qt.AlignTop) self.body_layout.addLayout(self.title_layout) self.main_frame = QtWidgets.QFrame(self) self.main_layout = QVBoxLayout() self.feature_brightness = FeatureWidget( self.main_frame, "Brightness", self.app.brightness) self.feature_contrast = FeatureWidget( self.main_frame, "Contrast", self.app.contrast) self.main_layout.addWidget(self.feature_brightness) self.main_layout.addWidget(self.feature_contrast) self.main_layout.addStretch(1) self.main_frame.setLayout(self.main_layout) self.main_frame.hide() self.body_layout.addWidget(self.main_frame, 1) self.setup_frame = QtWidgets.QFrame(self) leftButton = QPushButton("<", self.setup_frame) width = leftButton.fontMetrics().boundingRect("<").width() + 7 leftButton.setFlat(True) leftButton.setMaximumWidth(width) leftButton.setMinimumWidth(width) leftButton.setSizePolicy(QtWidgets.QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Expanding)) self.setup_layout = QHBoxLayout() self.setup_layout.addWidget(leftButton) self.feature_setup_widget = FeatureSetupWidget( self.app, self.setup_frame) # hlayout.addWidget(self.feature_setup_widget, 1) self.feature_setup_widget.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding) rightButton = QPushButton(">", self.setup_frame) rightButton.setFlat(True) rightButton.setMaximumWidth(width) rightButton.setMinimumWidth(width) rightButton.setSizePolicy(QtWidgets.QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Expanding)) self.setup_layout.addWidget(self.feature_setup_widget, 1) self.setup_layout.addWidget(rightButton) self.setup_layout.setContentsMargins(0, 0, 0, 0) self.setup_layout.setSpacing(0) leftButton.clicked.connect(self.feature_setup_widget.previous) rightButton.clicked.connect(self.feature_setup_widget.next) self.setup_frame.setLayout(self.setup_layout) # self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(10) self.body_layout.addWidget(self.setup_frame, 1) self.layout.addLayout(self.body_layout, 1) self.about_frame = QtWidgets.QFrame(self) self.about_layout = QVBoxLayout() self.aboutLabel1 = QLabel("About", self.about_frame) self.aboutLabel1.setWordWrap(True) myFont = self.aboutLabel1.font() myFont.setBold(True) self.aboutLabel1.setFont(myFont) about = "©️ ™️ Juno\n\nMonitor Control synchronizes your monitor hardware properties like brightness and contrast.\nThese properties can be changed by the software sliders, or monitor buttons. These changes are monitored and read, and subsequently set to the other monitors using a calibration. This will ensure an input change has the same result on all monitors.\n" self.aboutLabel2 = QLabel("{}".format(about), self.about_frame) self.aboutLabel2.setAlignment( QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.aboutLabel2.setWordWrap(True) self.about_layout.addWidget(self.aboutLabel1) self.about_layout.addWidget(self.aboutLabel2, 1) self.about_frame.setLayout(self.about_layout) self.about_frame.hide() self.body_layout.addWidget(self.about_frame, 1) # self.layout.setSizeConstraint(QtGui.QLayout.setFixedSize) self.setLayout(self.layout) self.setWindowIcon(QtGui.QIcon('artifacts/icon.png')) # set the title self.setWindowTitle("Monitors Control") self.main() self.setFixedSize(400, 250)
def resize_button_to_minimum(button: QtWidgets.QPushButton): # https://stackoverflow.com/a/19502467/888653 text = button.text() width = button.fontMetrics().boundingRect(text).width() + 7 button.setMinimumWidth(width) button.setMaximumWidth(width)
class IncomeSpendingWidget(AbstractOperationDetails): def __init__(self, parent=None): AbstractOperationDetails.__init__(self, parent) self.name = "Income/Spending" self.details_model = None self.category_delegate = CategorySelectorDelegate() self.tag_delegate = TagSelectorDelegate() self.float_delegate = FloatDelegate(2) self.date_label = QLabel(self) self.details_label = QLabel(self) self.account_label = QLabel(self) self.peer_label = QLabel(self) self.main_label.setText(g_tr("IncomeSpendingWidget", "Income / Spending")) self.date_label.setText(g_tr("IncomeSpendingWidget", "Date/Time")) self.details_label.setText(g_tr("IncomeSpendingWidget", "Details")) self.account_label.setText(g_tr("IncomeSpendingWidget", "Account")) self.peer_label.setText(g_tr("IncomeSpendingWidget", "Peer")) self.timestamp_editor = QDateTimeEdit(self) self.timestamp_editor.setCalendarPopup(True) self.timestamp_editor.setTimeSpec(Qt.UTC) self.timestamp_editor.setFixedWidth(self.timestamp_editor.fontMetrics().width("00/00/0000 00:00:00") * 1.25) self.timestamp_editor.setDisplayFormat("dd/MM/yyyy hh:mm:ss") self.account_widget = AccountSelector(self) self.peer_widget = PeerSelector(self) self.a_currency = OptionalCurrencyComboBox(self) self.a_currency.setText(g_tr("IncomeSpendingWidget", "Paid in foreign currency:")) self.add_button = QPushButton(self) self.add_button.setText(" +️ ") self.add_button.setFont(self.bold_font) self.add_button.setFixedWidth(self.add_button.fontMetrics().width("XXX")) self.del_button = QPushButton(self) self.del_button.setText(" — ️") self.del_button.setFont(self.bold_font) self.del_button.setFixedWidth(self.del_button.fontMetrics().width("XXX")) self.copy_button = QPushButton(self) self.copy_button.setText(" >> ️") self.copy_button.setFont(self.bold_font) self.copy_button.setFixedWidth(self.copy_button.fontMetrics().width("XXX")) self.details_table = QTableView(self) self.details_table.horizontalHeader().setFont(self.bold_font) self.details_table.setAlternatingRowColors(True) self.details_table.verticalHeader().setVisible(False) self.details_table.verticalHeader().setMinimumSectionSize(20) self.details_table.verticalHeader().setDefaultSectionSize(20) self.layout.addWidget(self.date_label, 1, 0, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.details_label, 2, 0, 1, 1, Qt.AlignLeft) self.layout.addWidget(self.timestamp_editor, 1, 1, 1, 4) self.layout.addWidget(self.add_button, 2, 1, 1, 1) self.layout.addWidget(self.copy_button, 2, 2, 1, 1) self.layout.addWidget(self.del_button, 2, 3, 1, 1) self.layout.addWidget(self.account_label, 1, 5, 1, 1, Qt.AlignRight) self.layout.addWidget(self.peer_label, 2, 5, 1, 1, Qt.AlignRight) self.layout.addWidget(self.account_widget, 1, 6, 1, 1) self.layout.addWidget(self.peer_widget, 2, 6, 1, 1) self.layout.addWidget(self.a_currency, 1, 7, 1, 1) self.layout.addWidget(self.commit_button, 0, 9, 1, 1) self.layout.addWidget(self.revert_button, 0, 10, 1, 1) self.layout.addWidget(self.details_table, 4, 0, 1, 11) self.layout.addItem(self.horizontalSpacer, 1, 8, 1, 1) self.add_button.clicked.connect(self.addChild) self.del_button.clicked.connect(self.delChild) super()._init_db("actions") self.mapper.setItemDelegate(IncomeSpendingWidgetDelegate(self.mapper)) self.details_model = DetailsModel(self.details_table, db_connection()) self.details_model.setTable("action_details") self.details_model.setEditStrategy(QSqlTableModel.OnManualSubmit) self.details_table.setModel(self.details_model) self.details_model.dataChanged.connect(self.onDataChange) self.account_widget.changed.connect(self.mapper.submit) self.peer_widget.changed.connect(self.mapper.submit) self.a_currency.changed.connect(self.mapper.submit) self.a_currency.updated.connect(self.details_model.setAltCurrency) self.mapper.addMapping(self.timestamp_editor, self.model.fieldIndex("timestamp")) self.mapper.addMapping(self.account_widget, self.model.fieldIndex("account_id")) self.mapper.addMapping(self.peer_widget, self.model.fieldIndex("peer_id")) self.mapper.addMapping(self.a_currency, self.model.fieldIndex("alt_currency_id")) self.details_table.setItemDelegateForColumn(2, self.category_delegate) self.details_table.setItemDelegateForColumn(3, self.tag_delegate) self.details_table.setItemDelegateForColumn(4, self.float_delegate) self.details_table.setItemDelegateForColumn(5, self.float_delegate) self.model.select() self.details_model.select() self.details_model.configureView() def setId(self, id): super().setId(id) self.details_model.setFilter(f"action_details.pid = {id}") @Slot() def addChild(self): new_record = self.details_model.record() new_record.setNull("tag_id") new_record.setValue("amount", 0) new_record.setValue("amount_alt", 0) if not self.details_model.insertRecord(-1, new_record): logging.fatal( g_tr('AbstractOperationDetails', "Failed to add new record: ") + self.details_model.lastError().text()) return @Slot() def delChild(self): idx = self.details_table.selectionModel().selection().indexes() selected_row = idx[0].row() self.details_model.removeRow(selected_row) self.details_table.setRowHidden(selected_row, True) @Slot() def saveChanges(self): if not self.model.submitAll(): logging.fatal( g_tr('AbstractOperationDetails', "Operation submit failed: ") + self.model.lastError().text()) return pid = self.model.data(self.model.index(0, self.model.fieldIndex("id"))) if pid is None: # we just have saved new action record and need last inserted id pid = self.model.query().lastInsertId() for row in range(self.details_model.rowCount()): self.details_model.setData(self.details_model.index(row, self.details_model.fieldIndex("pid")), pid) if not self.details_model.submitAll(): logging.fatal(g_tr('AbstractOperationDetails', "Operation details submit failed: ") + self.details_model.lastError().text()) return self.modified = False self.commit_button.setEnabled(False) self.revert_button.setEnabled(False) self.dbUpdated.emit() return def createNew(self, account_id=0): super().createNew(account_id) self.details_model.setFilter(f"action_details.pid = 0") def prepareNew(self, account_id): new_record = self.model.record() new_record.setNull("id") new_record.setValue("timestamp", int(datetime.now().replace(tzinfo=tz.tzutc()).timestamp())) new_record.setValue("account_id", account_id) new_record.setValue("peer_id", 0) new_record.setValue("alt_currency_id", None) return new_record def copyNew(self): old_id = self.model.record(self.mapper.currentIndex()).value(0) super().copyNew() self.details_model.setFilter(f"action_details.pid = 0") query = executeSQL("SELECT * FROM action_details WHERE pid = :pid ORDER BY id DESC", [(":pid", old_id)]) while query.next(): new_record = query.record() new_record.setNull("id") new_record.setNull("pid") assert self.details_model.insertRows(0, 1) self.details_model.setRecord(0, new_record) def copyToNew(self, row): new_record = self.model.record(row) new_record.setNull("id") new_record.setValue("timestamp", int(datetime.now().replace(tzinfo=tz.tzutc()).timestamp())) return new_record