示例#1
0
 def image_to_base64(self, img: QImage) -> bytes:
     quality = self.settings.int_value(default_settings.frame_quality)
     byte_arr = QByteArray()
     buffer = QBuffer(byte_arr)
     buffer.open(QIODevice.WriteOnly)
     img.save(buffer, 'jpg', quality)
     return byte_arr.toBase64().data()
示例#2
0
    def __init__(self, format, durationUs, sampleRate, parent):
        super(Generator, self).__init__(parent)

        self.m_pos = 0
        self.m_buffer = QByteArray()

        self.generateData(format, durationUs, sampleRate)
示例#3
0
def bytes_read(image, start, length):
    array = QByteArray()
    buffer = 0
    for i in range(in_bits(start), in_bits(start + length)):
        buffer = (buffer << 1) | take_bit(image, i)
        if i % 8 == 7:
            array.push_back(bytes((buffer, )))
            buffer = 0
    return array
示例#4
0
def encode_image(image: QImage) -> str:
    image_bytes = QByteArray()
    buffer = QBuffer(image_bytes)
    buffer.open(QIODevice.WriteOnly)
    # noinspection PyTypeChecker
    image.save(buffer, "PNG")  # writes pixmap into bytes in PNG format
    encoded_bytes = image_bytes.toBase64()
    encoded_string = encoded_bytes.data().decode()
    return encoded_string
示例#5
0
    def readData(self, maxlen):
        data = QByteArray()
        total = 0

        while maxlen > total:
            chunk = min(self.m_buffer.size() - self.m_pos, maxlen - total)
            data.append(self.m_buffer.mid(self.m_pos, chunk))
            self.m_pos = (self.m_pos + chunk) % self.m_buffer.size()
            total += chunk

        return data.data()
示例#6
0
    def message_changed(self):
        if self.image_capacity < 0:
            return

        byte_array = QByteArray()
        byte_array.push_back(self.ui.message_frame.toPlainText().encode())
        self.used_capacity = len(self.ui.message_frame.toPlainText())

        if self.image_capacity < self.used_capacity:
            self.ui.output_label.setText(f"Размер сообщения превышен на: {self.used_capacity - self.image_capacity} байт.")
        else:
            self.ui.output_label.setText(f"Ещё можно ввести: {self.image_capacity - self.used_capacity} байт.")
示例#7
0
def read_bytes(image: QImage, start, length) -> QByteArray:
    array = QByteArray()
    buffer = 0

    for i in range(to_bits(start), to_bits(start + length)):
        buffer = (buffer << 1) | get_bit(image, i)

        if i % 8 == 7:
            array.push_back(bytes((buffer, )))
            buffer = 0

    return array
示例#8
0
def read_bytes(image: QImage, begin, length) -> QByteArray:
    byte_array = QByteArray()
    buffer = 0
    end = (begin + length) * 8

    for i in range(begin * 8, end):
        buffer = (buffer << 1) | get_bit(image, i)

        if i % 8 == 7:
            byte_array.push_back(bytes((buffer, )))
            buffer = 0

    return byte_array
示例#9
0
 def update_frame_image(self, frame_index: int):
     """
     刷新帧图象显示
     :param frame_index: 帧索引
     :return: None
     """
     base64 = self._frame_base64_dict[frame_index]
     byte_arr = QByteArray(base64)
     img = QImage()
     img.loadFromData(QByteArray.fromBase64(byte_arr))
     pixmap = QPixmap.fromImage(img)
     self.current_frame_item.setPixmap(pixmap)
     self.current_frame_index = frame_index
