class ButtonLineEdit(QLineEdit):
    buttonClicked = pyqtSignal()

    def __init__(self, parent=None):
        super(ButtonLineEdit, self).__init__(parent)

        self.setPlaceholderText("Search")

        self.btnSearch = QToolButton(self)
        self.btnSearch.setIcon(QIcon(os.path.join(pluginPath, "icons", "search.svg")))
        self.btnSearch.setStyleSheet("QToolButton { padding: 0px; }")
        self.btnSearch.setCursor(Qt.ArrowCursor)
        self.btnSearch.clicked.connect(self.buttonClicked.emit)

        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        buttonSize = self.btnSearch.sizeHint()

        self.setStyleSheet("QLineEdit {{padding-right: {}px; }}".format(buttonSize.width() + frameWidth + 1))
        self.setMinimumSize(max(self.minimumSizeHint().width(), buttonSize.width() + frameWidth * 2 + 2),
                            max(self.minimumSizeHint().height(), buttonSize.height() + frameWidth * 2 + 2))

    def resizeEvent(self, event):
        buttonSize = self.btnSearch.sizeHint()
        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        self.btnSearch.move(self.rect().right() - frameWidth - buttonSize.width(),
                            (self.rect().bottom() - buttonSize.height() + 1) / 2)

        super(ButtonLineEdit, self).resizeEvent(event)
Exemplo n.º 2
0
class PasswordLineEdit(QLineEdit):
    def __init__(self, parent=None):
        QLineEdit.__init__(self, parent)

        self.setPlaceholderText(self.tr("Password"))
        self.setEchoMode(QLineEdit.Password)

        self.btnIcon = QToolButton(self)
        self.btnIcon.setIcon(QIcon(os.path.join(iconsPath, "lock.svg")))
        self.btnIcon.setEnabled(False)
        self.btnIcon.setStyleSheet(
            "QToolButton { border: none; padding: 0px; }")

        self.btnToggle = QToolButton(self)
        self.btnToggle.setIcon(QIcon(os.path.join(iconsPath, "eye-slash.svg")))
        self.btnToggle.setCheckable(True)
        self.btnToggle.setToolTip(self.tr("Toggle password visibility"))
        self.btnToggle.setCursor(Qt.ArrowCursor)
        self.btnToggle.setStyleSheet(
            "QToolButton { border: none; padding: 0px; }")

        self.btnToggle.toggled.connect(self.togglePassword)

        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        self.setStyleSheet(
            "QLineEdit {{ padding-right: {}px; padding-left: {}px }} ".format(
                self.btnToggle.sizeHint().width() + frameWidth + 1,
                self.btnIcon.sizeHint().width() + frameWidth + 1))
        msz = self.minimumSizeHint()
        self.setMinimumSize(
            max(msz.width(),
                self.btnToggle.sizeHint().height() + frameWidth * 2 + 2),
            max(msz.height(),
                self.btnToggle.sizeHint().height() + frameWidth * 2 + 2))

    def resizeEvent(self, event):
        frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)

        sz = self.btnIcon.sizeHint()
        self.btnIcon.move(frameWidth + 1,
                          (self.rect().bottom() + 1 - sz.height()) / 2)

        sz = self.btnToggle.sizeHint()
        self.btnToggle.move(self.rect().right() - frameWidth - sz.width(),
                            (self.rect().bottom() + 1 - sz.height()) / 2)

    def togglePassword(self, toggled):
        if toggled:
            self.setEchoMode(QLineEdit.Normal)
            self.btnToggle.setIcon(QIcon(os.path.join(iconsPath, "eye.svg")))
        else:
            self.setEchoMode(QLineEdit.Password)
            self.btnToggle.setIcon(
                QIcon(os.path.join(iconsPath, "eye-slash.svg")))
