Esempio n. 1
0
class AccountModal(QDialog):
    def __init__(self, parent):
        QDialog.__init__(self)
        self.account_group_box = QGroupBox("Account")
        self.modal_error_label = QLabel(
            "Wrong address, account must be written in form : '0x...'.")
        self.account_group_layout = QFormLayout()
        self.new_addr_line = QLineEdit()
        self.modal_error_label.hide()
        self.account_group_layout.addRow(self.modal_error_label)
        self.parent = parent
        self.account_group_layout.addRow(QLabel("Write your private key:"),
                                         self.new_addr_line)
        self.modal_save = QPushButton("Save")
        self.modal_save.clicked.connect(self.modal_save_func)

        self.modal_cancel = QPushButton("Cancel")
        # self.modal_cancel.clicked.connect(self.modal_cancel_func)
        self.account_group_layout.addRow(self.modal_save, self.modal_cancel)

        self.modal_cancel.clicked.connect(self.modal_cancel_func)
        self.setLayout(self.account_group_layout)

    """
    It is function to save private key for the current session
    (private key isn't stored, as it would take a lot of time to provide
    necessary security for such a task.
    """

    def modal_save_func(self):
        new_addr = self.new_addr_line.displayText()
        if re.fullmatch("[0-9a-f]{64}", new_addr):
            self.modal_error_label.hide()
            self.hide()
            self.p_key = new_addr
            self.parent.update_pkey(self.p_key)
        else:
            self.new_addr_line.setText("")
            self.modal_error_label.setText(
                "Wrong address, account must be written in form : 'e91f...'(total length is 64 characters in hexadecimal form)."
            )
            self.modal_error_label.show()

    """
    This method is for the modal window, to return to the main screen from adding private key
    """

    def modal_cancel_func(self):
        self.modal_error_label.hide()
        self.hide()
Esempio n. 2
0
class ContractModal(QDialog):

    def __init__(self, parent):
        QDialog.__init__(self)

        # This is modal window to add new contract to work with
        self.modal_group_box = QGroupBox("Contract")
        self.modal_error_label = QLabel("Wrong address, account must be written in form : '0x...'.")
        self.modal_group_layout = QFormLayout()
        self.new_addr_line = QLineEdit()
        self.modal_error_label.hide()
        self.modal_group_layout.addRow(self.modal_error_label)

        self.modal_group_layout.addRow(QLabel("Write address of new contract:"), self.new_addr_line)
        self.modal_add = QPushButton("Add")

        self.modal_add.clicked.connect(self.modal_add_func)
        self.modal_cancel = QPushButton("Cancel")
        self.modal_cancel.clicked.connect(self.modal_cancel_func)
        self.modal_group_layout.addRow(self.modal_add, self.modal_cancel)
        self.parent = parent
        self.setLayout(self.modal_group_layout)


    """
     This method adds address from textbox(in the modal window) to the list, and checks if it satisfies needed format
    """
    def modal_add_func(self):
        new_addr = self.new_addr_line.displayText()
        if re.fullmatch("0x[0-9A-Fa-f]{40}", new_addr):
            self.modal_error_label.hide()
            self.new_addr_line.setText("")
            self.hide()
            self.parent.add_cont_address(new_addr)
        else:
            self.new_addr_line.setText("")
            self.modal_error_label.setText("Wrong address, account must be written in form : '0x...'.")
            self.modal_error_label.show()

    """
    This method is for the modal window, to return to the main screen from adding new Registry smart contract
    """
    def modal_cancel_func(self):
        self.modal_error_label.hide()
        self.hide()