示例#10
0
    def encode_text(self):
        if self.image is None:
            self.set_output_message("Ошибка загрузки.")
            return

        array = QByteArray()
        array.push_back(self.get_input().encode())

        self.data.curr_power = len(array)

        if self.data.overflow():
            self.set_output_message(
                "Сильно большой текст для кодирования в эту картинку.")
            return

        for i in range(4):
            array.push_front(
                bytes(((self.data.curr_power >> in_bits(i)) & 0xff, )))

        for i in range(len(MainWindow.bytes_key) - 1, -1, -1):
            array.push_front(bytes((MainWindow.bytes_key[i], )))

        bytes_write(self.image, array, 0)

        self.set_output_message("Сообщение закодировано!")
    def run(self):
        tcpSocket = QTcpSocket()
        if not tcpSocket.setSocketDescriptor(self.socketDescriptor):
            self.error.emit(tcpSocket.error())
            return

        block = QByteArray()
        outstr = QDataStream(block, QIODevice.WriteOnly)
        outstr.setVersion(QDataStream.Qt_4_0)
        outstr.writeUInt16(0)
        outstr.writeQString(self.text)
        outstr.device().seek(0)
        outstr.writeUInt16(block.size() - 2)

        tcpSocket.write(block)
        tcpSocket.disconnectFromHost()
        tcpSocket.waitForDisconnected()
示例#12
0
    def message_changed(self):
        array = QByteArray()
        array.push_back(self.get_input().encode())
        self.data.curr_power = len(array)

        if self.data.less():
            argument = self.data.diff()
            self.set_output_message(
                "Ещё можно ввести: {} байт.".format(argument))
            return

        if self.data.max_():
            self.set_output_message("Размер сообщения достиг максимума.")
            return

        argument = self.data.rdiff()
        self.set_output_message(
            "Размер сообщения превышен на: {} байт.".format(argument))
示例#13
0
def encode_image(image: QImage) -> str:
    image_bytes = QByteArray()
    buffer = QBuffer(image_bytes)
    buffer.open(QIODevice.WriteOnly)  # type: ignore

    # writes pixmap into bytes in PNG format
    image.save(buffer, "PNG")  # type: ignore
    raw_bytes = buffer.data().data()
    b64_bytes = standard_b64encode(raw_bytes)
    b64_string = b64_bytes.decode('UTF-8')
    return b64_string
示例#14
0
    def start_request(self, ):
        token = 'c2FuY2hvcjpNVFF6TkRFME5UZ3lOVUJ4Y1M1amIyMD06MTYzNjk4MjAyNTowNjljMz' \
                'FlZjM4MDhlZjQ2YWFiYzA1NzUwMTYzMDY1ZTQyMWZkYTli'

        url = QUrl(
            'https://ladsweb.modaps.eosdis.nasa.gov/archive/orders/501675589.json'
        )
        self.http_request_aborted = False
        req = QNetworkRequest(url)
        req.setRawHeader(QByteArray('Authorization'),
                         QByteArray('Bearer ' + token))
        self.reply = self.qnam.get(req)
        self.reply.finished.connect(self.http_finished)

        progress = progress_dialog(url)
        progress.setAttribute(Qt.WA_DeleteOnClose)
        progress.canceled.connect(self.cancel_download)
        self.reply.downloadProgress.connect(progress.network_reply_progress)
        self.reply.finished.connect(progress.hide)
        progress.exec()
示例#15
0
 def set_image(self, buf: bytes) -> None:
     """
     Sets the image.
     :param buf: Image bytes to set
     """
     pix: QPixmap = QPixmap()
     pix.loadFromData(QByteArray(buf))
     self.setPixmap(pix.scaled(self.width(),
                               self.height(),
                               Qt.AspectRatioMode.KeepAspectRatio,
                               Qt.TransformationMode.SmoothTransformation))
 def textMessageReceived(self, message_data_in):
     """Deserialize the stringified JSON messageData and emit
        messageReceived."""
     message_data = QByteArray(bytes(message_data_in, encoding='utf8'))
     message = QJsonDocument.fromJson(message_data)
     if message.isNull():
         print("Failed to parse text message as JSON object:", message_data)
         return
     if not message.isObject():
         print("Received JSON message that is not an object: ",
               message_data)
         return
     self.messageReceived.emit(message.object(), self)