Exemplo n.º 3
0
class AlgorithmDialogBase(BASE, WIDGET):
    def __init__(self, alg):
        super(AlgorithmDialogBase,
              self).__init__(iface.mainWindow() if iface else None)
        self.setupUi(self)

        # don't collapse parameters panel
        self.splitter.setCollapsible(0, False)

        # add collapse button to splitter
        splitterHandle = self.splitter.handle(1)
        handleLayout = QVBoxLayout()
        handleLayout.setContentsMargins(0, 0, 0, 0)
        self.btnCollapse = QToolButton(splitterHandle)
        self.btnCollapse.setAutoRaise(True)
        self.btnCollapse.setFixedSize(12, 12)
        self.btnCollapse.setCursor(Qt.ArrowCursor)
        handleLayout.addWidget(self.btnCollapse)
        handleLayout.addStretch()
        splitterHandle.setLayout(handleLayout)

        self.settings = QgsSettings()
        self.splitter.restoreState(
            self.settings.value("/Processing/dialogBaseSplitter",
                                QByteArray()))
        self.restoreGeometry(
            self.settings.value("/Processing/dialogBase", QByteArray()))
        self.splitterState = self.splitter.saveState()
        self.splitterChanged(0, 0)

        self.executed = False
        self.mainWidget = None
        self.alg = alg

        self.setWindowTitle(self.alg.displayName())

        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.accept)

        # Rename OK button to Run
        self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok)
        self.btnRun.setText(self.tr('Run'))

        self.buttonCancel.setEnabled(False)

        self.btnClose = self.buttonBox.button(QDialogButtonBox.Close)

        self.buttonBox.helpRequested.connect(self.openHelp)

        self.btnCollapse.clicked.connect(self.toggleCollapsed)
        self.splitter.splitterMoved.connect(self.splitterChanged)

        # desktop = QDesktopWidget()
        # if desktop.physicalDpiX() > 96:
        # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96)

        algHelp = self.formatHelp(self.alg)
        if algHelp is None:
            self.textShortHelp.hide()
        else:
            self.textShortHelp.document().setDefaultStyleSheet(
                '''.summary { margin-left: 10px; margin-right: 10px; }
                                                    h2 { color: #555555; padding-bottom: 15px; }
                                                    a { text-decoration: none; color: #3498db; font-weight: bold; }
                                                    p { color: #666666; }
                                                    b { color: #333333; }
                                                    dl dd { margin-bottom: 5px; }'''
            )
            self.textShortHelp.setHtml(algHelp)

        def linkClicked(url):
            webbrowser.open(url.toString())

        self.textShortHelp.anchorClicked.connect(linkClicked)

        self.showDebug = ProcessingConfig.getSetting(
            ProcessingConfig.SHOW_DEBUG_IN_DIALOG)

    def createFeedback(self):
        feedback = AlgorithmDialogFeedback(self)
        feedback.progressChanged.connect(self.setPercentage)
        feedback.error.connect(self.error)
        feedback.progress_text.connect(self.setText)
        feedback.info.connect(self.setInfo)
        feedback.command_info.connect(self.setCommand)
        feedback.debug_info.connect(self.setDebugInfo)
        feedback.console_info.connect(self.setConsoleInfo)

        self.buttonCancel.clicked.connect(feedback.cancel)
        return feedback

    def formatHelp(self, alg):
        text = alg.shortHelpString()
        if not text:
            return None
        return "<h2>%s</h2>%s" % (alg.displayName(), "".join(
            ["<p>%s</p>" % s for s in text.split("\n")]))

    def closeEvent(self, event):
        self._saveGeometry()
        super(AlgorithmDialogBase, self).closeEvent(event)

    def setMainWidget(self, widget):
        if self.mainWidget is not None:
            QgsProject.instance().layerWasAdded.disconnect(
                self.mainWidget.layerRegistryChanged)
            QgsProject.instance().layersWillBeRemoved.disconnect(
                self.mainWidget.layerRegistryChanged)
        self.mainWidget = widget
        self.tabWidget.widget(0).layout().addWidget(self.mainWidget)
        QgsProject.instance().layerWasAdded.connect(
            self.mainWidget.layerRegistryChanged)
        QgsProject.instance().layersWillBeRemoved.connect(
            self.mainWidget.layerRegistryChanged)

    def error(self, msg):
        self.setInfo(msg, True)
        self.resetGUI()
        self.tabWidget.setCurrentIndex(1)

    def resetGUI(self):
        self.lblProgress.setText('')
        self.progressBar.setMaximum(100)
        self.progressBar.setValue(0)
        self.btnRun.setEnabled(True)
        self.btnClose.setEnabled(True)

    def setInfo(self, msg, error=False, escape_html=True):
        if error:
            self.txtLog.append(
                '<span style="color:red">{}</span><br />'.format(msg,
                                                                 quote=False))
        elif escape_html:
            self.txtLog.append(html.escape(msg))
        else:
            self.txtLog.append(msg)

    def setCommand(self, cmd):
        if self.showDebug:
            self.txtLog.append('<code>{}<code>'.format(
                html.escape(cmd, quote=False)))

    def setDebugInfo(self, msg):
        if self.showDebug:
            self.txtLog.append('<span style="color:blue">{}</span>'.format(
                html.escape(msg, quote=False)))

    def setConsoleInfo(self, msg):
        if self.showDebug:
            self.txtLog.append(
                '<code><span style="color:darkgray">{}</span></code>'.format(
                    html.escape(msg, quote=False)))

    def setPercentage(self, value):
        if self.progressBar.maximum() == 0:
            self.progressBar.setMaximum(100)
        self.progressBar.setValue(value)

    def setText(self, text):
        self.lblProgress.setText(text)
        self.setInfo(text, False)

    def getParamValues(self):
        return {}

    def accept(self):
        pass

    def reject(self):
        self._saveGeometry()
        super(AlgorithmDialogBase, self).reject()

    def finish(self, successful, result, context, feedback):
        pass

    def toggleCollapsed(self):
        if self.helpCollapsed:
            self.splitter.restoreState(self.splitterState)
            self.btnCollapse.setArrowType(Qt.RightArrow)
        else:
            self.splitterState = self.splitter.saveState()
            self.splitter.setSizes([1, 0])
            self.btnCollapse.setArrowType(Qt.LeftArrow)
        self.helpCollapsed = not self.helpCollapsed

    def splitterChanged(self, pos, index):
        if self.splitter.sizes()[1] == 0:
            self.helpCollapsed = True
            self.btnCollapse.setArrowType(Qt.LeftArrow)
        else:
            self.helpCollapsed = False
            self.btnCollapse.setArrowType(Qt.RightArrow)

    def openHelp(self):
        algHelp = self.alg.helpUrl()
        if not algHelp:
            algHelp = QgsHelp.helpUrl("processing_algs/{}/{}".format(
                self.alg.provider().id(), self.alg.id())).toString()

        if algHelp not in [None, ""]:
            webbrowser.open(algHelp)

    def _saveGeometry(self):
        self.settings.setValue("/Processing/dialogBaseSplitter",
                               self.splitter.saveState())
        self.settings.setValue("/Processing/dialogBase", self.saveGeometry())

    class InvalidParameterValue(Exception):
        def __init__(self, param, widget):
            (self.parameter, self.widget) = (param, widget)