Esempio n. 3
0
class mainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.activeImage = ""
        self.previewImage = ""
        self.n = 400  #Set image display max size

        #Top Row Setup
        self.hedder = QLabel("Welcome to the Image Restoration App")

        #Button Row Setup
        self.selectButton = QPushButton("Click to select an image.")
        self.selectButton.clicked.connect(self.imageSelect)
        self.option1 = QPushButton("Black and White to Color")
        self.option1.clicked.connect(self.bandwToColorFilter)
        self.option2 = QPushButton("Denoise Image")
        self.option2.clicked.connect(self.denoiseFilter)
        self.option3 = QPushButton("Sharpen Image")
        self.option3.clicked.connect(self.sharpenFilter)
        self.option4 = QPushButton("Resize Image")
        self.option4.clicked.connect(self.resizeFilter)
        self.resizePercent = QLineEdit(self)
        self.saveImage = QPushButton("Save Image")
        self.saveImage.clicked.connect(self.imageSave)
        self.saveLabel = QLabel("Save name ->")
        self.saveName = QLineEdit(self)

        self.optionsRow = QHBoxLayout()
        self.optionsRow.addWidget(self.selectButton)
        self.optionsRow.addWidget(self.option1)
        self.optionsRow.addWidget(self.option2)
        self.optionsRow.addWidget(self.option3)
        self.optionsRow.addWidget(self.option4)
        self.optionsRow.addWidget(self.resizePercent)
        self.optionsRow.addWidget(self.saveLabel)
        self.optionsRow.addWidget(self.saveName)
        self.optionsRow.addWidget(self.saveImage)

        #Image Display Setup
        self.activeImageDisplay = QLabel()
        self.previewImageDisplay = QLabel()

        self.imageDisplayRow = QHBoxLayout()
        self.imageDisplayRow.addWidget(self.activeImageDisplay)
        self.imageDisplayRow.addWidget(self.previewImageDisplay)

        #Main Layout Setup
        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(self.hedder)
        self.mainLayout.addLayout(self.optionsRow)
        self.mainLayout.addLayout(self.imageDisplayRow)

        self.setLayout(self.mainLayout)

    def imageSelect(self):  #function for selecting image
        self.activeImage = easygui.fileopenbox()
        pixmap = QPixmap(self.activeImage)
        self.previewImage = ""
        self.previewImageDisplay.clear()
        if str(pixmap.size()
               ) == "PySide2.QtCore.QSize(0, 0)":  #checks if image is valid
            self.activeImage = ""
            self.activeImageDisplay.clear()
            self.hedder.setText("Warning: Invalid image.")
            self.repaint()
        else:  #if image is valid, sets and displays image
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.activeImageDisplay.setPixmap(pixmap)
            self.hedder.setText("Image selected. Now, apply a filter.")
            self.previewImageDisplay.clear()
            self.repaint()

    def bandwToColorFilter(self):  #code to run bandwToColor, save and display
        if self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = bandwToColor(self.previewImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = bandwToColor(self.activeImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def denoiseFilter(self):  #code to run denoise, save and display
        if self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = denoise(self.previewImage)
            imPath = self.previewImage
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = denoise(self.activeImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def sharpenFilter(self):  #code to run sharpen, save and display
        if self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = sharpen(self.previewImage)
            imPath = self.previewImage
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = sharpen(self.activeImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def resizeFilter(self):  #code to run resize, save and "display"
        if self.resizePercent.displayText().isnumeric() == False:
            self.hedder.setText(
                "Warning: You must imput an integer for the resize. Greater than 100 increases size, less than 100 decreases size."
            )
            self.repaint()
        elif int(self.resizePercent.displayText()) < 0.0:
            self.hedder.setText(
                "Warning: Resize must be number greater than 0.")
            self.repaint()
        elif self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = resize(self.previewImage,
                                       int(self.resizePercent.displayText()))
            imPath = self.previewImage
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Warning: Resize may not be visible in app. Now, apply additional filters or save."
            )
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = resize(self.activeImage,
                                       int(self.resizePercent.displayText()))
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Warning: Resize may not be visible in app. Now, apply additional filters or save."
            )
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def imageSave(self):  #code to save image
        if self.previewImage == "":  #checks if image is ready
            self.hedder.setText(
                "Warning: No image to save. Upload an image to edit or apply a filter."
            )
            self.repaint()
        elif self.saveName.displayText() == "":  #checks if name is valid
            self.hedder.setText(
                "Warning: No name for image. Add a name before hitting save.")
            self.repaint()
        else:
            im = Image.open(self.previewImage)
            if "." in self.saveName.displayText(
            ):  #checks if save name as extension
                fileName = self.saveName.displayText()
            else:  #if not, defaults to extension of original image
                extension = findExtension(self.activeImage)
                fileName = self.saveName.displayText() + extension
            im.save(fileName)
            self.hedder.setText(
                "Image saved! Remember to change the save name before saving more images."
            )
Esempio n. 4
0
class ToggleStatsEditor (QGroupBox, PropertyWidget):
    def __init__(self, target_property_name):
        QGroupBox.__init__(self)
        PropertyWidget.__init__(self, target_property_name)
        self.main_layout = QFormLayout(self)

        self.buffer_editor = QLineEdit()
        self.buffer_editor.editingFinished.connect(self._on_buffer_edit)
        self.buffer_editor.setInputMask("HH HH HH HH HH HH HH HH;0")
        self.buffer_editor.setVisible(False)

        self.stats_layout = QFormLayout()
        self.stats_layout.setContentsMargins(0, 0, 0, 0)
        self.stat_editors = [
            QSpinBox(),
            QSpinBox(),
            QSpinBox(),
            QSpinBox(),
            QSpinBox(),
            QSpinBox(),
            QSpinBox(),
            QSpinBox()
        ]
        labels = self._get_labels_for_project()
        for i in range(0, 8):
            editor = self.stat_editors[i]
            editor.setRange(-128, 127)
            self.stats_layout.addRow(QLabel(labels[i]), editor)

        self.stats_widget = QWidget()
        self.stats_widget.setLayout(self.stats_layout)

        self.editor_toggle = QPushButton("Toggle Stats/Hex Editor")
        self.editor_toggle.clicked.connect(self._on_editor_toggle)

        self.main_layout.addRow(self.editor_toggle)
        self.main_layout.addRow(self.stats_widget)

        self.stat_editors[0].valueChanged.connect(lambda: self._on_stat_edit(0))
        self.stat_editors[1].valueChanged.connect(lambda: self._on_stat_edit(1))
        self.stat_editors[2].valueChanged.connect(lambda: self._on_stat_edit(2))
        self.stat_editors[3].valueChanged.connect(lambda: self._on_stat_edit(3))
        self.stat_editors[4].valueChanged.connect(lambda: self._on_stat_edit(4))
        self.stat_editors[5].valueChanged.connect(lambda: self._on_stat_edit(5))
        self.stat_editors[6].valueChanged.connect(lambda: self._on_stat_edit(6))
        self.stat_editors[7].valueChanged.connect(lambda: self._on_stat_edit(7))

    @staticmethod
    def _get_labels_for_project():
        driver = service_locator.locator.get_scoped("Driver")
        project = driver.get_project()
        if project.game == Game.FE15.value:
            return EDITOR_LABELS_SOV
        else:
            return EDITOR_LABELS

    def _on_editor_toggle(self):
        show_stats = self.buffer_editor.isVisible()
        self.buffer_editor.setVisible(not show_stats)
        self.stats_widget.setVisible(show_stats)
        self.main_layout.takeAt(1)
        if show_stats:
            self.main_layout.addRow(self.stats_widget)
        else:
            self.main_layout.addRow(self.buffer_editor)

    def _on_buffer_edit(self):
        if self.target:
            buffer = self._get_target_value()
            split_text = self.buffer_editor.displayText().split()
            for j in range(8):
                buffer[j] = int(split_text[j], 16)
            self._on_target_changed()

    def _on_stat_edit(self, index):
        if self.target:
            buffer = self._get_target_value()
            value = self.stat_editors[index].value()
            binary_value = struct.pack("b", value)
            unsigned_value = int(struct.unpack("B", binary_value)[0])
            buffer[index] = unsigned_value
            self._on_target_changed()

    def _on_target_changed(self):
        if self.target:
            buffer = self._get_target_value()
            self.buffer_editor.setText(" ".join("%02x" % x for x in buffer))
            for i in range(0, 8):
                binary_value = struct.pack("B", buffer[i])
                value = int(struct.unpack("b", binary_value)[0])
                self.stat_editors[i].setValue(value)
        else:
            self.buffer_editor.setText("00 00 00 00 00 00 00 00")
            for editor in self.stat_editors:
                editor.setValue(0)
Esempio n. 5
0
class Cramolayout(QDialog):
    def __init__(self, parent=None):
        super(Cramolayout, self).__init__(parent)
        layout = QGridLayout()
        # layout.setColumnStretch(1, 3)
        # layout.setRowStretch(1, 3)
        layout.setColumnMinimumWidth(0, 100)
        layout.setColumnMinimumWidth(1, 100)
        layout.setColumnMinimumWidth(2, 100)
        layout.setColumnMinimumWidth(3, 100)

        self.btn_get_dtm = QPushButton("DTM file")
        self.btn_get_dtm.clicked.connect(self.get_dtm)
        layout.addWidget(self.btn_get_dtm, 0, 0)

        self.dtm_line = QLineEdit()
        layout.addWidget(self.dtm_line, 0, 1, 1, 3)

        self.btn_get_shp = QPushButton("shp file")
        self.btn_get_shp.clicked.connect(self.get_column_names)
        layout.addWidget(self.btn_get_shp, 1, 0)

        self.shp_line = QLineEdit()
        layout.addWidget(self.shp_line, 1, 1, 1, 3)

        self.lblName = QLabel('Id', self)
        self.lblName.setStyleSheet("font: 9pt Myriad Pro")
        layout.addWidget(self.lblName, 3, 0)

        self.lblName = QLabel('Crater size', self)
        self.lblName.setStyleSheet("font: 9pt Myriad Pro")
        layout.addWidget(self.lblName, 3, 1)

        self.lblName = QLabel('X coord', self)
        self.lblName.setStyleSheet("font: 9pt Myriad Pro")
        layout.addWidget(self.lblName, 3, 2)

        self.lblName = QLabel('Y coord', self)
        self.lblName.setStyleSheet("font: 9pt Myriad Pro")
        layout.addWidget(self.lblName, 3, 3)

        self.id_box = QComboBox()
        layout.addWidget(self.id_box, 4, 0)

        self.size_box = QComboBox()
        layout.addWidget(self.size_box, 4, 1)

        self.x_coord_box = QComboBox()
        layout.addWidget(self.x_coord_box, 4, 2)

        self.y_coord_box = QComboBox()
        layout.addWidget(self.y_coord_box, 4, 3)

        self.chk_size = QCheckBox('Radius', self)
        self.chk_size.toggle()
        layout.addWidget(self.chk_size, 5, 1)

        self.chk_unit = QCheckBox('Size in meters', self)
        self.chk_unit.toggle()
        layout.addWidget(self.chk_unit, 6, 1)

        self.start_btn = QPushButton("Start cramo")
        # self.start_btn.clicked.connect(self.choose_parameters)
        self.start_btn.clicked.connect(self.create_for_txt_file)
        self.start_btn.clicked.connect(self.start_cramo)
        layout.addWidget(self.start_btn, 7, 0, 1, 4)

        # self.textEdit = QTextEdit(self)
        # self.textEdit.setStyleSheet("font: 9pt Myriad Pro")
        # layout.addWidget(self.start_btn, 8, 0)

        self.setWindowTitle("easyCramo V2")
        self.setLayout(layout)

    def get_dtm(self):
        dtm_path, filtr = QFileDialog.getOpenFileName(
            self, "QFileDialog.getOpenFileName()", self.dtm_line.text(),
            "DTM file (*.tif *.bsq *.img *tiff)", "")
        if dtm_path:
            self.dtm_line.setText(dtm_path)
            # print(dtm_path)
        return dtm_path

    def get_shp(self):
        shp_path, filtr = QFileDialog.getOpenFileName(
            self, "QFileDialog.getOpenFileName()", self.shp_line.text(),
            "Shp Files (*.shp)", "")
        if shp_path:
            self.shp_line.setText(shp_path)
            # print(shp_path)
        return shp_path

    def get_column_names(self):
        shp_file = self.get_shp()
        driver = ogr.GetDriverByName('ESRI Shapefile')
        ogrData = driver.Open(shp_file, 0)
        layer = ogrData.GetLayer(0)
        featDef = layer.GetLayerDefn()
        for i in range(featDef.GetFieldCount()):
            fieldDef = featDef.GetFieldDefn(i)
            field_name = fieldDef.GetNameRef()
            self.id_box.addItem(field_name)
            self.size_box.addItem(field_name)
            self.x_coord_box.addItem(field_name)
            self.y_coord_box.addItem(field_name)

    def choose_parameters(self):
        if self.chk_size.isChecked() is True:
            size = 2
        else:
            size = 1
        if self.chk_unit.isChecked() is True:
            length_unit = 1
        else:
            length_unit = 1000
        return (length_unit, size)

    def check_dtm(self):
        dtm_path = self.dtm_line.displayText()

    def get_geo_info(self):
        gdalData = gdal.Open(self.dtm_line.displayText())
        geo_info = gdalData.GetGeoTransform()
        return geo_info

    def create_for_txt_file(self):
        shp_path = self.shp_line.displayText()
        dtm_path = self.dtm_line.displayText()
        start_dir = os.path.dirname(shp_path)
        start_file = str(os.path.basename(shp_path))
        for_cramo_abs_path = start_dir + '\\for_' + start_file.split(
            '.')[0] + '.txt'
        for_txt = open(for_cramo_abs_path, 'w')
        # print(start_file.split('.')[0])
        # print(shp_path)
        # print(for_cramo_abs_path)

        geo_info = self.get_geo_info()
        pix_scale = geo_info[1]
        x0 = geo_info[0]
        y0 = geo_info[3]

        driver = ogr.GetDriverByName('ESRI Shapefile')
        ogrData = driver.Open(shp_path, 0)
        layer = ogrData.GetLayer(0)
        circle_coef = int(self.choose_parameters()[0])
        unit = int(self.choose_parameters()[1])
        print(circle_coef, unit)
        # print(type(circle_coef), type(unit))
        for crat_feature in layer:
            crat_id = str(int(crat_feature.GetField(
                self.id_box.currentText())))
            size = str(
                int((crat_feature.GetField(self.size_box.currentText())
                     )  # / 2 # проверить как лучше так или делить на 2
                    * (unit) * (circle_coef) // pix_scale))
            x_coord = str(
                int((crat_feature.GetField(self.x_coord_box.currentText()) -
                     x0) // pix_scale))
            y_coord = str(
                int((y0 -
                     crat_feature.GetField(self.y_coord_box.currentText())) //
                    pix_scale))
            for_txt.write(crat_id + ' ' + x_coord + ' ' + y_coord + ' ' +
                          size + '\n')

    def start_cramo(self):
        start_time = QDateTime.currentDateTime()
        s_time = start_time.toString(Qt.DefaultLocaleShortDate)
        print(s_time)

        shp_path = self.shp_line.displayText()
        dtm_path = self.dtm_line.displayText()
        start_file = str(os.path.basename(shp_path))
        start_dir = str(os.path.dirname(shp_path))
        start_dtm_file = str(os.path.basename(dtm_path))
        for_cramo_txt = 'for_' + start_file.split('.')[0] + '.txt'
        res_cramo_txt = 'res_' + start_file.split('.')[0] + '.txt'

        cmdcommand = 'cramo_app.ex' + ' ' + start_dtm_file + ' < ' + for_cramo_txt + ' > ' + res_cramo_txt
        print(cmdcommand)
        # print('cramo=', cmd_cram)
        infodir = 'info_' + start_file.split('.')[0] + '.txt'
        infotxt = open(infodir, 'w')
        infotxt.write(cmdcommand)
        infotxt.close()
        os.chdir(start_dir)
        os.system(cmdcommand)
        end_time = QDateTime.currentDateTime()
        e_time = end_time.toString(Qt.DefaultLocaleShortDate)
        print(e_time)
        print('ready')
Esempio n. 6
0
class Cramolayout(QDialog):

   def __init__(self, parent=None):
      super(Cramolayout, self).__init__(parent)
      layout = QGridLayout()
      # layout.setColumnStretch(1, 3)
      # layout.setRowStretch(1, 3)
      layout.setColumnMinimumWidth(0, 100)
      layout.setColumnMinimumWidth(1, 100)
      layout.setColumnMinimumWidth(2, 200)
      layout.setColumnMinimumWidth(3, 100)

      self.btn_get_dtm = QPushButton("DTM file")
      self.btn_get_dtm.clicked.connect(self.get_dtm)
      layout.addWidget(self.btn_get_dtm, 0, 0)

      self.dtm_line = QLineEdit()
      layout.addWidget(self.dtm_line, 0, 1, 1, 3)

      self.start_btn = QPushButton("Create txt")
      self.start_btn.clicked.connect(self.start_time)
      self.start_btn.clicked.connect(self.create_txt)
      self.start_btn.clicked.connect(self.end_time)
      self.start_btn.clicked.connect(self.msgbox)
      layout.addWidget(self.start_btn, 1, 0, 1, 4)

      self.setWindowTitle("DTM coordinate")
      self.setLayout(layout)


   def start_time(self):
       start_time = QDateTime.currentDateTime()
       self.s_time = start_time.toString(Qt.DefaultLocaleShortDate)
       # print('start time', self.s_time)



   def get_dtm(self):
      dtm_path, filtr = QFileDialog.getOpenFileName(self,
                                                              "QFileDialog.getOpenFileName()",
                                                    self.dtm_line.text(),
                                                               "DTM file (*.tif *.bsq *.img *tiff)", "")
      if dtm_path:
         self.dtm_line.setText(dtm_path)


   def create_txt(self):

       data_raster = gdal.Open(self.dtm_line.displayText())
       geo_info = data_raster.GetGeoTransform()
       band = data_raster.GetRasterBand(1)
       data_proj = data_raster.GetProjectionRef()
       data_srs = osr.SpatialReference(data_proj)
       geo_srs = data_srs.CloneGeogCS()  # new srs obj to go from x,y -> φ,λ
       geo_transform = osr.CoordinateTransformation(data_srs, geo_srs)

       dtm_arr = band.ReadAsArray()
       dtm_path = self.dtm_line.displayText()
       dtm_array = dtm_path.split('.')[0] + '_array_1.txt'
       array_txt = open(dtm_array, 'w')
       array_txt.write('Heights  ' + 'x  ' + 'y' + '\n')
       line_count = 0
       txt_count = 1

       bag = gdal.Open(self.dtm_line.displayText())  # replace it with your file
       bag_gtrn = bag.GetGeoTransform()
       bag_proj = bag.GetProjectionRef()
       bag_srs = osr.SpatialReference(bag_proj)
       geo_srs = bag_srs.CloneGeogCS()  # new srs obj to go from x,y -> φ,λ
       transform = osr.CoordinateTransformation(bag_srs, geo_srs)


       y_index = 0
       for lines in dtm_arr:
           x_index = 0
           for h_value in lines:
               line_count += 1
               if line_count == 200000:
                   temp_dtm_txt = dtm_path.split('.')[0] + '_array_' + str(txt_count) + '.txt'
                   array_txt = open(temp_dtm_txt, 'w')
                   array_txt.write('Heights  ' + 'x  ' +'y'+ '\n')
                   line_count = 0
                   txt_count += 1
               # print('n =', n)
               x2 = geo_info[0] + geo_info[1] * x_index + geo_info[2] * y_index
               y2 = geo_info[3] + geo_info[4] * x_index + geo_info[5] * y_index
               geo_pt = transform.TransformPoint(x2, y2) [:2]
               geo_x = geo_pt[0]
               geo_y = geo_pt[1]
               min_delim = "' "
               sec = r'" '
               # print(x_index, y_index, geo_pt)
               if geo_pt[0] < 0:
                   x_degree = int(-geo_x // 1)
                   x_min = int((-geo_x - x_degree) * 60)
                   x_sec = ((-geo_x - x_degree) * 60 - x_min) * 60
                   x_coord = str(x_degree) + '° ' + str(x_min) + min_delim + str(x_sec) + sec + ' S'
               else:
                   x_degree = int(geo_x // 1)
                   x_min = (int(geo_x - x_degree) * 60)
                   x_sec = ((geo_x - x_degree) * 60 - x_min) * 60
                   x_coord = str(x_degree) + '° ' + str(x_min) + min_delim + str(x_sec) + sec + ' N'
               if geo_pt[1] < 0:
                   y_degree = int(-geo_y // 1)
                   y_min = int((-geo_y - y_degree) * 60)
                   y_sec = ((-geo_y - y_degree) * 60 - y_min) * 60
                   y_coord = str(y_degree) + '° ' + str(y_min) + min_delim + str(y_sec) + sec + ' W'
               else:
                   y_degree = int(geo_y // 1)
                   y_min = int((geo_y - y_degree) * 60)
                   y_sec = ((geo_y - y_degree) * 60 - y_min) * 60

                   y_coord = str(y_degree) + '° ' + str(y_min) + min_delim + str(y_sec) + sec + 'W'

               # print(x_degree, x_min, x_sec)
               # print(y_degree, y_min, y_sec)
               array_txt.write(str(float(h_value)) + '   ' + x_coord + '    '+ y_coord + '  '  + '\n')
               x_index += 1
           y_index += 1


   def end_time(self):
        end_time = QDateTime.currentDateTime()
        self.e_time = end_time.toString(Qt.DefaultLocaleShortDate)
        # print('end_time', self.e_time)


   def msgbox(self):
       msgb1 = QMessageBox()
       msgb1.setWindowTitle("Complited")
       msgb1.setIcon(QMessageBox.Information)
       msgb1.setText('start time:  ' + self.s_time + '\n' + 'end-time:  ' + self.e_time)
       msgb1.setGeometry(200, 80, 250, 20)
       retval = msgb1.exec_()
Esempio n. 7
0
class LogFilterWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self._initUI()
        self._initData()

    def _initUI(self):
        self.mainLayout = QHBoxLayout(self)
        # self.treeModel = QFileSystemModel(self)
        # self.treeView = QTreeView(self)
        self.setAcceptDrops(True)
        #
        # self.treeView.setModel(self.treeModel)
        # self.treeView.setSortingEnabled(True)
        # self.treeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        # self.treeView.customContextMenuRequested.connect(self.showContextMenu)
        # self.mainLayout.addWidget(self.treeView)
        self.editTabsView = QTabWidget(self)
        self.editTabsView.setTabsClosable(True)
        self.editTabsView.setMovable(True)
        self.editTabsView.setDocumentMode(True)
        self.editTabsView.tabCloseRequested.connect(self.tabCloseRequested)
        self.contentLayout = QVBoxLayout(self)
        self.topHandlerLayout = QHBoxLayout(self)
        self.input = QLineEdit(self)
        self.searchButton = QPushButton(self)
        self.searchButton.clicked.connect(self.handerFilter)
        self.searchButton.setText("搜索当前文件")

        self.searchButtonAll = QPushButton(self)
        self.searchButtonAll.clicked.connect(self.handerFilterAll)
        self.searchButtonAll.setText("搜索全部文件")

        self.topHandlerLayout.addWidget(self.input, 1)
        self.topHandlerLayout.addWidget(self.searchButton)
        self.topHandlerLayout.addWidget(self.searchButtonAll)

        self.contentLayout.addLayout(self.topHandlerLayout)

        self.contentLayout.addWidget(self.editTabsView, 1)
        self.mainLayout.addLayout(self.contentLayout, 1)
        self.setLayout(self.mainLayout)
        self._initMenus()
        RxBus.instance.register(self, Class.LogInfo).pipe(
            ops.subscribe_on(scheduler.ThreadPoolScheduler()),
            qtScheduler.QtScheduler()).subscribe(
                on_next=lambda value: self.handlerLogInfo(value))

    def handerFilterAll(self):
        self.startFilter(-1)

    def handerFilter(self):
        self.startFilter(self.editTabsView.currentIndex())

    def startFilter(self, index):
        searchTag = self.input.displayText()
        print(searchTag)
        filterData = list()
        if index == -1:
            print("全部")
            for i in range(self.editTabsView.count()):
                currentTab = self.editTabsView.widget(i)
                data = currentTab.toPlainText()
                filterData.append(data)

        else:
            data = self.editTabsView.currentWidget().toPlainText()
            filterData.append(data)
        Fiter().filter(searchTag, filterData).pipe(
            ops.subscribe_on(scheduler.ThreadPoolScheduler()),
            qtScheduler.QtScheduler()).subscribe(
                on_next=lambda filterResult: self.handlerFilterResult(
                    filterResult),
                on_error=lambda e: self.handlerFilterErrorResult(e),
            )

    def handlerFilterErrorResult(self, error):
        print("error")
        print(error)
        box = QErrorMessage(self)
        box.showMessage(error, "结果提示")
        box.exec_()

    def handlerFilterResult(self, filterResult):
        self.editTabsView.currentWidget().handlerFilterResult(filterResult)

    def _initData(self):
        pass

    def tabCloseRequested(self, index):
        self.editTabsView.removeTab(index)

    def _initMenus(self):
        pass

    def showContextMenu(self, pos):
        index = self.treeView.indexAt(pos)

    def dragEnterEvent(self, event: PySide2.QtGui.QDragEnterEvent):
        print("dragEnterEvent")
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
        else:
            event.ignore()

    def dropEvent(self, event: PySide2.QtGui.QDropEvent):
        print("dropEvent")

        data = event.mimeData()
        if data.hasUrls():
            urls = data.urls()
            if len(urls) <= 0:
                return
            files = list()
            for fileUrl in urls:
                print("fileUrl:%s" % fileUrl)
                if fileUrl.isLocalFile():
                    files.append(fileUrl.toLocalFile())
            self.addFile(files)

    def addFile(self, files):
        def _createObserver(subscription: rx.typing.Subscription,
                            scheduler) -> rx.Observable:
            for file in files:
                print("file:%s" % file)
                with open(file, mode='r') as f:
                    content = f.readlines()
                subscription.on_next(Class.LogInfo(file, "".join(content)))

        rx.create(_createObserver).pipe(
            ops.subscribe_on(scheduler.ThreadPoolScheduler()),
            qtScheduler.QtScheduler()).subscribe(
                on_next=lambda value: self.handlerLogInfoResult(value))

    def handlerLogInfoResult(self, data):
        RxBus.instance.post(data)

    def closeEvent(self, event: PySide2.QtGui.QCloseEvent):
        print("LogFilterWidget close")
        RxBus.instance.unRegister(self)
        event.isAccepted()

    def handlerLogInfo(self, data: Class.LogInfo):
        print("handlerLogInfo %s" % data.title)
        editWidget = EditWidget()
        editWidget.setLogData(data)
        logTitle = data.title
        # (text, ok) = QInputDialog.getText(None, "日志名称", "名称", text=logTitle)
        # if ok and text:
        #     logTitle = text
        self.editTabsView.addTab(editWidget, data.title)
        # self.editTabsView.setTabWhatsThis(self.editTabsView.count() - 1, data.title)
        self.editTabsView.setTabToolTip(self.editTabsView.count() - 1,
                                        data.title)
        self.editTabsView.setCurrentIndex(self.editTabsView.count() - 1)
        # self.editTabsView.setCurrentIndex(0)
        pass
class guiMain(QMainWindow):
    def __init__(self, bk, prefs):
        super(guiMain, self).__init__()
        self.taglist = taglist
        # Edit Plugin container object
        self.bk = bk

        # Handy prefs groupings
        self.gui_prefs = prefs['gui_selections']
        self.misc_prefs = prefs['miscellaneous_settings']
        self.update_prefs = prefs['update_settings']
        self.combobox_values = prefs['combobox_values']

        self._ok_to_close = False
        # Check online github files for newer version
        self.update, self.newversion = self.check_for_update()
        self.setup_ui()

    def setup_ui(self):
        app = QApplication.instance()
        p = app.palette()
        link_color = p.color(p.Active, p.Link).name()

        DELETE_STR = _t('guiMain', 'Delete')
        MODIFY_STR = _t('guiMain', 'Modify')
        self.NO_ATTRIB_STR = _t('guiMain', 'No attributes (naked tag)')
        self.NO_CHANGE_STR = _t('guiMain', 'No change')
        self.setWindowTitle(_t('guiMain', 'Tag Mechanic'))

        configAct = QAction(_t('guiMain', '&Config'), self)
        configAct.triggered.connect(self.showConfig)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu(_t('guiMain', '&Edit'))
        fileMenu.addAction(configAct)

        layout = QVBoxLayout()

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

        if self.update:
            update_layout = QHBoxLayout()
            layout.addLayout(update_layout)
            self.label = QLabel()
            self.label.setText(
                _t('guiMain', 'Plugin Update Available') + ' ' +
                str(self.newversion))
            self.label.setStyleSheet(
                'QLabel {{color: {};}}'.format(link_color))
            update_layout.addWidget(self.label)

        action_layout = QHBoxLayout()
        layout.addLayout(action_layout)
        label = QLabel(_t('guiMain', 'Action type:'), self)
        action_layout.addWidget(label)
        self.action_combo = QComboBox()
        action_layout.addWidget(self.action_combo)
        self.action_combo.addItems([DELETE_STR, MODIFY_STR])
        self.action_combo.setCurrentIndex(self.gui_prefs['action'])
        self.action_combo.currentIndexChanged.connect(self.update_gui)

        tag_layout = QHBoxLayout()
        layout.addLayout(tag_layout)
        label = QLabel(_t('guiMain', 'Tag name:'), self)
        tag_layout.addWidget(label)
        self.tag_combo = QComboBox()
        tag_layout.addWidget(self.tag_combo)
        self.tag_combo.addItems(self.taglist)
        self.tag_combo.setCurrentIndex(self.gui_prefs['tag'])
        self.tag_combo.currentIndexChanged.connect(self.update_gui)

        attr_layout = QHBoxLayout()
        layout.addLayout(attr_layout)
        label = QLabel(_t('guiMain', 'Having the attribute:'), self)
        attr_layout.addWidget(label)
        self.attr_combo = QComboBox()
        attr_layout.addWidget(self.attr_combo)
        self.attr_combo.addItems(self.combobox_values['attrs'])
        self.attr_combo.addItem(self.NO_ATTRIB_STR)
        self.attr_combo.setCurrentIndex(self.gui_prefs['attrs'])
        self.attr_combo.currentIndexChanged.connect(self.update_gui)

        srch_layout = QHBoxLayout()
        layout.addLayout(srch_layout)
        label = QLabel(_t('guiMain', 'Whose value is (no quotes):'), self)
        srch_layout.addWidget(label)
        self.srch_txt = QLineEdit('', self)
        srch_layout.addWidget(self.srch_txt)
        self.srch_method = QCheckBox(_t('guiMain', 'Regex'), self)
        srch_layout.addWidget(self.srch_method)

        newtag_layout = QHBoxLayout()
        layout.addLayout(newtag_layout)
        label = QLabel(_t('guiMain', 'Change tag to:'), self)
        newtag_layout.addWidget(label)
        self.newtag_combo = QComboBox()
        newtag_layout.addWidget(self.newtag_combo)

        self.newtag_combo.addItem(self.NO_CHANGE_STR)
        self.newtag_combo.addItems(self.combobox_values['{}_changes'.format(
            str(self.tag_combo.currentText()))])

        if self.action_combo.currentIndex() == 0:
            self.newtag_combo.setDisabled(True)

        newattr_layout = QVBoxLayout()
        layout.addLayout(newattr_layout)
        label = QLabel(
            _t('guiMain', 'New attribute string to insert (entire):'), self)
        newattr_layout.addWidget(label)
        self.newattr_txt = QLineEdit('', self)
        newattr_layout.addWidget(self.newattr_txt)
        self.copy_attr = QCheckBox(
            _t('guiMain', 'Copy existing attribute string'), self)
        self.copy_attr.stateChanged.connect(self.update_txt_box)
        newattr_layout.addWidget(self.copy_attr)
        if self.action_combo.currentIndex() == 0:
            self.copy_attr.setDisabled(True)
            self.newattr_txt.setDisabled(True)

        layout.addSpacing(10)
        self.text_panel = QTextEdit()
        self.text_panel.setReadOnly(True)
        layout.addWidget(self.text_panel)

        layout.addSpacing(10)
        button_layout = QHBoxLayout()
        layout.addLayout(button_layout)
        self.process_button = QPushButton(_t('guiMain', 'Process'), self)
        self.process_button.setToolTip('<p>{}'.format(
            _t('guiMain', 'Process selected files with current criteria')))
        self.process_button.clicked.connect(self._process_clicked)
        button_layout.addWidget(self.process_button)

        self.abort_button = QPushButton(_t('guiMain', 'Abort Changes'), self)
        self.abort_button.setToolTip('<p>{}'.format(
            _t('guiMain', 'Make no changes and exit')))
        self.abort_button.clicked.connect(self._abort_clicked)
        self.abort_button.setDisabled(True)
        button_layout.addWidget(self.abort_button)

        self.quit_button = QPushButton(_t('guiMain', 'Quit'), self)
        self.quit_button.setToolTip('<p>{}'.format(
            _t('guiMain', 'Quit with no changes')))
        self.quit_button.clicked.connect(self._quit_clicked)
        button_layout.addWidget(self.quit_button)

        if self.misc_prefs['windowGeometry'] is not None:
            try:
                self.restoreGeometry(
                    QByteArray.fromHex(
                        self.misc_prefs['windowGeometry'].encode('ascii')))
            except Exception:
                pass
        self.show()

    def update_gui(self):
        if self.attr_combo.currentIndex() == self.attr_combo.count() - 1:
            self.srch_txt.clear()
            self.srch_txt.setDisabled(True)
            self.srch_method.setChecked(False)
            self.srch_method.setDisabled(True)
        else:
            self.srch_txt.setDisabled(False)
            self.srch_method.setDisabled(False)

        self.newtag_combo.clear()
        self.newtag_combo.addItem(self.NO_CHANGE_STR)
        self.newtag_combo.addItems(self.combobox_values['{}_changes'.format(
            str(self.tag_combo.currentText()))])

        if self.action_combo.currentIndex() == 0:
            self.newtag_combo.setCurrentIndex(0)
            self.newtag_combo.setDisabled(True)
            self.newattr_txt.clear()
            self.newattr_txt.setDisabled(True)
            self.copy_attr.setChecked(False)
            self.copy_attr.setDisabled(True)
        else:
            self.newtag_combo.setDisabled(False)
            self.newattr_txt.setDisabled(False)
            self.copy_attr.setDisabled(False)

        self.update_txt_box()

    def update_txt_box(self):
        if self.copy_attr.isChecked() or not self.copy_attr.isEnabled():
            self.newattr_txt.clear()
            self.newattr_txt.setDisabled(True)
        else:
            self.newattr_txt.setDisabled(False)

    def refresh_attr_values(self):
        self.attr_combo.clear()
        self.attr_combo.addItems(self.combobox_values['attrs'])
        self.attr_combo.addItem(self.NO_ATTRIB_STR)

    def _process_clicked(self):
        criteria = {}
        global PROCESSED
        criteria['tag'] = str(self.tag_combo.currentText())
        if self.action_combo.currentIndex() == 0:
            criteria['action'] = 'delete'
        else:
            criteria['action'] = 'modify'
        if self.attr_combo.currentIndex() == self.attr_combo.count() - 1:
            criteria['attrib'] = None
        else:
            criteria['attrib'] = str(self.attr_combo.currentText())
        srch_str = str(self.srch_txt.displayText())
        if not len(srch_str):
            srch_str = None
        if srch_str is None and criteria['attrib'] is not None:
            title = _t('guiMain', 'Error')
            msg = '<p>{0}'.format(
                _t('guiMain', 'Must enter a value for the attribute selected'))
            return QMessageBox.warning(self, title, msg, QMessageBox.Ok)
        criteria['srch_str'] = srch_str

        criteria['srch_method'] = 'normal'
        if self.srch_method.isChecked():
            criteria['srch_method'] = 'regex'
        if self.newtag_combo.currentIndex() == 0:
            criteria['new_tag'] = None
        else:
            criteria['new_tag'] = str(self.newtag_combo.currentText())
        if criteria['action'] == 'modify' and criteria[
                'new_tag'] is None and self.copy_attr.isChecked():
            title = _t('guiMain', 'Error')
            msg = '<p>{0}'.format(
                _t('guiMain', 'What--exactly--would that achieve?'))
            return QMessageBox.question(self, title, msg, QMessageBox.Ok)

        criteria['new_str'] = str(self.newattr_txt.displayText())
        criteria['copy'] = False
        if self.copy_attr.isChecked():
            criteria['copy'] = True
        if not len(criteria['new_str']):
            criteria['new_str'] = ''

        # Disable the 'Process' button, disable the context customization menu
        self.process_button.setDisabled(True)
        PROCESSED = True

        totals = 0
        self.text_panel.clear()
        self.text_panel.insertHtml('<h4>{}...</h4><br>'.format(
            _t('guiMain', 'Starting')))

        # Loop through the files selected in Sigil's Book View
        for (typ, ident) in self.bk.selected_iter():
            # Skip the ones that aren't the "Text" mimetype.
            if self.bk.id_to_mime(ident) != 'application/xhtml+xml':
                continue
            href = self.bk.id_to_href(ident)
            # Param 1 - the contents of the (x)html file.
            criteria['html'] = self.bk.readfile(ident)
            if not isinstance(criteria['html'], str):
                criteria['html'] = str(criteria['html'], 'utf-8')

            # Hand off the "criteria" parameters dictionary to the parsing engine
            parser = MarkupParser(criteria)

            # Retrieve the new markup and the number of occurrences changed
            try:
                html, occurrences = parser.processml()
            except Exception:
                self.text_panel.insertHtml('<p>{} {}! {}.</p>\n'.format(
                    _t('guiMain', 'Error parsing'), href,
                    _t('guiMain', 'File skipped')))
                continue

            # Report whether or not changes were made (and how many)
            totals += occurrences
            if occurrences:
                # write changed markup back to file
                self.bk.writefile(ident, html)
                self.text_panel.insertHtml(
                    '<p>{} {}:&#160;&#160;&#160;{}</p>\n'.format(
                        _t('guiMain', 'Occurrences found/changed in'), href,
                        int(occurrences)))
            else:
                self.text_panel.insertHtml('<p>{} {}</p>\n'.format(
                    _t('guiMain', 'Criteria not found in'), href))

        # report totals
        if totals:
            self.quit_button.setText(_t('guiMain', 'Commit and Exit'))
            self.quit_button.setToolTip('<p>{}'.format(
                _t('guiMain', 'Commit all changes and exit')))
            self.abort_button.setDisabled(False)
            self.text_panel.insertHtml(
                '<br><h4>{}:&#160;&#160;&#160;{}</h4>'.format(
                    _t('guiMain', 'Total occurrences found/changed'),
                    int(totals)))
        else:
            self.text_panel.insertHtml('<br><h4>{}</h4>'.format(
                _t('guiMain', 'No changes made to book')))
        self.text_panel.insertHtml('<br><h4>{}</h4>'.format(
            _t('guiMain', 'Finished')))

    def _quit_clicked(self):
        self.misc_prefs['windowGeometry'] = self.saveGeometry().toHex().data(
        ).decode('ascii')
        if PROCESSED:
            self.gui_prefs['action'] = self.action_combo.currentIndex()
            self.gui_prefs['tag'] = self.tag_combo.currentIndex()
            self.gui_prefs['attrs'] = self.attr_combo.currentIndex()
        self._ok_to_close = True
        self.close()

    def _abort_clicked(self):
        global BAIL_OUT
        BAIL_OUT = True
        self._ok_to_close = True
        self.close()

    def getAbort(self):
        return BAIL_OUT

    def showConfig(self):
        ''' Launch Customization Dialog '''
        dlg = ConfigDialog(self, self.combobox_values)
        if dlg.exec_() == QDialog.Accepted:
            self.refresh_attr_values()
            self.update_gui()

    def check_for_update(self):
        '''Use updatecheck.py to check for newer versions of the plugin'''
        last_time_checked = self.update_prefs['last_time_checked']
        last_online_version = self.update_prefs['last_online_version']
        chk = UpdateChecker(last_time_checked, last_online_version, self.bk._w)
        update_available, online_version, time = chk.update_info()
        # update preferences with latest date/time/version
        self.update_prefs['last_time_checked'] = time
        if online_version is not None:
            self.update_prefs['last_online_version'] = online_version
        if update_available:
            return (True, online_version)
        return (False, online_version)

    def closeEvent(self, event):
        if self._ok_to_close:
            event.accept()  # let the window close
        else:
            self._abort_clicked()
class ConfigDialog(QDialog):
    def __init__(self, parent, combobox_values):
        super().__init__()
        self.gui = parent
        self.combobox_values = combobox_values
        self.qlinedit_widgets = {}
        self.setup_ui()
        self.setWindowTitle(_t('ConfigDialog', 'Customize Tag Mechanic'))

    def setup_ui(self):
        layout = QVBoxLayout()
        self.setLayout(layout)
        columns_frame = QHBoxLayout()
        layout.addLayout(columns_frame)

        # How many columns of nine items each will it take to display
        # a text box for each tag in taglist?
        col_limit = 8
        num_cols = len(taglist) / col_limit
        num_cols = int(math.ceil(num_cols))

        # If the column limit and the number of columns produces a single
        # orphan text entry widget, reduce the column limit accordingly.
        if num_cols > 1 and (len(taglist) - ((num_cols - 1) * col_limit)) < 2:
            if num_cols >= 3:
                col_limit -= 1
        # Create an integer-indexed dictionary of QVBoxLayouts representing the number of
        # columns necessary. Added left to right in the parent QHBoxLayout.
        column = {}
        for i in range(1, num_cols + 1):
            column[i] = QVBoxLayout()
            column[i].setAlignment(Qt.AlignLeft)
            columns_frame.addLayout(column[i])

        # Create a dictionary of QLineEdit widgets (indexed by tag name) and stack them
        # (top to bottom) and their labels in as many columns as it takes.
        curr_col = 1
        curr_item = 1
        tooltip = _t(
            'ConfigDialog',
            'Comma separated list of html elements (no quotes, no angle "&lt;" brackets).'
        )
        for tag in taglist:
            # Column item limit surpassed - switch to next column.
            if curr_item > col_limit:
                column[curr_col].addStretch()
                curr_col += 1
                curr_item = 1
            # Add lable and QLineEdit widget to current column.
            label = QLabel(
                '<b>{} "{}" {}</b>'.format(
                    _t('ConfigDialog', 'Choices to change'), tag,
                    _t('ConfigDialog', 'elements to:')), self)
            label.setAlignment(Qt.AlignCenter)
            self.qlinedit_widgets[tag] = QLineEdit(
                ', '.join(self.combobox_values['{}_changes'.format(tag)]),
                self)
            self.qlinedit_widgets[tag].setToolTip('<p>{}'.format(tooltip))
            column[curr_col].addWidget(label)
            column[curr_col].addWidget(self.qlinedit_widgets[tag])

            if not len(self.combobox_values['{}_changes'.format(tag)]):
                self.qlinedit_widgets[tag].setDisabled(True)
            curr_item += 1
        column[curr_col].addStretch()

        layout.addSpacing(10)
        attrs_layout = QVBoxLayout()
        attrs_layout.setAlignment(Qt.AlignCenter)
        layout.addLayout(attrs_layout)
        label = QLabel(
            '<b>{}</b>'.format(
                _t('ConfigDialog',
                   'HTML attributes available to search for:')), self)
        label.setAlignment(Qt.AlignCenter)
        self.attrs_txtBox = QLineEdit(', '.join(self.combobox_values['attrs']),
                                      self)
        self.attrs_txtBox.setToolTip('<p>{}'.format(
            _t('ConfigDialog',
               'Comma separated list of html attribute names (no quotes).')))
        attrs_layout.addWidget(label)
        attrs_layout.addWidget(self.attrs_txtBox)

        layout.addSpacing(10)
        right_layout = QHBoxLayout()
        right_layout.setAlignment(Qt.AlignRight)
        layout.addLayout(right_layout)
        reset_button = QPushButton(_t('ConfigDialog', 'Reset all defaults'),
                                   self)
        reset_button.setToolTip('<p>{}'.format(
            _t('ConfigDialog', 'Reset all settings to original defaults.')))
        reset_button.clicked.connect(self.reset_defaults)
        right_layout.addWidget(reset_button)

        layout.addSpacing(10)
        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self.save_settings)
        button_box.rejected.connect(self.reject)
        layout.addWidget(button_box)

    def save_settings(self):
        # Save current dialog sttings back to JSON config file
        for tag in taglist:
            tmp_list = str(self.qlinedit_widgets[tag].displayText()).split(',')
            tmp_list = remove_dupes([x.strip(' ') for x in tmp_list])
            self.combobox_values['{}_changes'.format(tag)] = list(
                filter(None, tmp_list))

        tmp_list = str(self.attrs_txtBox.displayText()).split(',')
        tmp_list = remove_dupes([x.strip(' ') for x in tmp_list])
        self.combobox_values['attrs'] = list(filter(None, tmp_list))
        self.accept()

    def reset_defaults(self):
        caption = _t('ConfigDialog', 'Are you sure?')
        msg = '<p>{}'.format(
            _t('ConfigDialog',
               'Reset all customizable options to their original defaults?'))
        if QMessageBox.question(self, caption, msg, QMessageBox.Yes
                                | QMessageBox.Cancel) == QMessageBox.Yes:
            for tag in taglist:
                self.combobox_values['{}_changes'.format(
                    tag)] = combobox_defaults['{}_changes'.format(tag)]
            self.combobox_values['attrs'] = combobox_defaults['attrs']
            self.accept()