示例#17
0
    def encode_text(self):
        if not self.is_loaded:
            self.ui.output_label.setText("Изображение не загружено в программу")
            return

        self.used_capacity = len(self.ui.message_frame.toPlainText())
        if self.image_capacity < self.used_capacity:
            self.ui.output_label.setText("Ошибка. Недостаточно места!")
            return
            
        byte_array = QByteArray()
        byte_array.push_back(self.ui.message_frame.toPlainText().encode())
        for i in range(4):
            byte_array.push_front(bytes(((self.used_capacity >> i * 8) & 0xff,)))
        for i in range(len(MainWindow.indicator) - 1, -1, -1):
            byte_array.push_front(bytes((MainWindow.indicator[i],)))

        write_bytes(self.image, byte_array, 0)

        self.ui.output_label.setText("Сообщение успешно добавлено в изображение")
示例#18
0
class Window(metaclass=SettingsCategory):  # noqa D101
    geometry: t.Annotated[
        QByteArray,
        SettingsParams(
            "AdnQywADAAAAAAJ/AAAA+QAABDQAAAH9AAACgAAAARgAAAQzAAAB/AAAAAAAAAAAB4AAAAKAAAABGAAABDMAAAH8",
            lambda val: b64encode(val.data()).decode(),
            lambda val: QByteArray(b64decode(val.encode())),
        ),
    ]
    dark_mode: t.Annotated[Theme, SettingsParams(True, None, Theme)]
    autoscroll: t.Annotated[bool, SettingsParams(True)]
    font: t.Annotated[
        QFont,
        SettingsParams(
            "Arial,9,-1,5,700,0,0,0,0,0,0,0,0,0,0,1",
            lambda val: val.to_string(),
            _font_deserializer,
        ),
    ]