Exemplo n.º 4
0
class AlgorithmDialogBase(BASE, WIDGET):

    def __init__(self, alg):
        super(AlgorithmDialogBase, self).__init__(iface.mainWindow() if iface else None)
        self.setupUi(self)

        # don't collapse parameters panel
        self.splitter.setCollapsible(0, False)

        # add collapse button to splitter
        splitterHandle = self.splitter.handle(1)
        handleLayout = QVBoxLayout()
        handleLayout.setContentsMargins(0, 0, 0, 0)
        self.btnCollapse = QToolButton(splitterHandle)
        self.btnCollapse.setAutoRaise(True)
        self.btnCollapse.setFixedSize(12, 12)
        self.btnCollapse.setCursor(Qt.ArrowCursor)
        handleLayout.addWidget(self.btnCollapse)
        handleLayout.addStretch()
        splitterHandle.setLayout(handleLayout)

        self.settings = QgsSettings()
        self.splitter.restoreState(self.settings.value("/Processing/dialogBaseSplitter", QByteArray()))
        self.restoreGeometry(self.settings.value("/Processing/dialogBase", QByteArray()))
        self.splitterState = self.splitter.saveState()
        self.splitterChanged(0, 0)

        self.executed = False
        self.mainWidget = None
        self.alg = alg

        self.setWindowTitle(self.alg.displayName())

        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.accept)

        # Rename OK button to Run
        self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok)
        self.btnRun.setText(self.tr('Run'))

        self.buttonCancel.setEnabled(False)

        self.btnClose = self.buttonBox.button(QDialogButtonBox.Close)

        self.buttonBox.helpRequested.connect(self.openHelp)

        self.btnCollapse.clicked.connect(self.toggleCollapsed)
        self.splitter.splitterMoved.connect(self.splitterChanged)

        # desktop = QDesktopWidget()
        # if desktop.physicalDpiX() > 96:
        # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96)

        algHelp = self.formatHelp(self.alg)
        if algHelp is None:
            self.textShortHelp.hide()
        else:
            self.textShortHelp.document().setDefaultStyleSheet('''.summary { margin-left: 10px; margin-right: 10px; }
                                                    h2 { color: #555555; padding-bottom: 15px; }
                                                    a { text-decoration: none; color: #3498db; font-weight: bold; }
                                                    p { color: #666666; }
                                                    b { color: #333333; }
                                                    dl dd { margin-bottom: 5px; }''')
            self.textShortHelp.setHtml(algHelp)

        def linkClicked(url):
            webbrowser.open(url.toString())

        self.textShortHelp.anchorClicked.connect(linkClicked)

        self.showDebug = ProcessingConfig.getSetting(
            ProcessingConfig.SHOW_DEBUG_IN_DIALOG)

    def createFeedback(self):
        feedback = AlgorithmDialogFeedback(self)
        feedback.progressChanged.connect(self.setPercentage)
        feedback.error.connect(self.error)
        feedback.progress_text.connect(self.setText)
        feedback.info.connect(self.setInfo)
        feedback.command_info.connect(self.setCommand)
        feedback.debug_info.connect(self.setDebugInfo)
        feedback.console_info.connect(self.setConsoleInfo)

        self.buttonCancel.clicked.connect(feedback.cancel)
        return feedback

    def formatHelp(self, alg):
        text = alg.shortHelpString()
        if not text:
            return None
        return "<h2>%s</h2>%s" % (alg.displayName(), "".join(["<p>%s</p>" % s for s in text.split("\n")]))

    def closeEvent(self, event):
        self._saveGeometry()
        super(AlgorithmDialogBase, self).closeEvent(event)

    def setMainWidget(self, widget):
        if self.mainWidget is not None:
            QgsProject.instance().layerWasAdded.disconnect(self.mainWidget.layerRegistryChanged)
            QgsProject.instance().layersWillBeRemoved.disconnect(self.mainWidget.layerRegistryChanged)
        self.mainWidget = widget
        self.tabWidget.widget(0).layout().addWidget(self.mainWidget)
        QgsProject.instance().layerWasAdded.connect(self.mainWidget.layerRegistryChanged)
        QgsProject.instance().layersWillBeRemoved.connect(self.mainWidget.layerRegistryChanged)

    def error(self, msg):
        self.setInfo(msg, True)
        self.resetGUI()
        self.tabWidget.setCurrentIndex(1)

    def resetGUI(self):
        self.lblProgress.setText('')
        self.progressBar.setMaximum(100)
        self.progressBar.setValue(0)
        self.btnRun.setEnabled(True)
        self.btnClose.setEnabled(True)

    def setInfo(self, msg, error=False, escape_html=True):
        if error:
            self.txtLog.append('<span style="color:red">{}</span><br />'.format(msg, quote=False))
        elif escape_html:
            self.txtLog.append(html.escape(msg))
        else:
            self.txtLog.append(msg)

    def setCommand(self, cmd):
        if self.showDebug:
            self.txtLog.append('<code>{}<code>'.format(html.escape(cmd, quote=False)))

    def setDebugInfo(self, msg):
        if self.showDebug:
            self.txtLog.append('<span style="color:blue">{}</span>'.format(html.escape(msg, quote=False)))

    def setConsoleInfo(self, msg):
        if self.showDebug:
            self.txtLog.append('<code><span style="color:darkgray">{}</span></code>'.format(html.escape(msg, quote=False)))

    def setPercentage(self, value):
        if self.progressBar.maximum() == 0:
            self.progressBar.setMaximum(100)
        self.progressBar.setValue(value)

    def setText(self, text):
        self.lblProgress.setText(text)
        self.setInfo(text, False)

    def getParamValues(self):
        return {}

    def accept(self):
        pass

    def reject(self):
        self._saveGeometry()
        super(AlgorithmDialogBase, self).reject()

    def finish(self, successful, result, context, feedback):
        pass

    def toggleCollapsed(self):
        if self.helpCollapsed:
            self.splitter.restoreState(self.splitterState)
            self.btnCollapse.setArrowType(Qt.RightArrow)
        else:
            self.splitterState = self.splitter.saveState()
            self.splitter.setSizes([1, 0])
            self.btnCollapse.setArrowType(Qt.LeftArrow)
        self.helpCollapsed = not self.helpCollapsed

    def splitterChanged(self, pos, index):
        if self.splitter.sizes()[1] == 0:
            self.helpCollapsed = True
            self.btnCollapse.setArrowType(Qt.LeftArrow)
        else:
            self.helpCollapsed = False
            self.btnCollapse.setArrowType(Qt.RightArrow)

    def openHelp(self):
        algHelp = self.alg.helpUrl()
        if not algHelp:
            algHelp = QgsHelp.helpUrl("processing_algs/{}/{}".format(
                self.alg.provider().id(), self.alg.id())).toString()

        if algHelp not in [None, ""]:
            webbrowser.open(algHelp)

    def _saveGeometry(self):
        self.settings.setValue("/Processing/dialogBaseSplitter", self.splitter.saveState())
        self.settings.setValue("/Processing/dialogBase", self.saveGeometry())

    class InvalidParameterValue(Exception):

        def __init__(self, param, widget):
            (self.parameter, self.widget) = (param, widget)
Exemplo n.º 5
0
class ExpressionLineEdit(QLineEdit):
    def __init__(self, column, host=None, parent=None):
        # Use a different pixmap

        self._current_profile = current_profile()

        QLineEdit.__init__(self, parent)

        self.column = column
        self._entity = self.column.entity

        self.layer = self.create_layer()
        self.host = host
        # Configure load button
        self.btn_load = QToolButton(parent)
        self.btn_load.setCursor(Qt.PointingHandCursor)
        self.btn_load.setFocusPolicy(Qt.NoFocus)
        px = GuiUtils.get_icon_pixmap('expression.png')

        self.btn_load.setIcon(QIcon(px))
        self.btn_load.setIconSize(px.size())
        self.btn_load.setStyleSheet('background: transparent; padding: 0px; '
                                    'border: none;')

        frame_width = self.set_button_minimum_size(self.btn_load)

        # Ensure that text does not overlay button
        padding = self.btn_load.sizeHint().width() + frame_width + 1

        self.setStyleSheet('padding-right: ' + str(padding * 2) + 'px;')

        # Set layout
        self.button_layout = QHBoxLayout(self)

        self.button_layout.addWidget(self.btn_load, 0, Qt.AlignRight)

        self.button_layout.setSpacing(0)
        self.button_layout.setMargin(5)

        # Readonly as text generated automatically
        self.setReadOnly(True)

        # Current model object
        self._current_item = None

    def create_layer(self):
        srid = None
        column = ''
        if self.entity.has_geometry_column():
            geom_cols = [col.name for col in self.entity.columns.values()
                         if col.TYPE_INFO == 'GEOMETRY']
            column = geom_cols[0]
            geom_col_obj = self.entity.columns[column]

            if geom_col_obj.srid >= 100000:
                srid = geom_col_obj.srid
        layer = vector_layer(self.entity.name, geom_column=column,
                             proj_wkt=srid)
        return layer

    def get_feature_value(self, model=None):
        self.layer.startEditing()
        feature = None

        request = QgsFeatureRequest()
        if model is None:
            model = self.host.model()
        request.setFilterFid(model.id)
        feature_itr = self.layer.getFeatures(request)
        for feat in feature_itr:
            feature = feat
            break

        exp = QgsExpression(self.column.expression)

        if exp.hasParserError():
            raise Exception(exp.parserErrorString())

        exp.prepare(self.layer.fields())
        if feature is not None:
            value = exp.evaluate(feature)

            return value
        else:
            return None

    def set_button_minimum_size(self, button):
        """
        Sets the minimum button size.
        :param button: The button to be set.
        :type button: QToolButton
        :return: Returns the frame width of the button
        :rtype: Integer
        """
        frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        msz = self.minimumSizeHint()
        self.setMinimumSize(
            max(
                msz.width(),
                button.sizeHint().height() + frame_width * 2 + 2
            ), max(
                msz.height(),
                button.sizeHint().height() + frame_width * 2 + 2
            )
        )
        return frame_width

    @property
    def entity(self):
        """
        :return: Returns the entity object corresponding to this widget.
        :rtype: Entity
        """
        return self._entity

    def clear_line_edit(self):
        """
        Clears the text in the line edit.
        """
        self.clear()

    def on_expression_triggered(self, model=None):
        """
        Slot raised to load browser for selecting foreign key entities. To be
        implemented by subclasses.
        """
        self.format_display(self.get_feature_value(model))
        return self.get_feature_value()

    def format_display(self, value):
        """
        Extract object values to show in the line edit based on the specified
        display columns.
        """
        if value is not None:
            self.setText(str(value))