示例#19
0
class Generator(QIODevice):
    def __init__(self, format, durationUs, sampleRate, parent):
        super(Generator, self).__init__(parent)

        self.m_pos = 0
        self.m_buffer = QByteArray()

        self.generateData(format, durationUs, sampleRate)

    def start(self):
        self.open(QIODevice.ReadOnly)

    def stop(self):
        self.m_pos = 0
        self.close()

    def generateData(self, format, durationUs, sampleRate):
        pack_format = ''

        if format.sampleSize() == 8:
            if format.sampleType() == QAudioFormat.UnSignedInt:
                scaler = lambda x: ((1.0 + x) / 2 * 255)
                pack_format = 'B'
            elif format.sampleType() == QAudioFormat.SignedInt:
                scaler = lambda x: x * 127
                pack_format = 'b'
        elif format.sampleSize() == 16:
            if format.sampleType() == QAudioFormat.UnSignedInt:
                scaler = lambda x: (1.0 + x) / 2 * 65535
                pack_format = '<H' if format.byteOrder(
                ) == QAudioFormat.LittleEndian else '>H'
            elif format.sampleType() == QAudioFormat.SignedInt:
                scaler = lambda x: x * 32767
                pack_format = '<h' if format.byteOrder(
                ) == QAudioFormat.LittleEndian else '>h'

        assert (pack_format != '')

        channelBytes = format.sampleSize() // 8
        sampleBytes = format.channelCount() * channelBytes

        length = (format.sampleRate() * format.channelCount() *
                  (format.sampleSize() // 8)) * durationUs // 100000

        self.m_buffer.clear()
        sampleIndex = 0
        factor = 2 * pi * sampleRate / format.sampleRate()

        while length != 0:
            x = sin((sampleIndex % format.sampleRate()) * factor)
            packed = pack(pack_format, int(scaler(x)))

            for _ in range(format.channelCount()):
                self.m_buffer.append(packed)
                length -= channelBytes

            sampleIndex += 1

    def readData(self, maxlen):
        data = QByteArray()
        total = 0

        while maxlen > total:
            chunk = min(self.m_buffer.size() - self.m_pos, maxlen - total)
            data.append(self.m_buffer.mid(self.m_pos, chunk))
            self.m_pos = (self.m_pos + chunk) % self.m_buffer.size()
            total += chunk

        return data.data()

    def writeData(self, data):
        return 0

    def bytesAvailable(self):
        return self.m_buffer.size() + super(Generator, self).bytesAvailable()
    ]
    source_model.setHorizontalHeaderLabels(horizontal_header_list)
    for i in range(model_size):
        first_item = QStandardItem("FancyTextNumber {}".format(i))
        if i == 0:
            first_item.appendRow(add_child(2, 2))
        second_item = QStandardItem("FancyRow2TextNumber {}".format(i))
        if i % 2 == 0:
            first_item.setBackground(Qt.red)
        row = [first_item, second_item]
        source_model.invisibleRootItem().appendRow(row)
        list.append("FancyTextNumber {}".format(i))

    # Needed by QMLModelViewClient
    role_names = {
        Qt.DisplayRole: QByteArray(b'_text'),
        Qt.BackgroundRole: QByteArray(b'_color')
    }
    source_model.setItemRoleNames(role_names)

    roles = [Qt.DisplayRole, Qt.BackgroundRole]

    print("Creating registry host")
    node = QRemoteObjectRegistryHost(QUrl("local:registry"))

    node2 = QRemoteObjectHost(QUrl("local:replica"), QUrl("local:registry"))
    node2.enableRemoting(source_model, "RemoteModel", roles)

    view = QTreeView()
    view.setWindowTitle("SourceView")
    view.setModel(source_model)
    def __init__(self, item_type, songs=None, **kwargs):

        # metadata values
        # can be any type
        self.metadata = {}

        # application values
        # always strings
        self.dict = {}
        app_fields = SONG_FIELDS if item_type == TreeWidgetType.SONG else ALBUM_FIELDS
        for field in (set(kwargs.keys()) | app_fields):
            # set all mandatory settings to their defaults if not
            # specified in the parameters
            # and any extra settings specified in the parameters
            if field in kwargs:
                self.dict[field] = kwargs[field]
            else:
                # set to default setting
                self.dict[field] = get_setting(field)

            if field == 'coverArt' and self.dict[field] in QRC_TO_FILE_PATH:
                # convert resource path to real file path for ffmpeg
                self.dict[field] = QRC_TO_FILE_PATH[get_setting(field)]

        # add song metadata
        if item_type == TreeWidgetType.SONG:
            try:
                metadata = audio_metadata.load(self.dict['song_path'])

                if get_setting(
                        'extractCoverArt') == SETTINGS_VALUES.CheckBox.CHECKED:
                    # extract cover art if it exists
                    if metadata.pictures and len(metadata.pictures) > 0:
                        bytes = QByteArray(metadata.pictures[0].data)
                        cover = QTemporaryFile(
                            os.path.join(QDir().tempPath(), APPLICATION,
                                         "XXXXXX.cover"))
                        cover.setAutoRemove(False)
                        cover.open(QIODevice.WriteOnly)
                        cover.write(bytes)
                        cover.close()
                        self.set_value('coverArt', cover.fileName())

                self.metadata = flatten_metadata(metadata)

            except Exception as e:
                logging.warning(e)
                logging.warning(self.dict['song_path'])
        else:
            # album gets metadata from children
            # song metadata is stored as song.<key>
            # e.g. song.tags.album would be the album name
            #
            # we will only get metadata from one song
            # because the album shouldn't care about
            # the varying metadata values for the songs
            # such as title or track number
            for song in songs:
                if song.has_metadata():
                    for key, value in song.to_dict().items():
                        key = "song.{}".format(key)
                        self.metadata[key] = value
                    break

        self.update_fields()
示例#22
0
def write_bytes(image: QImage, byte_array: QByteArray, begin) -> None:
    end = (begin + byte_array.size()) * 8
    for i in range(begin * 8, end):
        set_bit(image, i, (int.from_bytes(byte_array[i // 8], "big") >>
                           (7 - i % 8)) & 1)
示例#23
0
 def roleNames(self):
     roles = {
         PersonModel.MyRole : QByteArray(b'modelData'),
         Qt.DisplayRole : QByteArray(b'display')
     }
     return roles
示例#24
0
def decode_image(text: str) -> QImage:
    encoded_bytes = QByteArray(text.encode('utf8'))
    image_bytes = QByteArray.fromBase64(encoded_bytes)
    image = QImage.fromData(image_bytes)
    return image
示例#25
0
    def __init__(self, parent=None):
        AbstractOperationDetails.__init__(self, parent)
        self.name = "Dividend"
        self.operation_type = LedgerTransaction.Dividend
        self.combo_model = None

        self.date_label = QLabel(self)
        self.ex_date_label = QLabel(self)
        self.number_label = QLabel(self)
        self.type_label = QLabel(self)
        self.account_label = QLabel(self)
        self.symbol_label = QLabel(self)
        self.amount_label = QLabel(self)
        self.price_label = QLabel(self)
        self.tax_label = QLabel(self)
        self.comment_label = QLabel(self)

        self.main_label.setText(self.tr("Dividend"))
        self.date_label.setText(self.tr("Date/Time"))
        self.ex_date_label.setText(self.tr("Ex-Date"))
        self.type_label.setText(self.tr("Type"))
        self.number_label.setText(self.tr("#"))
        self.account_label.setText(self.tr("Account"))
        self.symbol_label.setText(self.tr("Asset"))
        self.amount_label.setText(self.tr("Dividend"))
        self.price_label.setText(self.tr("Price"))
        self.tax_label.setText(self.tr("Tax"))
        self.comment_label.setText(self.tr("Note"))

        self.timestamp_editor = QDateTimeEdit(self)
        self.timestamp_editor.setCalendarPopup(True)
        self.timestamp_editor.setTimeSpec(Qt.UTC)
        self.timestamp_editor.setFixedWidth(self.timestamp_editor.fontMetrics().horizontalAdvance("00/00/0000 00:00:00") * 1.25)
        self.timestamp_editor.setDisplayFormat("dd/MM/yyyy hh:mm:ss")
        self.ex_date_editor = QDateEdit(self)
        self.ex_date_editor.setCalendarPopup(True)
        self.ex_date_editor.setTimeSpec(Qt.UTC)
        self.ex_date_editor.setFixedWidth(self.ex_date_editor.fontMetrics().horizontalAdvance("00/00/0000") * 1.5)
        self.ex_date_editor.setDisplayFormat("dd/MM/yyyy")
        self.type = QComboBox(self)
        self.account_widget = AccountSelector(self)
        self.asset_widget = AssetSelector(self)
        self.dividend_edit = QLineEdit(self)
        self.dividend_edit.setAlignment(Qt.AlignRight)
        self.price_edit = QLineEdit(self)
        self.price_edit.setAlignment(Qt.AlignRight)
        self.price_edit.setReadOnly(True)
        self.tax_edit = QLineEdit(self)
        self.tax_edit.setAlignment(Qt.AlignRight)
        self.number = QLineEdit(self)
        self.comment = QLineEdit(self)

        self.layout.addWidget(self.date_label, 1, 0, 1, 1, Qt.AlignLeft)
        self.layout.addWidget(self.account_label, 2, 0, 1, 1, Qt.AlignLeft)
        self.layout.addWidget(self.symbol_label, 3, 0, 1, 1, Qt.AlignLeft)
        self.layout.addWidget(self.comment_label, 4, 0, 1, 1, Qt.AlignLeft)

        self.layout.addWidget(self.timestamp_editor, 1, 1, 1, 1, Qt.AlignLeft)
        self.layout.addWidget(self.account_widget, 2, 1, 1, 4)
        self.layout.addWidget(self.asset_widget, 3, 1, 1, 4)
        self.layout.addWidget(self.comment, 4, 1, 1, 8)

        self.layout.addWidget(self.ex_date_label, 1, 2, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.ex_date_editor, 1, 3, 1, 1, Qt.AlignLeft)

        self.layout.addWidget(self.type_label, 1, 5, 1, 1, Qt.AlignLeft)
        self.layout.addWidget(self.amount_label, 2, 5, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.tax_label, 3, 5, 1, 1, Qt.AlignRight)

        self.layout.addWidget(self.type, 1, 6, 1, 1)
        self.layout.addWidget(self.dividend_edit, 2, 6, 1, 1)
        self.layout.addWidget(self.tax_edit, 3, 6, 1, 1)

        self.layout.addWidget(self.number_label, 1, 7, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.price_label, 2, 7, 1, 1, Qt.AlignRight)

        self.layout.addWidget(self.number, 1, 8, 1, 1)
        self.layout.addWidget(self.price_edit, 2, 8, 1, 1)

        self.layout.addWidget(self.commit_button, 0, 9, 1, 1)
        self.layout.addWidget(self.revert_button, 0, 10, 1, 1)

        self.layout.addItem(self.verticalSpacer, 5, 0, 1, 1)
        self.layout.addItem(self.horizontalSpacer, 1, 8, 1, 1)

        super()._init_db("dividends")
        self.combo_model = QStringListModel([self.tr("N/A"),
                                             self.tr("Dividend"),
                                             self.tr("Bond Interest"),
                                             self.tr("Stock Dividend")])
        self.type.setModel(self.combo_model)

        self.mapper.setItemDelegate(DividendWidgetDelegate(self.mapper))

        self.account_widget.changed.connect(self.mapper.submit)
        self.asset_widget.changed.connect(self.assetChanged)
        self.type.currentIndexChanged.connect(self.typeChanged)
        self.timestamp_editor.dateTimeChanged.connect(self.refreshAssetPrice)

        self.mapper.addMapping(self.timestamp_editor, self.model.fieldIndex("timestamp"))
        self.mapper.addMapping(self.ex_date_editor, self.model.fieldIndex("ex_date"))
        self.mapper.addMapping(self.account_widget, self.model.fieldIndex("account_id"))
        self.mapper.addMapping(self.asset_widget, self.model.fieldIndex("asset_id"))
        self.mapper.addMapping(self.type, self.model.fieldIndex("type"), QByteArray().setRawData("currentIndex", 12))
        self.mapper.addMapping(self.number, self.model.fieldIndex("number"))
        self.mapper.addMapping(self.dividend_edit, self.model.fieldIndex("amount"))
        self.mapper.addMapping(self.tax_edit, self.model.fieldIndex("tax"))
        self.mapper.addMapping(self.comment, self.model.fieldIndex("note"))

        self.model.select()
示例#26
0
def write_bytes(image: QImage, array: QByteArray, start) -> None:
    for i in range(to_bits(start), to_bits(start + array.size())):
        set_bit(image, i, (int.from_bytes(array[i // 8], "big") >>
                           (7 - i % 8)) & 1)
示例#27
0
def Base64ToBytes(filename):
    image = QImage(filename)
    ba = QByteArray()
    buff = QBuffer(ba)
    image.save(buff, "PNG")
    return ba.toBase64().data()
示例#28
0
def GMakeIcon(base64):
    pixmap = QPixmap()
    pixmap.loadFromData(QByteArray.fromBase64(base64))
    icon = QIcon(pixmap)
    return icon
    def __init__(self, parent=None):
        AbstractOperationDetails.__init__(self, parent)
        self.name = "Corporate action"
        self.combo_model = None

        self.date_label = QLabel(self)
        self.account_label = QLabel(self)
        self.type_label = QLabel(self)
        self.number_label = QLabel(self)
        self.before_label = QLabel(self)
        self.asset_b_label = QLabel(self)
        self.qty_b_label = QLabel(self)
        self.after_label = QLabel(self)
        self.asset_a_label = QLabel(self)
        self.qty_a_label = QLabel(self)
        self.ratio_label = QLabel(self)
        self.comment_label = QLabel(self)
        self.arrow_asset = QLabel(self)
        self.arrow_amount = QLabel(self)

        self.main_label.setText(self.tr("Corporate Action"))
        self.date_label.setText(self.tr("Date/Time"))
        self.account_label.setText(self.tr("Account"))
        self.type_label.setText(self.tr("Type"))
        self.number_label.setText(self.tr("#"))
        self.asset_b_label.setText(self.tr("Asset"))
        self.qty_b_label.setText(self.tr("Qty"))
        self.asset_a_label.setText(self.tr("Asset"))
        self.qty_a_label.setText(self.tr("Qty"))
        self.ratio_label.setText(self.tr("% of basis"))
        self.comment_label.setText(self.tr("Note"))
        self.arrow_asset.setText(" ➜ ")
        self.arrow_amount.setText(" ➜ ")

        self.timestamp_editor = QDateTimeEdit(self)
        self.timestamp_editor.setCalendarPopup(True)
        self.timestamp_editor.setTimeSpec(Qt.UTC)
        self.timestamp_editor.setFixedWidth(
            self.timestamp_editor.fontMetrics().horizontalAdvance(
                "00/00/0000 00:00:00") * 1.25)
        self.timestamp_editor.setDisplayFormat("dd/MM/yyyy hh:mm:ss")
        self.type = QComboBox(self)
        self.account_widget = AccountSelector(self)
        self.asset_b_widget = AssetSelector(self)
        self.asset_a_widget = AssetSelector(self)
        self.qty_b_edit = QLineEdit(self)
        self.qty_a_edit = QLineEdit(self)
        self.ratio_edit = QLineEdit(self)
        self.number = QLineEdit(self)
        self.comment = QLineEdit(self)

        self.layout.addWidget(self.date_label, 1, 0, 1, 1, Qt.AlignLeft)
        self.layout.addWidget(self.type_label, 2, 0, 1, 1, Qt.AlignLeft)
        self.layout.addWidget(self.number_label, 3, 0, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.comment_label, 5, 0, 1, 6, Qt.AlignLeft)

        self.layout.addWidget(self.timestamp_editor, 1, 1, 1, 1)
        self.layout.addWidget(self.type, 2, 1, 1, 1)
        self.layout.addWidget(self.number, 3, 1, 1, 1)
        self.layout.addWidget(self.comment, 5, 1, 1, 6)

        self.layout.addWidget(self.account_label, 1, 2, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.asset_b_label, 2, 2, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.qty_b_label, 3, 2, 1, 1, Qt.AlignRight)

        self.layout.addWidget(self.account_widget, 1, 3, 1, 4)
        self.layout.addWidget(self.asset_b_widget, 2, 3, 1, 1)
        self.layout.addWidget(self.qty_b_edit, 3, 3, 1, 1)

        self.layout.addWidget(self.arrow_asset, 2, 4, 1, 1)
        self.layout.addWidget(self.arrow_amount, 3, 4, 1, 1)

        self.layout.addWidget(self.asset_a_label, 2, 5, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.qty_a_label, 3, 5, 1, 1, Qt.AlignRight)
        self.layout.addWidget(self.ratio_label, 4, 5, 1, 1, Qt.AlignRight)

        self.layout.addWidget(self.asset_a_widget, 2, 6, 1, 1)
        self.layout.addWidget(self.qty_a_edit, 3, 6, 1, 1)
        self.layout.addWidget(self.ratio_edit, 4, 6, 1, 1)

        self.layout.addWidget(self.commit_button, 0, 8, 1, 1)
        self.layout.addWidget(self.revert_button, 0, 9, 1, 1)

        self.layout.addItem(self.verticalSpacer, 6, 0, 1, 1)
        self.layout.addItem(self.horizontalSpacer, 1, 7, 1, 1)

        super()._init_db("corp_actions")
        self.combo_model = QStringListModel([
            self.tr("N/A"),
            self.tr("Merger"),
            self.tr("Spin-Off"),
            self.tr("Symbol change"),
            self.tr("Split"),
            self.tr("Stock dividend")
        ])
        self.type.setModel(self.combo_model)

        self.mapper.setItemDelegate(CorporateActionWidgetDelegate(self.mapper))

        self.account_widget.changed.connect(self.mapper.submit)
        self.asset_b_widget.changed.connect(self.mapper.submit)
        self.asset_a_widget.changed.connect(self.mapper.submit)

        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.asset_b_widget,
                               self.model.fieldIndex("asset_id"))
        self.mapper.addMapping(self.asset_a_widget,
                               self.model.fieldIndex("asset_id_new"))
        self.mapper.addMapping(self.number, self.model.fieldIndex("number"))
        self.mapper.addMapping(self.qty_b_edit, self.model.fieldIndex("qty"))
        self.mapper.addMapping(self.qty_a_edit,
                               self.model.fieldIndex("qty_new"))
        self.mapper.addMapping(self.ratio_edit,
                               self.model.fieldIndex("basis_ratio"))
        self.mapper.addMapping(self.comment, self.model.fieldIndex("note"))
        self.mapper.addMapping(self.type, self.model.fieldIndex("type"),
                               QByteArray().setRawData("currentIndex", 12))

        self.model.select()