Exemplo n.º 6
0
class ForeignKeyLineEdit(QLineEdit):
    """
    Line edit that enables the browsing of related entities defined through
    foreign key constraint.
    """

    def __init__(self, column, parent=None, pixmap=None, host=None):
        """
        Class constructor.
        :param column: Column object containing foreign key information.
        :type column: BaseColumn
        :param parent: Parent widget for the control.
        :type parent: QWidget
        :param pixmap: Pixmap to use for the line edit button.
        :type pixmap: QPixmap
        """

        QLineEdit.__init__(self, parent)

        self.column = column
        self._entity = self.column.entity
        self.entity_dialog = host

        # Configure load button
        self.btn_load = QToolButton(parent)
        self.btn_load.setCursor(Qt.PointingHandCursor)
        self.btn_load.setFocusPolicy(Qt.NoFocus)
        px = GuiUtils.get_icon_pixmap('select_record.png')
        if not pixmap is None:
            px = pixmap
        self.btn_load.setIcon(QIcon(px))
        self.btn_load.setIconSize(px.size())
        self.btn_load.setStyleSheet('background: transparent; padding: 0px; '
                                    'border: none;')
        self.btn_load.clicked.connect(self.on_load_foreign_key_browser)

        clear_px = GuiUtils.get_icon_pixmap('clear.png')

        self.btn_clear = QToolButton(parent)
        self.btn_clear.setCursor(Qt.PointingHandCursor)
        self.btn_clear.setFocusPolicy(Qt.NoFocus)
        self.btn_clear.setIcon(QIcon(clear_px))
        self.btn_clear.setIconSize(clear_px.size())
        self.btn_clear.setStyleSheet('background: transparent; padding: 0px; '
                                     'border: none;')

        self.btn_clear.clicked.connect(self.clear_line_edit)

        frame_width = self.set_button_minimum_size(self.btn_load)
        self.set_button_minimum_size(self.btn_clear)
        # Ensure that text does not overlay button
        padding = self.btn_load.sizeHint().width() + frame_width + 1

        self.setStyleSheet('padding-right: ' + str(padding * 2) + 'px;')

        # Set layout
        self.button_layout = QHBoxLayout(self)

        self.button_layout.addWidget(self.btn_clear, 0, Qt.AlignRight)
        self.button_layout.addWidget(self.btn_load, 0, Qt.AlignRight)

        self.button_layout.setSpacing(0)
        self.button_layout.setMargin(5)

        self.btn_clear.setVisible(False)
        # Readonly as text is loaded from the related entity
        self.setReadOnly(True)

        # Current model object
        self._current_item = None

    def set_button_minimum_size(self, button):
        """
        Sets the minimum button size.
        :param button: The button to be set.
        :type button: QToolButton
        :return: Returns the frame width of the button
        :rtype: Integer
        """
        frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
        msz = self.minimumSizeHint()
        self.setMinimumSize(
            max(
                msz.width(),
                button.sizeHint().height() + frame_width * 2 + 2
            ), max(
                msz.height(),
                button.sizeHint().height() + frame_width * 2 + 2
            )
        )
        return frame_width

    @property
    def current_item(self):
        return self._current_item

    @current_item.setter
    def current_item(self, value):
        # Update display every time the current item is changed.
        self._current_item = value
        self.format_display()

    @property
    def entity(self):
        """
        :return: Returns the entity object corresponding to this widget.
        :rtype: Entity
        """
        return self._entity

    def clear_line_edit(self):
        """
        Clears the text in the line edit.
        """
        self.clear()
        self.hide_clear_button()

    def hide_clear_button(self):
        """
        Hides the clear button.
        """
        self.btn_clear.setVisible(False)
        self.button_layout.setStretch(0, 0)

    def show_clear_button(self):
        """
        Shows the clear button if a text exists.
        """
        if len(self.text()) > 0:
            self.btn_clear.setVisible(True)
            self.button_layout.setStretch(0, 5)

    def on_load_foreign_key_browser(self):
        """
        Slot raised to load browser for selecting foreign key entities. To be
        implemented by subclasses.
        """
        raise NotImplementedError

    def format_display(self):
        """
        Extract object values to show in the line edit based on the specified
        display columns.
        """
        raise NotImplementedError

    def parent_entity_model(self):
        """
        :return: Returns the database model corresponding to the parent table
        of the relation defined by this column. Please note that the database
        model will not contain relationship configurations in its attributes.
        :rtype: object
        """
        entity = self.column.entity_relation.parent

        return entity_model(entity, entity_only=True)

    def load_current_item_from_id(self, id):
        """
        Loads the current item from the id corresponding to the primary
        key.
        :param id: Primary key of the referenced entity.
        :type id: int
        """
        QApplication.processEvents()
        model = self.parent_entity_model()

        if model is None:
            return

        model_obj = model()
        res = model_obj.queryObject().filter(model.id == id).first()

        if not res is None:
            self.current_item = res