def _addStringProperty(self,bool,deletable=True): layout2=QHBoxLayout() findPropertyNameLabel = QLabel("Property: ") findPropertyNameLineEdit = QLineEdit() findPropertyNameLineEdit.setToolTip("Example: Label = Particle1 ") findPropertyValueLabel = QLabel(" = ") findPropertyValueLineEdit = QLineEdit() findPropertyValueLineEdit.setToolTip("Example: Label = Particle1 ") propertyAdd = QToolButton() propertyAdd.setText("+") propertyDelete = QToolButton() propertyDelete.setText("-") if deletable: propertyAdd.hide() else: propertyDelete.hide() layout2.addWidget(propertyAdd) layout2.addWidget(propertyDelete) layout2.addWidget(findPropertyNameLabel) layout2.addWidget(findPropertyNameLineEdit) layout2.addWidget(findPropertyValueLabel) layout2.addWidget(findPropertyValueLineEdit) self.connect(findPropertyNameLineEdit, SIGNAL('textChanged(QString)'), self.edited) self.connect(findPropertyValueLineEdit, SIGNAL('textChanged(QString)'), self.edited) self.connect(propertyAdd, SIGNAL('clicked(bool)'), self._addStringProperty) self.connect(propertyDelete, SIGNAL('clicked(bool)'), self._removeProperty) self.layout().insertLayout(len(self._properties)+len(self._scripts)+1,layout2) self._properties+=[(layout2,findPropertyNameLineEdit,findPropertyValueLineEdit,findPropertyNameLabel,findPropertyValueLabel,propertyAdd,propertyDelete)]
def _addScript(self,bool,deletable=True): layout2=QHBoxLayout() findScriptLabel = QLabel("Filter = ") findScriptLineEdit = QLineEdit("") findScriptLineEdit.setToolTip("Example: object.Label == 'Particle1' ") scriptAdd = QToolButton() scriptAdd.setText("+") scriptDelete = QToolButton() scriptDelete.setText("-") if deletable: scriptAdd.hide() else: scriptDelete.hide() layout2.addWidget(scriptAdd) layout2.addWidget(scriptDelete) layout2.addWidget(findScriptLabel) layout2.addWidget(findScriptLineEdit) self.connect(findScriptLineEdit, SIGNAL('textChanged(QString)'), self.edited) self.connect(scriptAdd, SIGNAL('clicked(bool)'), self._addScript) self.connect(scriptDelete, SIGNAL('clicked(bool)'), self._removeScript) self.layout().insertLayout(len(self._properties)+len(self._scripts)+1,layout2) self._scripts+=[(layout2,findScriptLineEdit,findScriptLabel,scriptAdd,scriptDelete)]
class ClosableProperty(QWidget): def __init__(self, property): QWidget.__init__(self) self.setContentsMargins(0, 0, 0, 0) self.setLayout(QHBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(property) self._closeButton = QToolButton() self._closeButton.setText("x") self._closeButton.hide() self._property = property self.layout().addWidget(self._closeButton) def closableProperty(self): return self._property def closeButton(self): return self._closeButton def enterEvent(self, event): self._closeButton.show() def leaveEvent(self, event): self._closeButton.hide()
def _addScript(self, bool, deletable=True): layout2 = QHBoxLayout() findScriptLabel = QLabel("Filter = ") findScriptLineEdit = QLineEdit("") findScriptLineEdit.setToolTip("Example: object.Label == 'Particle1' ") scriptAdd = QToolButton() scriptAdd.setText("+") scriptDelete = QToolButton() scriptDelete.setText("-") if deletable: scriptAdd.hide() else: scriptDelete.hide() layout2.addWidget(scriptAdd) layout2.addWidget(scriptDelete) layout2.addWidget(findScriptLabel) layout2.addWidget(findScriptLineEdit) self.connect(findScriptLineEdit, SIGNAL("textChanged(QString)"), self.edited) self.connect(scriptAdd, SIGNAL("clicked(bool)"), self._addScript) self.connect(scriptDelete, SIGNAL("clicked(bool)"), self._removeScript) self.layout().insertLayout(len(self._properties) + len(self._scripts) + 1, layout2) self._scripts += [(layout2, findScriptLineEdit, findScriptLabel, scriptAdd, scriptDelete)]
def _addStringProperty(self, bool, deletable=True): layout2 = QHBoxLayout() findPropertyNameLabel = QLabel("Property: ") findPropertyNameLineEdit = QLineEdit() findPropertyNameLineEdit.setToolTip("Example: Label = Particle1 ") findPropertyValueLabel = QLabel(" = ") findPropertyValueLineEdit = QLineEdit() findPropertyValueLineEdit.setToolTip("Example: Label = Particle1 ") propertyAdd = QToolButton() propertyAdd.setText("+") propertyDelete = QToolButton() propertyDelete.setText("-") if deletable: propertyAdd.hide() else: propertyDelete.hide() layout2.addWidget(propertyAdd) layout2.addWidget(propertyDelete) layout2.addWidget(findPropertyNameLabel) layout2.addWidget(findPropertyNameLineEdit) layout2.addWidget(findPropertyValueLabel) layout2.addWidget(findPropertyValueLineEdit) self.connect(findPropertyNameLineEdit, SIGNAL("textChanged(QString)"), self.edited) self.connect(findPropertyValueLineEdit, SIGNAL("textChanged(QString)"), self.edited) self.connect(propertyAdd, SIGNAL("clicked(bool)"), self._addStringProperty) self.connect(propertyDelete, SIGNAL("clicked(bool)"), self._removeProperty) self.layout().insertLayout(len(self._properties) + len(self._scripts) + 1, layout2) self._properties += [ ( layout2, findPropertyNameLineEdit, findPropertyValueLineEdit, findPropertyNameLabel, findPropertyValueLabel, propertyAdd, propertyDelete, ) ]
class ClosableProperty(QWidget): def __init__(self,property): QWidget.__init__(self) self.setContentsMargins(0, 0, 0, 0) self.setLayout(QHBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(property) self._closeButton=QToolButton() self._closeButton.setText("x") self._closeButton.hide() self._property=property self.layout().addWidget(self._closeButton) def closableProperty(self): return self._property def closeButton(self): return self._closeButton def enterEvent(self,event): self._closeButton.show() def leaveEvent(self,event): self._closeButton.hide()
class XSearchEdit(XLineEdit): def __init__(self, parent=None): super(XSearchEdit, self).__init__(parent) # setup custom properties self._cancelButton = QToolButton(self) self._cancelButton.setIcon(QIcon( resources.find('img/remove_dark.png'))) self._cancelButton.setAutoRaise(True) self._cancelButton.setToolTip('Clear Search Text') self._cancelButton.hide() self.addButton(self._cancelButton) # setup default properties self.setHint('enter search') self.setIcon(QIcon(resources.find('img/search.png'))) self.setCornerRadius(8) self.adjustStyleSheet() self.adjustTextMargins() # create connections self._cancelButton.clicked.connect(self.clear) self.textChanged.connect(self.toggleCancelButton) def clear(self): """ Clears the search text for this instance. """ super(XLineEdit, self).clear() self.textEntered.emit('') def toggleCancelButton(self): """ Toggles the visibility for the cancel button based on the current text. """ self._cancelButton.setVisible(self.text() != '')
class TextEditWithButtonProperty(Property, QWidget): """ This class provides a PropertyView property holding an editable text and a button. It is possible to hide the button unless the mouse cursor is over the property. This feature is turned on by default. See setAutohideButton(). If the button is pressed nothing happens. This functionality should be implemented in sub-classes. See buttonClicked(). The text field can hold single or multiple lines. See setMultiline() """ BUTTON_LABEL = '' AUTOHIDE_BUTTON = True def __init__(self, name, value, categoryName=None, multiline=False): """ The constructor creates a QHBoxLayout and calls createLineEdit(), createTextEdit() and createButton(). """ Property.__init__(self, name, categoryName) QWidget.__init__(self) self._lineEdit = None self._textEdit = None self._button = None self.setAutohideButton(self.AUTOHIDE_BUTTON) self.setLayout(QHBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self._readOnly = False self._multiline = False self.createLineEdit() self.createTextEdit() self.createButton() self.setMultiline(multiline) self.setValue(value) def setValue(self, value): """ Sets value of text edit. """ self._originalValue = value if value != None: strValue = str(value) else: strValue = "" if not self._readOnly: self.disconnect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.disconnect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) self._lineEdit.setText(strValue) self._textEdit.setText(strValue) self.setToolTip(strValue) if not self._readOnly: self.connect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.connect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) # TODO: sometimes when changing value the text edit appears to be empty when new text is shorter than old text #if not self._multiline: # self._textEdit.setCursorPosition(self._textEdit.displayText().length()) def setToolTip(self, text): self._lineEdit.setToolTip(text) self._textEdit.setToolTip(text) def setMultiline(self, multi): """ Switch between single and multi line mode. """ self.setValue(self.strValue()) self._multiline = multi if self._multiline: self._textEdit.show() self._lineEdit.hide() self.setFocusProxy(self._textEdit) else: self._lineEdit.show() self._textEdit.hide() self.setFocusProxy(self._lineEdit) def createLineEdit(self, value=None): """ This function creates the signle line text field and adds it to the property's layout. """ self._lineEdit = QLineEdit(self) self._lineEdit.setFrame(False) self.connect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self._lineEdit.setContentsMargins(0, 0, 0, 0) self._lineEdit.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding)) self.layout().addWidget(self._lineEdit) def createTextEdit(self, value=None): """ This function creates the multi line text field and adds it to the property's layout. """ self._textEdit = TextEdit(self) self._textEdit.setWordWrapMode(QTextOption.NoWrap) self._textEdit.setFrameStyle(QFrame.NoFrame) self.connect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) self._textEdit.setContentsMargins(0, 0, 0, 0) self._textEdit.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding)) self.layout().addWidget(self._textEdit) def properyHeight(self): """ Return the estimated height of the property. The returned height covers the whole text, even if multiline. """ if self._multiline: self._textEdit.document().adjustSize() height = self._textEdit.document().size().height() + 3 if self._textEdit.horizontalScrollBar().isVisible(): height += self._textEdit.horizontalScrollBar().height() + 3 return height else: return self.DEFAULT_HEIGHT def lineEdit(self): """ Returns line edit. """ return self._lineEdit def textEdit(self): """ Returns text edit. """ return self._textEdit def createButton(self): """ Creates a button and adds it to the property's layout. """ self._button = QToolButton(self) self._button.setText(self.BUTTON_LABEL) self._button.setContentsMargins(0, 0, 0, 0) self.connect(self._button, SIGNAL('clicked(bool)'), self.buttonClicked) self.layout().addWidget(self._button) if self.autohideButtonFlag: self._button.hide() def button(self): """ Return button. """ return self._button def hasButton(self): """ Returns True if the button has been created, otherwise False is returned. """ return self._button != None def setReadOnly(self, readOnly): """ Switch between readonly and editable. """ self._readOnly = readOnly if not self.lineEdit().isReadOnly() and readOnly: self.disconnect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.disconnect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) if self.hasButton(): self._button = None if self.lineEdit().isReadOnly() and not readOnly: self.connect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.connect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) if not self.hasButton(): self.createButton() self.lineEdit().setReadOnly(readOnly) self.textEdit().setReadOnly(readOnly) def readOnly(self): return self._readOnly def strValue(self): """ Returns value of text edit. """ if not self._multiline: return str(self._lineEdit.text().toAscii()) else: return str(self._textEdit.toPlainText().toAscii()) return "" def value(self): """ Returns the value of correct type (in case its not a string). """ return self.strValue() def setAutohideButton(self, hide): """ If hide is True the button will only be visible while the cursor is over the property. """ self.autohideButtonFlag = hide def buttonClicked(self, checked=False): """ This function is called if the button was clicked. For information on the checked argument see documentation of QPushButton::clicked(). This function should be overwritten by sub-classes. """ pass def enterEvent(self, event): """ If autohideButtonFlag is set this function makes the button visible. See setAutohideButton(). """ if self.autohideButtonFlag and self.hasButton() and not self._readOnly: self._button.show() def leaveEvent(self, event): """ If autohideButtonFlag is set this function makes the button invisible. See setAutohideButton(). """ if self.autohideButtonFlag and self.hasButton() and not self._readOnly: self._button.hide() def valueChanged(self): """ Update tooltip and height when text is changed. """ if self._multiline: self.emit(SIGNAL('updatePropertyHeight'), self) self.setToolTip(self.strValue()) # set property only if button is not being pressed if not self.button() or not self.button().isDown(): Property.valueChanged(self) def setHighlighted(self, highlight): """ Highlight the property by changing the background color of the textfield. """ p = QPalette() if highlight: p.setColor(QPalette.Active, QPalette.ColorRole(9), Qt.red) else: p.setColor(QPalette.Active, QPalette.ColorRole(9), Qt.white) self._lineEdit.setPalette(p) self._textEdit.viewport().setPalette(p) def keyPressEvent(self, event): """ Switch back to the original value on ESC. """ QWidget.keyPressEvent(self, event) if event.key() == Qt.Key_Escape: self.setValue(self._originalValue)
class Search_QLineEdit(QLineEdit): """ Defines a `QLineEdit <http://doc.qt.nokia.com/qlinedit.html>`_ subclass providing a search field with clearing capabilities. """ def __init__( self, parent=None, uiSearchImage=None, uiSearchClickedImage=None, uiClearImage=None, uiClearClickedImage=None ): """ Initializes the class. :param parent: Widget parent. :type parent: QObject :param uiSearchImage: Search button image path. :type uiSearchImage: str :param uiSearchClickedImage: Search button clicked image path. :type uiSearchClickedImage: str :param uiClearImage: Clear button image path. :type uiClearImage: str :param uiClearClickedImage: Clear button clicked image path. :type uiClearClickedImage: str """ LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__)) QLineEdit.__init__(self, parent) # --- Setting class attributes. --- self.__uiSearchImage = None self.uiSearchImage = uiSearchImage or umbra.ui.common.getResourcePath("images/Search_Glass.png") self.__uiSearchClickedImage = None self.uiSearchClickedImage = uiSearchClickedImage or umbra.ui.common.getResourcePath( "images/Search_Glass_Clicked.png" ) self.__uiClearImage = None self.uiClearImage = uiClearImage or umbra.ui.common.getResourcePath("images/Search_Clear.png") self.__uiClearClickedImage = None self.uiClearClickedImage = uiClearClickedImage or umbra.ui.common.getResourcePath( "images/Search_Clear_Clicked.png" ) self.__searchActiveLabel = Active_QLabel( self, QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchClickedImage) ) self.__searchActiveLabel.setObjectName("Search_Field_activeLabel") self.__searchActiveLabel.showEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.showEvent(self.__searchActiveLabel, event)) ) self.__searchActiveLabel.hideEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.hideEvent(self.__searchActiveLabel, event)) ) self.__clearButton = QToolButton(self) self.__clearButton.setObjectName("Clear_Field_button") self.__completer = QCompleter() self.setCompleter(self.__completer) self.__completerVisibleItemsCount = 16 Search_QLineEdit.__initializeUi(self) self.__setClearButtonVisibility(self.text()) # Signals / Slots. self.__clearButton.clicked.connect(self.clear) self.textChanged.connect(self.__setClearButtonVisibility) # ****************************************************************************************************************** # *** Attributes properties. # ****************************************************************************************************************** @property def uiSearchImage(self): """ Property for **self.__uiSearchImage** attribute. :return: self.__uiSearchImage. :rtype: str """ return self.__uiSearchImage @uiSearchImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchImage(self, value): """ Setter for **self.__uiSearchImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchImage", value ) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format("uiSearchImage", value) self.__uiSearchImage = value @uiSearchImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiSearchImage(self): """ Deleter for **self.__uiSearchImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchImage") ) @property def uiSearchClickedImage(self): """ Property for **self.__uiSearchClickedImage** attribute. :return: self.__uiSearchClickedImage. :rtype: str """ return self.__uiSearchClickedImage @uiSearchClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchClickedImage(self, value): """ Setter for **self.__uiSearchClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchClickedImage", value ) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchClickedImage", value ) self.__uiSearchClickedImage = value @uiSearchClickedImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiSearchClickedImage(self): """ Deleter for **self.__uiSearchClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchClickedImage") ) @property def uiClearImage(self): """ Property for **self.__uiClearImage** attribute. :return: self.__uiClearImage. :rtype: str """ return self.__uiClearImage @uiClearImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearImage(self, value): """ Setter for **self.__uiClearImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format("uiClearImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format("uiClearImage", value) self.__uiClearImage = value @uiClearImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiClearImage(self): """ Deleter for **self.__uiClearImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearImage") ) @property def uiClearClickedImage(self): """ Property for **self.__uiClearClickedImage** attribute. :return: self.__uiClearClickedImage. :rtype: str """ return self.__uiClearClickedImage @uiClearClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearClickedImage(self, value): """ Setter for **self.__uiClearClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiClearClickedImage", value ) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearClickedImage", value ) self.__uiClearClickedImage = value @uiClearClickedImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiClearClickedImage(self): """ Deleter for **self.__uiClearClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearClickedImage") ) @property def searchActiveLabel(self): """ Property for **self.__searchActiveLabel** attribute. :return: self.__searchActiveLabel. :rtype: QPushButton """ return self.__searchActiveLabel @searchActiveLabel.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def searchActiveLabel(self, value): """ Setter for **self.__searchActiveLabel** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "searchActiveLabel") ) @searchActiveLabel.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def searchActiveLabel(self): """ Deleter for **self.__searchActiveLabel** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "searchActiveLabel") ) @property def clearButton(self): """ Property for **self.__clearButton** attribute. :return: self.__clearButton. :rtype: QPushButton """ return self.__clearButton @clearButton.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def clearButton(self, value): """ Setter for **self.__clearButton** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "clearButton") ) @clearButton.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def clearButton(self): """ Deleter for **self.__clearButton** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "clearButton") ) @property def completer(self): """ Property for **self.__completer** attribute. :return: self.__completer. :rtype: QCompleter """ return self.__completer @completer.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completer(self, value): """ Setter for **self.__completer** attribute. :param value: Attribute value. :type value: QCompleter """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completer") ) @completer.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completer(self): """ Deleter for **self.__completer** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completer") ) @property def completerVisibleItemsCount(self): """ Property for **self.__completerVisibleItemsCount** attribute. :return: self.__completerVisibleItemsCount. :rtype: int """ return self.__completerVisibleItemsCount @completerVisibleItemsCount.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self, value): """ Setter for **self.__completerVisibleItemsCount** attribute. :param value: Attribute value. :type value: int """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completerVisibleItemsCount") ) @completerVisibleItemsCount.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self): """ Deleter for **self.__completerVisibleItemsCount** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completerVisibleItemsCount") ) # ****************************************************************************************************************** # *** Class methods. # ****************************************************************************************************************** def resizeEvent(self, event): """ Reimplements the :meth:`QLineEdit.QResizeEvent` method. :param event: Resize event. :type event: QResizeEvent """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) searchActiveLabelSize = self.__searchActiveLabel.sizeHint() self.__searchActiveLabel.move( self.rect().left() + frameWidth, (self.rect().bottom() - searchActiveLabelSize.height()) / 2 + frameWidth / 2, ) clearButtonSize = self.__clearButton.sizeHint() self.__clearButton.move( self.rect().right() - frameWidth - clearButtonSize.width(), (self.rect().bottom() - clearButtonSize.height()) / 2 + frameWidth / 2, ) def __initializeUi(self): """ Initializes the Widget ui. """ self.__clearButton.setCursor(Qt.ArrowCursor) if self.__uiClearImage and self.__uiClearClickedImage: pixmap = QPixmap(self.__uiClearImage) clickedPixmap = QPixmap(self.__uiClearClickedImage) self.__clearButton.setIcon(QIcon(pixmap)) self.__clearButton.setMaximumSize(pixmap.size()) # Signals / Slots. self.__clearButton.pressed.connect(functools.partial(self.__clearButton.setIcon, QIcon(clickedPixmap))) self.__clearButton.released.connect(functools.partial(self.__clearButton.setIcon, QIcon(pixmap))) else: self.__clearButton.setText("Clear") self.__setStyleSheet() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setMinimumSize( max(self.minimumSizeHint().width(), self.__clearButton.sizeHint().height() + frameWidth * 2), max(self.minimumSizeHint().height(), self.__clearButton.sizeHint().height() + frameWidth * 2), ) self.__completer.setCaseSensitivity(Qt.CaseInsensitive) self.__completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) # self.__completer.setMaxVisibleItems(self.__completerVisibleItemsCount) def __setStyleSheet(self): """ Sets the Widget stylesheet. """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet( QString( "QLineEdit {{ padding-left: {0}px; padding-right: {1}px; }}\nQToolButton {{ border: none; padding: 0px; }}".format( self.__searchActiveLabel.sizeHint().width() if self.__searchActiveLabel.isVisible() else 0 + frameWidth, self.__clearButton.sizeHint().width() + frameWidth, ) ) ) def __setClearButtonVisibility(self, text): """ Sets the clear button visibility. :param text: Current field text. :type text: QString """ if text: self.__clearButton.show() else: self.__clearButton.hide()
class TextEditWithButtonProperty(Property, QWidget): """ This class provides a PropertyView property holding an editable text and a button. It is possible to hide the button unless the mouse cursor is over the property. This feature is turned on by default. See setAutohideButton(). If the button is pressed nothing happens. This functionality should be implemented in sub-classes. See buttonClicked(). The text field can hold single or multiple lines. See setMultiline() """ BUTTON_LABEL = '' AUTOHIDE_BUTTON = True def __init__(self, name, value, categoryName=None, multiline=False): """ The constructor creates a QHBoxLayout and calls createLineEdit(), createTextEdit() and createButton(). """ Property.__init__(self, name, categoryName) QWidget.__init__(self) self._lineEdit = None self._textEdit = None self._button = None self.setAutohideButton(self.AUTOHIDE_BUTTON) self.setLayout(QHBoxLayout()) self.layout().setSpacing(0) self.layout().setContentsMargins(0, 0, 0, 0) self._readOnly = False self._multiline = False self.createLineEdit() self.createTextEdit() self.createButton() self.setMultiline(multiline) self.setValue(value) def setValue(self, value): """ Sets value of text edit. """ self._originalValue=value if value != None: strValue = str(value) else: strValue = "" if not self._readOnly: self.disconnect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.disconnect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) self._lineEdit.setText(strValue) self._textEdit.setText(strValue) self.setToolTip(strValue) if not self._readOnly: self.connect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.connect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) # TODO: sometimes when changing value the text edit appears to be empty when new text is shorter than old text #if not self._multiline: # self._textEdit.setCursorPosition(self._textEdit.displayText().length()) def setToolTip(self,text): self._lineEdit.setToolTip(text) self._textEdit.setToolTip(text) def setMultiline(self,multi): """ Switch between single and multi line mode. """ self.setValue(self.strValue()) self._multiline=multi if self._multiline: self._textEdit.show() self._lineEdit.hide() self.setFocusProxy(self._textEdit) else: self._lineEdit.show() self._textEdit.hide() self.setFocusProxy(self._lineEdit) def createLineEdit(self, value=None): """ This function creates the signle line text field and adds it to the property's layout. """ self._lineEdit = QLineEdit(self) self._lineEdit.setFrame(False) self.connect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self._lineEdit.setContentsMargins(0, 0, 0, 0) self._lineEdit.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding)) self.layout().addWidget(self._lineEdit) def createTextEdit(self, value=None): """ This function creates the multi line text field and adds it to the property's layout. """ self._textEdit = TextEdit(self) self._textEdit.setWordWrapMode(QTextOption.NoWrap) self._textEdit.setFrameStyle(QFrame.NoFrame) self.connect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) self._textEdit.setContentsMargins(0, 0, 0, 0) self._textEdit.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding)) self.layout().addWidget(self._textEdit) def properyHeight(self): """ Return the estimated height of the property. The returned height covers the whole text, even if multiline. """ if self._multiline: self._textEdit.document().adjustSize() height=self._textEdit.document().size().height()+3 if self._textEdit.horizontalScrollBar().isVisible(): height+=self._textEdit.horizontalScrollBar().height()+3 return height else: return self.DEFAULT_HEIGHT def lineEdit(self): """ Returns line edit. """ return self._lineEdit def textEdit(self): """ Returns text edit. """ return self._textEdit def createButton(self): """ Creates a button and adds it to the property's layout. """ self._button = QToolButton(self) self._button.setText(self.BUTTON_LABEL) self._button.setContentsMargins(0, 0, 0, 0) self.connect(self._button, SIGNAL('clicked(bool)'), self.buttonClicked) self.layout().addWidget(self._button) if self.autohideButtonFlag: self._button.hide() def button(self): """ Return button. """ return self._button def hasButton(self): """ Returns True if the button has been created, otherwise False is returned. """ return self._button != None def setReadOnly(self, readOnly): """ Switch between readonly and editable. """ self._readOnly = readOnly if not self.lineEdit().isReadOnly() and readOnly: self.disconnect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.disconnect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) if self.hasButton(): self._button=None if self.lineEdit().isReadOnly() and not readOnly: self.connect(self._lineEdit, SIGNAL('editingFinished()'), self.valueChanged) self.connect(self._textEdit, SIGNAL('editingFinished()'), self.valueChanged) if not self.hasButton(): self.createButton() self.lineEdit().setReadOnly(readOnly) self.textEdit().setReadOnly(readOnly) def readOnly(self): return self._readOnly def strValue(self): """ Returns value of text edit. """ if not self._multiline: return str(self._lineEdit.text().toAscii()) else: return str(self._textEdit.toPlainText().toAscii()) return "" def value(self): """ Returns the value of correct type (in case its not a string). """ return self.strValue() def setAutohideButton(self, hide): """ If hide is True the button will only be visible while the cursor is over the property. """ self.autohideButtonFlag = hide def buttonClicked(self, checked=False): """ This function is called if the button was clicked. For information on the checked argument see documentation of QPushButton::clicked(). This function should be overwritten by sub-classes. """ pass def enterEvent(self, event): """ If autohideButtonFlag is set this function makes the button visible. See setAutohideButton(). """ if self.autohideButtonFlag and self.hasButton() and not self._readOnly: self._button.show() def leaveEvent(self, event): """ If autohideButtonFlag is set this function makes the button invisible. See setAutohideButton(). """ if self.autohideButtonFlag and self.hasButton() and not self._readOnly: self._button.hide() def valueChanged(self): """ Update tooltip and height when text is changed. """ if self._multiline: self.emit(SIGNAL('updatePropertyHeight'),self) self.setToolTip(self.strValue()) # set property only if button is not being pressed if not self.button() or not self.button().isDown(): Property.valueChanged(self) def setHighlighted(self,highlight): """ Highlight the property by changing the background color of the textfield. """ p=QPalette() if highlight: p.setColor(QPalette.Active, QPalette.ColorRole(9),Qt.red) else: p.setColor(QPalette.Active, QPalette.ColorRole(9),Qt.white) self._lineEdit.setPalette(p) self._textEdit.viewport().setPalette(p) def keyPressEvent(self,event): """ Switch back to the original value on ESC. """ QWidget.keyPressEvent(self,event) if event.key()==Qt.Key_Escape: self.setValue(self._originalValue)
class Search_QLineEdit(QLineEdit): """ Defines a `QLineEdit <http://doc.qt.nokia.com/qlinedit.html>`_ subclass providing a search field with clearing capabilities. """ def __init__(self, parent=None, uiSearchImage=None, uiSearchClickedImage=None, uiClearImage=None, uiClearClickedImage=None): """ Initializes the class. :param parent: Widget parent. :type parent: QObject :param uiSearchImage: Search button image path. :type uiSearchImage: str :param uiSearchClickedImage: Search button clicked image path. :type uiSearchClickedImage: str :param uiClearImage: Clear button image path. :type uiClearImage: str :param uiClearClickedImage: Clear button clicked image path. :type uiClearClickedImage: str """ LOGGER.debug("> Initializing '{0}()' class.".format( self.__class__.__name__)) QLineEdit.__init__(self, parent) # --- Setting class attributes. --- self.__uiSearchImage = None self.uiSearchImage = uiSearchImage or umbra.ui.common.getResourcePath( "images/Search_Glass.png") self.__uiSearchClickedImage = None self.uiSearchClickedImage = uiSearchClickedImage or umbra.ui.common.getResourcePath( "images/Search_Glass_Clicked.png") self.__uiClearImage = None self.uiClearImage = uiClearImage or umbra.ui.common.getResourcePath( "images/Search_Clear.png") self.__uiClearClickedImage = None self.uiClearClickedImage = uiClearClickedImage or umbra.ui.common.getResourcePath( "images/Search_Clear_Clicked.png") self.__searchActiveLabel = Active_QLabel( self, QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchClickedImage)) self.__searchActiveLabel.setObjectName("Search_Field_activeLabel") self.__searchActiveLabel.showEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.showEvent(self.__searchActiveLabel, event))) self.__searchActiveLabel.hideEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.hideEvent(self.__searchActiveLabel, event))) self.__clearButton = QToolButton(self) self.__clearButton.setObjectName("Clear_Field_button") self.__completer = QCompleter() self.setCompleter(self.__completer) self.__completerVisibleItemsCount = 16 Search_QLineEdit.__initializeUi(self) self.__setClearButtonVisibility(self.text()) # Signals / Slots. self.__clearButton.clicked.connect(self.clear) self.textChanged.connect(self.__setClearButtonVisibility) #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def uiSearchImage(self): """ Property for **self.__uiSearchImage** attribute. :return: self.__uiSearchImage. :rtype: str """ return self.__uiSearchImage @uiSearchImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchImage(self, value): """ Setter for **self.__uiSearchImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchImage", value) self.__uiSearchImage = value @uiSearchImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiSearchImage(self): """ Deleter for **self.__uiSearchImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiSearchImage")) @property def uiSearchClickedImage(self): """ Property for **self.__uiSearchClickedImage** attribute. :return: self.__uiSearchClickedImage. :rtype: str """ return self.__uiSearchClickedImage @uiSearchClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchClickedImage(self, value): """ Setter for **self.__uiSearchClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchClickedImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchClickedImage", value) self.__uiSearchClickedImage = value @uiSearchClickedImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiSearchClickedImage(self): """ Deleter for **self.__uiSearchClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiSearchClickedImage")) @property def uiClearImage(self): """ Property for **self.__uiClearImage** attribute. :return: self.__uiClearImage. :rtype: str """ return self.__uiClearImage @uiClearImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearImage(self, value): """ Setter for **self.__uiClearImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiClearImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearImage", value) self.__uiClearImage = value @uiClearImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiClearImage(self): """ Deleter for **self.__uiClearImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiClearImage")) @property def uiClearClickedImage(self): """ Property for **self.__uiClearClickedImage** attribute. :return: self.__uiClearClickedImage. :rtype: str """ return self.__uiClearClickedImage @uiClearClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearClickedImage(self, value): """ Setter for **self.__uiClearClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiClearClickedImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearClickedImage", value) self.__uiClearClickedImage = value @uiClearClickedImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiClearClickedImage(self): """ Deleter for **self.__uiClearClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiClearClickedImage")) @property def searchActiveLabel(self): """ Property for **self.__searchActiveLabel** attribute. :return: self.__searchActiveLabel. :rtype: QPushButton """ return self.__searchActiveLabel @searchActiveLabel.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def searchActiveLabel(self, value): """ Setter for **self.__searchActiveLabel** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "searchActiveLabel")) @searchActiveLabel.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def searchActiveLabel(self): """ Deleter for **self.__searchActiveLabel** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "searchActiveLabel")) @property def clearButton(self): """ Property for **self.__clearButton** attribute. :return: self.__clearButton. :rtype: QPushButton """ return self.__clearButton @clearButton.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def clearButton(self, value): """ Setter for **self.__clearButton** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "clearButton")) @clearButton.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def clearButton(self): """ Deleter for **self.__clearButton** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "clearButton")) @property def completer(self): """ Property for **self.__completer** attribute. :return: self.__completer. :rtype: QCompleter """ return self.__completer @completer.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completer(self, value): """ Setter for **self.__completer** attribute. :param value: Attribute value. :type value: QCompleter """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "completer")) @completer.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completer(self): """ Deleter for **self.__completer** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "completer")) @property def completerVisibleItemsCount(self): """ Property for **self.__completerVisibleItemsCount** attribute. :return: self.__completerVisibleItemsCount. :rtype: int """ return self.__completerVisibleItemsCount @completerVisibleItemsCount.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self, value): """ Setter for **self.__completerVisibleItemsCount** attribute. :param value: Attribute value. :type value: int """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "completerVisibleItemsCount")) @completerVisibleItemsCount.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self): """ Deleter for **self.__completerVisibleItemsCount** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "completerVisibleItemsCount")) #****************************************************************************************************************** #*** Class methods. #****************************************************************************************************************** def resizeEvent(self, event): """ Reimplements the :meth:`QLineEdit.QResizeEvent` method. :param event: Resize event. :type event: QResizeEvent """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) searchActiveLabelSize = self.__searchActiveLabel.sizeHint() self.__searchActiveLabel.move( self.rect().left() + frameWidth, (self.rect().bottom() - searchActiveLabelSize.height()) / 2 + frameWidth / 2) clearButtonSize = self.__clearButton.sizeHint() self.__clearButton.move( self.rect().right() - frameWidth - clearButtonSize.width(), (self.rect().bottom() - clearButtonSize.height()) / 2 + frameWidth / 2) def __initializeUi(self): """ Initializes the Widget ui. """ self.__clearButton.setCursor(Qt.ArrowCursor) if self.__uiClearImage and self.__uiClearClickedImage: pixmap = QPixmap(self.__uiClearImage) clickedPixmap = QPixmap(self.__uiClearClickedImage) self.__clearButton.setIcon(QIcon(pixmap)) self.__clearButton.setMaximumSize(pixmap.size()) # Signals / Slots. self.__clearButton.pressed.connect( functools.partial(self.__clearButton.setIcon, QIcon(clickedPixmap))) self.__clearButton.released.connect( functools.partial(self.__clearButton.setIcon, QIcon(pixmap))) else: self.__clearButton.setText("Clear") self.__setStyleSheet() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setMinimumSize( max(self.minimumSizeHint().width(), self.__clearButton.sizeHint().height() + frameWidth * 2), max(self.minimumSizeHint().height(), self.__clearButton.sizeHint().height() + frameWidth * 2)) self.__completer.setCaseSensitivity(Qt.CaseInsensitive) self.__completer.setCompletionMode( QCompleter.UnfilteredPopupCompletion) # self.__completer.setMaxVisibleItems(self.__completerVisibleItemsCount) def __setStyleSheet(self): """ Sets the Widget stylesheet. """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet( QString( "QLineEdit {{ padding-left: {0}px; padding-right: {1}px; }}\nQToolButton {{ border: none; padding: 0px; }}" .format( self.__searchActiveLabel.sizeHint().width() if self.__searchActiveLabel.isVisible() else 0 + frameWidth, self.__clearButton.sizeHint().width() + frameWidth))) def __setClearButtonVisibility(self, text): """ Sets the clear button visibility. :param text: Current field text. :type text: QString """ if text: self.__clearButton.show() else: self.__clearButton.hide()
class MyMainWindow(QMainWindow): ' Main Window ' def __init__(self, parent=None): ' Initialize QWidget inside MyMainWindow ' super(MyMainWindow, self).__init__(parent) self.statusBar().showMessage(__doc__.title()) self.setWindowTitle(__doc__) self.setMinimumSize(600, 800) self.setMaximumSize(2048, 1024) self.resize(1024, 800) self.setWindowIcon(QIcon.fromTheme("face-monkey")) if not A11Y: self.setStyleSheet('''QWidget{color:#fff;font-family:Oxygen} QWidget:item:hover, QWidget:item:selected { background-color: cyan; color: #000 } QWidget:disabled { color: #404040; background-color: #323232 } QWidget:focus { border: 1px solid cyan } QPushButton { background-color: gray; padding: 3px; border: 1px solid gray; border-radius: 9px; margin: 0;font-size: 12px; padding-left: 5px; padding-right: 5px } QLineEdit, QTextEdit { background-color: #4a4a4a; border: 1px solid gray; border-radius: 0; font-size: 12px; } QPushButton:pressed { background-color: #323232 } QComboBox { background-color: #4a4a4a; padding-left: 9px; border: 1px solid gray; border-radius: 5px; } QComboBox:pressed { background-color: gray } QComboBox QAbstractItemView, QMenu { border: 1px solid #4a4a4a; background:grey; selection-background-color: cyan; selection-color: #000; } QSlider { padding: 3px; font-size: 8px; padding-left: 2px; padding-right: 2px; border: 5px solid #1e1e1e } QSlider::sub-page:vertical { background-color: QLinearGradient(spread:pad, x1:0, y1:0, x2:1, y2:0.27, stop:0 rgba(255, 0, 0, 255), stop:1 rgba(50, 0, 0, 200)); border: 4px solid #1e1e1e; border-radius: 5px } QSlider::add-page:vertical { background-color: QLinearGradient(spread:pad, x1:0, y1:0, x2:1, y2:0.27, stop:0 rgba(0, 255, 0, 255), stop:1 rgba(0, 99, 0, 255)); border: 4px solid #1e1e1e; border-radius: 5px; } QSlider::handle:vertical { background-color: QLinearGradient(spread:pad, x1:0, y1:0, x2:1, y2:0.273, stop:0 rgba(0, 0, 0, 255), stop:1 gray); height: 5px; border: 1px dotted #fff; text-align: center; border-top-left-radius: 2px; border-bottom-left-radius: 2px; border-top-right-radius: 2px; border-bottom-right-radius 2px; margin-left: 2px; margin-right: 2px; } QSlider::handle:vertical:hover { border: 1px solid cyan } QSlider::sub-page:vertical:disabled { background: #bbb; border-color: #999; } QSlider::add-page:vertical:disabled { background: #eee; border-color: #999; } QSlider::handle:vertical:disabled { background: #eee; border: 1px solid #aaa; border-radius: 4px; } QToolBar, QStatusBar, QDockWidget::title{background-color:#323232;} QToolBar::handle, QToolBar::handle:vertical, QToolBar::handle:horizontal { border: 1px solid gray; border-radius: 9px; width: 19px; height: 19px; margin: 0.5px } QGroupBox { border: 1px solid gray; border-radius: 9px; padding-top: 9px; } QStatusBar, QToolBar::separator:horizontal, QToolBar::separator:vertical {color:gray} QScrollBar:vertical{ background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #212121,stop: 1.0 #323232); width: 10px; } QScrollBar:horizontal{ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #212121,stop: 1.0 #323232); height: 10px; } QScrollBar::handle:vertical{ padding: 2px; min-height: 50px; background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #585858,stop: 1.0 #404040); border-radius: 5px; border: 1px solid #191919; } QScrollBar::handle:horizontal{ padding: 2px; min-width: 50px; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #585858,stop: 1.0 #404040); border-radius: 5px; border: 1px solid #191919; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical, QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical, QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal, QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; border: none; } QDockWidget::close-button, QDockWidget::float-button { border: 1px solid gray; border-radius: 3px; background: darkgray; }''') self.process = QProcess() self.process.readyReadStandardOutput.connect(self.read_output) self.process.readyReadStandardError.connect(self.read_errors) self.process.finished.connect(self._process_finished) self.process.error.connect(self._process_finished) self.group0, self.group1 = QGroupBox("Options"), QGroupBox("Paths") self.group2 = QGroupBox("Nodes") self.group3 = QGroupBox("Python Code") self.group4, self.group5 = QGroupBox("Logs"), QGroupBox("Backend") g0grid, g1vlay = QGridLayout(self.group0), QVBoxLayout(self.group1) g5vlay = QVBoxLayout(self.group5) self.treeview_nodes, self.textedit_source = QTextEdit(), QTextEdit() self.dock1, self.dock2 = QDockWidget(), QDockWidget() self.output, self.dock3 = QTextEdit(), QDockWidget() self.treeview_nodes.setAutoFormatting(QTextEdit.AutoAll) self.treeview_nodes.setWordWrapMode(QTextOption.NoWrap) self.dock1.setWidget(self.treeview_nodes) self.dock2.setWidget(self.textedit_source) self.dock3.setWidget(self.output) self.dock1.setWindowTitle("Tree") self.dock2.setWindowTitle("Sources") self.dock3.setWindowTitle("STDOutput") featur = QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable self.dock1.setFeatures(featur) self.dock2.setFeatures(featur) self.dock3.setFeatures(featur) QVBoxLayout(self.group2).addWidget(self.dock1) QVBoxLayout(self.group3).addWidget(self.dock2) QVBoxLayout(self.group4).addWidget(self.dock3) self.slider1, self.slider2 = QSlider(), QSlider() g0grid.addWidget(self.slider1, 0, 0) g0grid.addWidget(QLabel('Use Debug'), 0, 1) self.slider2.setValue(1) g0grid.addWidget(self.slider2, 1, 0) g0grid.addWidget(QLabel('Use verbose'), 1, 1) self.slider3, self.slider4 = QSlider(), QSlider() self.slider3.setValue(1) g0grid.addWidget(self.slider3, 2, 0) g0grid.addWidget(QLabel('Show compiling progress'), 2, 1) self.slider4.setValue(1) g0grid.addWidget(self.slider4, 3, 0) g0grid.addWidget(QLabel('Show Scons building debug'), 3, 1) self.slider5, self.slider6 = QSlider(), QSlider() g0grid.addWidget(self.slider5, 4, 0) g0grid.addWidget(QLabel('Keep debug unstriped binary'), 4, 1) g0grid.addWidget(self.slider6, 5, 0) g0grid.addWidget(QLabel('Traced execution outputs'), 5, 1) self.slider7, self.slider8 = QSlider(), QSlider() self.slider7.setValue(1) g0grid.addWidget(self.slider7, 6, 0) g0grid.addWidget(QLabel('Remove the build folder'), 6, 1) g0grid.addWidget(self.slider8, 7, 0) g0grid.addWidget(QLabel('No Python Optimizations'), 7, 1) self.slider9, self.slider10 = QSlider(), QSlider() g0grid.addWidget(self.slider9, 8, 0) g0grid.addWidget(QLabel('No Statements line numbers'), 8, 1) g0grid.addWidget(self.slider10, 9, 0) g0grid.addWidget(QLabel('Execute the output binary'), 9, 1) self.slider11, self.slider12 = QSlider(), QSlider() g0grid.addWidget(self.slider11, 10, 0) g0grid.addWidget(QLabel('Warning detected implicit exceptions'), 10, 1) g0grid.addWidget(self.slider12, 11, 0) g0grid.addWidget(QLabel('Keep the PYTHONPATH, do not Reset it'), 11, 1) self.slider13 = QSlider() g0grid.addWidget(self.slider13, 12, 0) g0grid.addWidget(QLabel('Enhance compile, CPython incompatible'), 12, 1) self.slider1a, self.slider2a = QSlider(), QSlider() g0grid.addWidget(self.slider1a, 0, 2) g0grid.addWidget(QLabel('Descendent Recursive Compile'), 0, 3) self.slider2a.setValue(1) g0grid.addWidget(self.slider2a, 1, 2) g0grid.addWidget(QLabel('Force non recursive compile'), 1, 3) self.slider3a, self.slider4a = QSlider(), QSlider() g0grid.addWidget(self.slider3a, 2, 2) g0grid.addWidget(QLabel('STD Lib Recursive Compile'), 2, 3) g0grid.addWidget(self.slider4a, 3, 2) g0grid.addWidget(QLabel('Enforce the use of Clang'), 3, 3) self.slider5a, self.slider6a = QSlider(), QSlider() self.slider5a.setValue(1) g0grid.addWidget(self.slider5a, 4, 2) g0grid.addWidget(QLabel('Use G++ link time optimizations'), 4, 3) g0grid.addWidget(self.slider6a, 5, 2) g0grid.addWidget(QLabel('Disable the console window'), 5, 3) self.slider7a, self.slider8a = QSlider(), QSlider() g0grid.addWidget(self.slider7a, 6, 2) g0grid.addWidget(QLabel('Force compile for MS Windows'), 6, 3) g0grid.addWidget(self.slider8a, 7, 2) g0grid.addWidget(QLabel('Use Python Debug versions'), 7, 3) self.slider9a, self.slider10a = QSlider(), QSlider() self.slider9a.setValue(1) g0grid.addWidget(self.slider9a, 8, 2) g0grid.addWidget(QLabel('Create standalone executable'), 8, 3) g0grid.addWidget(self.slider10a, 9, 2) g0grid.addWidget(QLabel('Enable Standalone mode build'), 9, 3) self.slider11a, self.slider12a = QSlider(), QSlider() g0grid.addWidget(self.slider11a, 10, 2) g0grid.addWidget(QLabel('Make module executable instead of app'), 10, 3) g0grid.addWidget(self.slider12a, 11, 2) g0grid.addWidget(QLabel('No froze module of stdlib as bytecode'), 11, 3) self.slider13a = QSlider() g0grid.addWidget(self.slider13a, 12, 2) g0grid.addWidget(QLabel('Force use of MinGW on MS Windows'), 12, 3) for each_widget in (self.slider1, self.slider2, self.slider3, self.slider4, self.slider5, self.slider6, self.slider7, self.slider8, self.slider9, self.slider10, self.slider11, self.slider12, self.slider13, self.slider1a, self.slider2a, self.slider3a, self.slider4a, self.slider5a, self.slider6a, self.slider7a, self.slider8a, self.slider9a, self.slider10a, self.slider11a, self.slider12a, self.slider13a): each_widget.setRange(0, 1) each_widget.setCursor(QCursor(Qt.OpenHandCursor)) each_widget.setTickInterval(1) each_widget.TickPosition(QSlider.TicksBothSides) self.combo1 = QComboBox() self.combo1.addItems(('2.7', '2.6', '3.2', '3.3')) g5vlay.addWidget(QLabel('Python Version')) g5vlay.addWidget(self.combo1) self.combo2 = QComboBox() self.combo2.addItems(('Default', 'Low', 'High')) g5vlay.addWidget(QLabel('CPU priority')) g5vlay.addWidget(self.combo2) self.combo3 = QComboBox() self.combo3.addItems(('1', '2', '3', '4', '5', '6', '7', '8', '9')) g5vlay.addWidget(QLabel('MultiProcessing Workers')) g5vlay.addWidget(self.combo3) self.outdir = QLineEdit() self.outdir.setStyleSheet("QLineEdit{margin-left:25px}") self.clearButton = QToolButton(self.outdir) self.clearButton.setIcon(QIcon.fromTheme("edit-clear")) self.clearButton.setIconSize(QSize(25, 25)) self.clearButton.setStyleSheet("QToolButton{border:none}") self.clearButton.hide() self.clearButton.clicked.connect(self.outdir.clear) self.outdir.textChanged.connect( lambda: self.clearButton.setVisible(True)) self.clearButton.clicked.connect( lambda: self.clearButton.setVisible(False)) self.outdir.setPlaceholderText('Output Directory') if path.isfile('.nuitka-output-dir.txt'): self.outdir.setText(open('.nuitka-output-dir.txt', 'r').read()) else: self.outdir.setText(path.expanduser("~")) self.completer, self.dirs = QCompleter(self), QDirModel(self) self.dirs.setFilter(QDir.Dirs | QDir.NoDotAndDotDot) self.completer.setModel(self.dirs) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.PopupCompletion) self.completer.popup().setStyleSheet( """border:1px solid #4a4a4a;background:grey; selection-background-color:cyan;selection-color:#000""") self.completer.popup().setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.outdir.setCompleter(self.completer) self.btn1 = QPushButton(QIcon.fromTheme("document-open"), 'Open' if IS_WIN else '') self.btn1.clicked.connect( lambda: open('.nuitka-output-dir.txt', 'w').write( str( QFileDialog.getExistingDirectory( None, 'Open Output Directory', path.expanduser("~"))))) self.btn1.released.connect(lambda: self.outdir.setText( open('.nuitka-output-dir.txt', 'r').read())) g1vlay.addWidget(QLabel('Output Directory')) g1vlay.addWidget(self.outdir) g1vlay.addWidget(self.btn1) self.target = QLineEdit() self.target.setStyleSheet("QLineEdit{margin-left:25px}") self.clearButton2 = QToolButton(self.target) self.clearButton2.setIcon(QIcon.fromTheme("edit-clear")) self.clearButton2.setIconSize(QSize(25, 25)) self.clearButton2.setStyleSheet("QToolButton{border:none}") self.clearButton2.hide() self.clearButton2.clicked.connect(self.target.clear) self.target.textChanged.connect( lambda: self.clearButton2.setVisible(True)) self.clearButton2.clicked.connect( lambda: self.clearButton2.setVisible(False)) self.target.setPlaceholderText('Target Python App to Binary Compile') self.target.setCompleter(self.completer) self.btn2 = QPushButton(QIcon.fromTheme("document-open"), 'Open' if IS_WIN else '') self.btn2.clicked.connect(lambda: self.target.setText( str( QFileDialog.getOpenFileName( None, "Open", path.expanduser("~"), ';;'.join([ '{}(*.{})'.format(e.upper(), e) for e in ('py', 'pyw', '*') ]))))) g1vlay.addWidget(QLabel('Input File')) g1vlay.addWidget(self.target) g1vlay.addWidget(self.btn2) self.icon, self.icon_label = QLineEdit(), QLabel('Icon File') self.icon.setStyleSheet("QLineEdit{margin-left:25px}") self.clearButton3 = QToolButton(self.icon) self.clearButton3.setIcon(QIcon.fromTheme("edit-clear")) self.clearButton3.setIconSize(QSize(25, 25)) self.clearButton3.setStyleSheet("QToolButton{border:none}") self.clearButton3.hide() self.clearButton3.clicked.connect(self.icon.clear) self.icon.textChanged.connect( lambda: self.clearButton3.setVisible(True)) self.clearButton3.clicked.connect( lambda: self.clearButton3.setVisible(False)) self.icon.setPlaceholderText('Path to Icon file for your App') self.icon.setCompleter(self.completer) self.btn3 = QPushButton(QIcon.fromTheme("document-open"), 'Open' if IS_WIN else '') self.btn3.clicked.connect(lambda: self.icon.setText( str( QFileDialog.getOpenFileName( None, "Open", path.expanduser("~"), ';;'.join([ '{}(*.{})'.format(e.upper(), e) for e in ('ico', 'png', 'bmp', 'svg', '*') ]))))) g1vlay.addWidget(self.icon_label) g1vlay.addWidget(self.icon) g1vlay.addWidget(self.btn3) # Menu Bar inicialization and detail definitions menu_salir = QAction(QIcon.fromTheme("application-exit"), 'Quit', self) menu_salir.setStatusTip('Quit') menu_salir.triggered.connect(exit) menu_minimize = QAction(QIcon.fromTheme("go-down"), 'Minimize', self) menu_minimize.setStatusTip('Minimize') menu_minimize.triggered.connect(lambda: self.showMinimized()) menu_qt = QAction(QIcon.fromTheme("help-about"), 'About Qt', self) menu_qt.setStatusTip('About Qt...') menu_qt.triggered.connect(lambda: QMessageBox.aboutQt(self)) menu_dev = QAction(QIcon.fromTheme("applications-development"), 'Developer Manual PDF', self) menu_dev.setStatusTip('Open Nuitka Developer Manual PDF...') menu_dev.triggered.connect(lambda: call( OPEN + '/usr/share/doc/nuitka/Developer_Manual.pdf.gz', shell=True) ) menu_usr = QAction(QIcon.fromTheme("help-contents"), 'User Docs', self) menu_usr.setStatusTip('Open Nuitka End User Manual PDF...') menu_usr.triggered.connect(lambda: call( OPEN + '/usr/share/doc/nuitka/README.pdf.gz', shell=True)) menu_odoc = QAction(QIcon.fromTheme("help-browser"), 'OnLine Doc', self) menu_odoc.setStatusTip('Open Nuitka on line Documentation pages...') menu_odoc.triggered.connect( lambda: open_new_tab('http://nuitka.net/doc/user-manual.html')) menu_man = QAction(QIcon.fromTheme("utilities-terminal"), 'Man', self) menu_man.setStatusTip('Open Nuitka technical command line Man Pages..') menu_man.triggered.connect( lambda: call('xterm -e "man nuitka"', shell=True)) menu_tra = QAction(QIcon.fromTheme("applications-development"), 'View Nuitka-GUI Source Code', self) menu_tra.setStatusTip('View, study, edit Nuitka-GUI Libre Source Code') menu_tra.triggered.connect(lambda: call(OPEN + __file__, shell=True)) menu_foo = QAction(QIcon.fromTheme("folder"), 'Open Output Dir', self) menu_foo.setStatusTip('Open the actual Output Directory location...') menu_foo.triggered.connect( lambda: call(OPEN + str(self.outdir.text()), shell=True)) menu_pic = QAction(QIcon.fromTheme("camera-photo"), 'Screenshot', self) menu_pic.setStatusTip('Take a Screenshot for Documentation purposes..') menu_pic.triggered.connect( lambda: QPixmap.grabWindow(QApplication.desktop().winId()).save( QFileDialog.getSaveFileName(None, "Save", path.expanduser("~"), 'PNG(*.png)', 'png'))) menu_don = QAction(QIcon.fromTheme("emblem-favorite"), 'Help Nuitka', self) menu_don.setStatusTip('Help the Nuitka Open Source Libre Free Project') menu_don.triggered.connect( lambda: open_new_tab('http://nuitka.net/pages/donations.html')) # movable draggable toolbar self.toolbar = QToolBar(self) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.toggleViewAction().setText("Show/Hide Toolbar") l_spacer, r_spacer = QWidget(self), QWidget(self) l_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) r_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolbar.addWidget(l_spacer) self.toolbar.addSeparator() self.toolbar.addActions((menu_salir, menu_minimize, menu_qt, menu_odoc, menu_foo, menu_pic, menu_don)) if not IS_WIN: self.toolbar.addActions((menu_man, menu_dev, menu_tra, menu_usr)) self.toolbar.addSeparator() self.toolbar.addWidget(r_spacer) self.addToolBar(Qt.BottomToolBarArea, self.toolbar) # Bottom Buttons Bar self.buttonBox = QDialogButtonBox(self) self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Close) self.buttonBox.rejected.connect(exit) self.buttonBox.accepted.connect(self.run) self.guimode = QComboBox() self.guimode.addItems(('Full UX / UI', 'Simple UX / UI')) self.guimode.setStyleSheet( """QComboBox{background:transparent;border:0; margin-left:25px;color:gray;text-decoration:underline}""") self.guimode.currentIndexChanged.connect(self.set_guimode) container = QWidget() container_layout = QGridLayout(container) # Y, X container_layout.addWidget(self.guimode, 0, 1) container_layout.addWidget(self.group2, 1, 0) container_layout.addWidget(self.group3, 2, 0) container_layout.addWidget(self.group0, 1, 1) container_layout.addWidget(self.group1, 2, 1) container_layout.addWidget(self.group4, 1, 2) container_layout.addWidget(self.group5, 2, 2) container_layout.addWidget(self.buttonBox, 3, 1) self.setCentralWidget(container) # Paleta de colores para pintar transparente if not A11Y: palette = self.palette() palette.setBrush(QPalette.Base, Qt.transparent) self.setPalette(palette) self.setAttribute(Qt.WA_OpaquePaintEvent, False) def get_fake_tree(self, target): """Return the fake tree.""" try: fake_tree = check_output(NUITKA + ' --dump-xml ' + target, shell=True) except: fake_tree = "ERROR: Failed to get Tree Dump." finally: return fake_tree.strip() def run(self): ' run the actual backend process ' self.treeview_nodes.clear() self.textedit_source.clear() self.output.clear() self.statusBar().showMessage('WAIT!, Working...') target = str(self.target.text()).strip() self.treeview_nodes.setText(self.get_fake_tree(target)) self.textedit_source.setText(open(target, "r").read().strip()) conditional_1 = sys.platform.startswith('linux') conditional_2 = self.combo3.currentIndex() != 2 command_to_run_nuitka = " ".join( ('chrt -i 0' if conditional_1 and conditional_2 else '', NUITKA, '--debug' if self.slider1.value() else '', '--verbose' if self.slider2.value() else '', '--show-progress' if self.slider3.value() else '', '--show-scons --show-modules' if self.slider4.value() else '', '--unstriped' if self.slider5.value() else '', '--trace-execution' if self.slider6.value() else '', '--remove-output' if self.slider7.value() else '', '--no-optimization' if self.slider8.value() else '', '--code-gen-no-statement-lines' if self.slider9.value() else '', '--execute' if self.slider10.value() else '', '--recurse-all' if self.slider1a.value() else '', '--recurse-none' if self.slider2a.value() else '', '--recurse-stdlib' if self.slider3a.value() else '', '--clang' if self.slider4a.value() else '', '--lto' if self.slider5a.value() else '', '--windows-disable-console' if self.slider6a.value() else '', '--windows-target' if self.slider7a.value() else '', '--python-debug' if self.slider8a.value() else '', '--exe' if self.slider9a.value() else '', '--standalone' if self.slider10a.value() else '', '--module' if self.slider11a.value() else '', '--nofreeze-stdlib' if self.slider12a.value() else '', '--mingw' if self.slider13a.value() else '', '--warn-implicit-exceptions' if self.slider11.value() else '', '--execute-with-pythonpath' if self.slider12.value() else '', '--enhanced' if self.slider13.value() else '', '--icon="{}"'.format(self.icon.text()) if self.icon.text() else '', '--python-version={}'.format( self.combo1.currentText()), '--jobs={}'.format( self.combo3.currentText()), '--output-dir="{}"'.format( self.outdir.text()), "{}".format(target))) if DEBUG: print(command_to_run_nuitka) self.process.start(command_to_run_nuitka) if not self.process.waitForStarted() and not IS_WIN: return # ERROR ! self.statusBar().showMessage(__doc__.title()) def _process_finished(self): """finished sucessfully""" self.output.setFocus() self.output.selectAll() def read_output(self): """Read and append output to the log""" self.output.append(str(self.process.readAllStandardOutput())) def read_errors(self): """Read and append errors to the log""" self.output.append(str(self.process.readAllStandardError())) def paintEvent(self, event): """Paint semi-transparent background,animated pattern,background text""" if not A11Y: p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) p.setRenderHint(QPainter.TextAntialiasing) p.setRenderHint(QPainter.HighQualityAntialiasing) p.fillRect(event.rect(), Qt.transparent) # animated random dots background pattern for i in range(4096): x = randint(25, self.size().width() - 25) y = randint(25, self.size().height() - 25) # p.setPen(QPen(QColor(randint(9, 255), 255, 255), 1)) p.drawPoint(x, y) p.setPen(QPen(Qt.white, 1)) p.rotate(40) p.setFont(QFont('Ubuntu', 250)) p.drawText(200, 99, "Nuitka") p.rotate(-40) p.setPen(Qt.NoPen) p.setBrush(QColor(0, 0, 0)) p.setOpacity(0.8) p.drawRoundedRect(self.rect(), 9, 9) p.end() def set_guimode(self): """Switch between simple and full UX""" for widget in (self.group2, self.group3, self.group4, self.group5, self.icon, self.icon_label, self.btn3, self.toolbar, self.statusBar()): widget.hide() if self.guimode.currentIndex() else widget.show()
class SearchBox(QWidget): def __init__(self, parent = None): super(SearchBox, self).__init__(parent) self.setFixedHeight(30) self.lineEdit = QLineEdit() self.lineEdit.setFixedHeight(29) self.lineEdit.setToolTip("输入搜索关键词") self.lineEdit.setFocusPolicy(Qt.ClickFocus) self.searchButton = QToolButton() self.searchButton.setText("搜索") self.searchButton.setFixedHeight(30) self.searchButton.setToolTip("点击搜索") self.searchButton.setCursor(QCursor(Qt.PointingHandCursor)) self.resetButton = QToolButton() self.resetButton.setIcon(QIcon(":/iconSources/icons/reset.png")) self.resetButton.setIconSize(QSize(24, 24)) self.resetButton.setFixedSize(27, 27) self.resetButton.setToolTip("重置搜索") self.resetButton.setCursor(QCursor(Qt.PointingHandCursor)) self.clearButton = QToolButton() self.searchComboBox = QComboBox() self.searchComboBox.setToolTip("选择搜索类型") musicIcon = QIcon(":/iconSources/icons/music.png") artistIcon = QIcon(":/iconSources/icons/artist.png") albumIcon = QIcon(":/iconSources/icons/album.png") self.searchComboBox.setIconSize(QSize(20,20)) self.searchComboBox.insertItem(0, musicIcon, "歌曲") self.searchComboBox.insertItem(1, artistIcon, "歌手") self.searchComboBox.insertItem(2, albumIcon, "专辑") self.searchComboBox.setFixedSize(78, 27) self.searchComboBox.setCursor(Qt.PointingHandCursor) searchIcon = QIcon(":/iconSources/icons/delete.png") self.clearButton.setFixedSize(27, 27) self.clearButton.setIcon(searchIcon) self.clearButton.setIconSize(QSize(18, 18)) self.clearButton.setAutoRaise(True) self.clearButton.setToolTip("清空搜索栏") self.clearButton.setCursor(Qt.PointingHandCursor) self.clearButton.hide() searchLayout = QHBoxLayout() searchLayout.addWidget(self.searchComboBox) searchLayout.addStretch() searchLayout.addWidget(self.clearButton) searchLayout.setMargin(1) searchLayout.setSpacing(0) searchLayout.setContentsMargins(0, 0, 0, 0) self.lineEdit.setLayout(searchLayout) self.lineEdit.setTextMargins(self.searchComboBox.width(), 0, self.clearButton.width(), 0) mainLayout = QHBoxLayout(self) mainLayout.setMargin(0) mainLayout.setSpacing(1) mainLayout.addWidget(self.resetButton) mainLayout.addWidget(self.lineEdit) mainLayout.addWidget(self.searchButton) #self.connect(self.clearButton, SIGNAL("clicked()"), self.lineEdit.clear) self.clearButton.clicked.connect(self.lineEdit.clear) self.lineEdit.textChanged.connect(self.clrbutton_show) def clrbutton_show(self): if self.lineEdit.text(): self.clearButton.show() else: self.clearButton.hide()
class Search_QLineEdit(QLineEdit): """ This class is a `QLineEdit <http://doc.qt.nokia.com/qlinedit.html>`_ subclass providing a search field with clearing capabilities. """ @core.executionTrace def __init__(self, parent=None, uiSearchImage=None, uiSearchClickedImage=None, uiClearImage=None, uiClearClickedImage=None): """ This method initializes the class. :param parent: Widget parent. ( QObject ) :param uiSearchImage: Search button image path. ( String ) :param uiSearchClickedImage: Search button clicked image path. ( String ) :param uiClearImage: Clear button image path. ( String ) :param uiClearClickedImage: Clear button clicked image path. ( String ) """ LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__)) QLineEdit.__init__(self, parent) # --- Setting class attributes. --- self.__uiSearchImage = None self.uiSearchImage = uiSearchImage or snippets.ui.common.getResourcePath("images/Search_Glass.png") self.__uiSearchClickedImage = None self.uiSearchClickedImage = uiSearchClickedImage or snippets.ui.common.getResourcePath( "images/Search_Glass_Clicked.png") self.__uiClearImage = None self.uiClearImage = uiClearImage or snippets.ui.common.getResourcePath("images/Search_Clear.png") self.__uiClearClickedImage = None self.uiClearClickedImage = uiClearClickedImage or snippets.ui.common.getResourcePath( "images/Search_Clear_Clicked.png") self.__searchActiveLabel = Active_QLabel(self, QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchClickedImage)) self.__searchActiveLabel.setObjectName("Search_Field_activeLabel") self.__clearButton = QToolButton(self) self.__clearButton.setObjectName("Clear_Field_button") self.__completer = QCompleter() self.setCompleter(self.__completer) self.__completerVisibleItemsCount = 16 # TODO: Rollback to Search_QLineEdit.__initializeUi(self) whenever MPC changes it's PyQt version. self.__initializeUi() self.__setClearButtonVisibility(self.text()) # Signals / Slots. self.__clearButton.clicked.connect(self.clear) self.textChanged.connect(self.__setClearButtonVisibility) #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def uiSearchImage(self): """ This method is the property for **self.__uiSearchImage** attribute. :return: self.__uiSearchImage. ( String ) """ return self.__uiSearchImage @uiSearchImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiSearchImage(self, value): """ This method is the setter method for **self.__uiSearchImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiSearchImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format("uiSearchImage", value) self.__uiSearchImage = value @uiSearchImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiSearchImage(self): """ This method is the deleter method for **self.__uiSearchImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchImage")) @property def uiSearchClickedImage(self): """ This method is the property for **self.__uiSearchClickedImage** attribute. :return: self.__uiSearchClickedImage. ( String ) """ return self.__uiSearchClickedImage @uiSearchClickedImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiSearchClickedImage(self, value): """ This method is the setter method for **self.__uiSearchClickedImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiSearchClickedImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchClickedImage", value) self.__uiSearchClickedImage = value @uiSearchClickedImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiSearchClickedImage(self): """ This method is the deleter method for **self.__uiSearchClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchClickedImage")) @property def uiClearImage(self): """ This method is the property for **self.__uiClearImage** attribute. :return: self.__uiClearImage. ( String ) """ return self.__uiClearImage @uiClearImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiClearImage(self, value): """ This method is the setter method for **self.__uiClearImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiClearImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearImage", value) self.__uiClearImage = value @uiClearImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiClearImage(self): """ This method is the deleter method for **self.__uiClearImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearImage")) @property def uiClearClickedImage(self): """ This method is the property for **self.__uiClearClickedImage** attribute. :return: self.__uiClearClickedImage. ( String ) """ return self.__uiClearClickedImage @uiClearClickedImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiClearClickedImage(self, value): """ This method is the setter method for **self.__uiClearClickedImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiClearClickedImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearClickedImage", value) self.__uiClearClickedImage = value @uiClearClickedImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiClearClickedImage(self): """ This method is the deleter method for **self.__uiClearClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearClickedImage")) @property def searchActiveLabel(self): """ This method is the property for **self.__searchActiveLabel** attribute. :return: self.__searchActiveLabel. ( QPushButton ) """ return self.__searchActiveLabel @searchActiveLabel.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def searchActiveLabel(self, value): """ This method is the setter method for **self.__searchActiveLabel** attribute. :param value: Attribute value. ( QPushButton ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "searchActiveLabel")) @searchActiveLabel.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def searchActiveLabel(self): """ This method is the deleter method for **self.__searchActiveLabel** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "searchActiveLabel")) @property def clearButton(self): """ This method is the property for **self.__clearButton** attribute. :return: self.__clearButton. ( QPushButton ) """ return self.__clearButton @clearButton.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def clearButton(self, value): """ This method is the setter method for **self.__clearButton** attribute. :param value: Attribute value. ( QPushButton ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "clearButton")) @clearButton.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def clearButton(self): """ This method is the deleter method for **self.__clearButton** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "clearButton")) @property def completer(self): """ This method is the property for **self.__completer** attribute. :return: self.__completer. ( QCompleter ) """ return self.__completer @completer.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completer(self, value): """ This method is the setter method for **self.__completer** attribute. :param value: Attribute value. ( QCompleter ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completer")) @completer.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completer(self): """ This method is the deleter method for **self.__completer** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completer")) @property def completerVisibleItemsCount(self): """ This method is the property for **self.__completerVisibleItemsCount** attribute. :return: self.__completerVisibleItemsCount. ( Integer ) """ return self.__completerVisibleItemsCount @completerVisibleItemsCount.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self, value): """ This method is the setter method for **self.__completerVisibleItemsCount** attribute. :param value: Attribute value. ( Integer ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completerVisibleItemsCount")) @completerVisibleItemsCount.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self): """ This method is the deleter method for **self.__completerVisibleItemsCount** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completerVisibleItemsCount")) #****************************************************************************************************************** #*** Class methods. #****************************************************************************************************************** @core.executionTrace def resizeEvent(self, event): """ This method reimplements the :meth:`QLineEdit.QResizeEvent` method. :param event: Resize event. ( QResizeEvent ) """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) searchActiveLabelSize = self.__searchActiveLabel.sizeHint() self.__searchActiveLabel.move(self.rect().left() + frameWidth, (self.rect().bottom() - searchActiveLabelSize.height()) / 2 + frameWidth / 2) clearButtonSize = self.__clearButton.sizeHint() self.__clearButton.move(self.rect().right() - frameWidth - clearButtonSize.width(), (self.rect().bottom() - clearButtonSize.height()) / 2 + frameWidth / 2) @core.executionTrace def __initializeUi(self): """ This method initializes the Widget ui. """ self.__clearButton.setCursor(Qt.ArrowCursor) if self.__uiClearImage and self.__uiClearClickedImage: pixmap = QPixmap(self.__uiClearImage) clickedPixmap = QPixmap(self.__uiClearClickedImage) self.__clearButton.setStyleSheet("QToolButton { border: none; padding: 0px; }") self.__clearButton.setIcon(QIcon(pixmap)) self.__clearButton.setMaximumSize(pixmap.size()) # Signals / Slots. self.__clearButton.pressed.connect(functools.partial(self.__clearButton.setIcon, QIcon(clickedPixmap))) self.__clearButton.released.connect(functools.partial(self.__clearButton.setIcon, QIcon(pixmap))) else: self.__clearButton.setText("Clear") frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet(QString("QLineEdit {{ padding-left: {0}px; padding-right: {1}px; }}".format( self.__searchActiveLabel.sizeHint().width() + frameWidth, self.__clearButton.sizeHint().width() + frameWidth))) self.setMinimumSize(max(self.minimumSizeHint().width(), self.__clearButton.sizeHint().height() + frameWidth * 2), max(self.minimumSizeHint().height(), self.__clearButton.sizeHint().height() + frameWidth * 2)) self.__completer.setCaseSensitivity(Qt.CaseInsensitive) self.__completer.setCompletionMode(QCompleter.PopupCompletion) # TODO: Restore next line whnever MPC changes it's PyQt version. # self.__completer.setMaxVisibleItems(self.__completerVisibleItemsCount) @core.executionTrace def __setClearButtonVisibility(self, text): """ This method sets the clear button visibility. :param text: Current field text. ( QString ) """ if text: self.__clearButton.show() else: self.__clearButton.hide()
class projectInfoWidget(infoWidget): __master_url = "" __projectCached = None __mainLayout = None __projectInfo = None __projectInfoLayout = None __projectSettings = None #informacie o projekte __masterUrlLabel = None __masterUrlText = None __projectNameLabel = None __projectNameText = None __userNameLabel = None __userNameText = None __teamNameLabel = None __teamNameText = None __userTotalCreditLabel = None __userTotalCreditText = None __hostTotalCreditLabel = None __hostTotalCreditText = None __suspendedLabel = None __newTasksLabel = None __projectLinksButton = None __projectSettingsMenu = None def __init__(self, client, project, parent = None): infoWidget.__init__(self, client, parent) self.__mainLayout = QGridLayout() self.__mainLayout.setRowStretch(1, 1) self.setMainLayout(self.__mainLayout) self.__projectInfo = QGroupBox(self.tr("Project Info")); self.__projectInfoLayout = QGridLayout() self.__projectInfo.setLayout(self.__projectInfoLayout) self.__projectSettings = QHBoxLayout() self.__projectLinksButton = QToolButton() self.__projectLinksButton.setText(self.tr("Project Links")) self.__projectLinksButton.hide() self.__updateProjectButton = QPushButton(self.tr("Update")) self.__suspendProjectButton = QPushButton() self.__allowNewTasksButton = QPushButton() self.__resetProjectButton = QPushButton(self.tr("Reset project")) self.__detachProjectButton = QPushButton(self.tr("Detach project")) self.__resetProjectButton.setEnabled(False) self.__detachProjectButton.setEnabled(False) self.__updateProjectButton.hide() self.__suspendProjectButton.hide() self.__allowNewTasksButton.hide() self.__resetProjectButton.hide() self.__detachProjectButton.hide() self.connect(self.__updateProjectButton, SIGNAL('clicked()'), self.__updateProject) self.connect(self.__suspendProjectButton, SIGNAL('clicked()'), self.__suspendProject) self.connect(self.__allowNewTasksButton, SIGNAL('clicked()'), self.__allowNewTasksProject) self.__projectSettings.addWidget(self.__projectLinksButton) self.__projectSettings.addWidget(self.__updateProjectButton) self.__projectSettings.addWidget(self.__suspendProjectButton) self.__projectSettings.addWidget(self.__allowNewTasksButton) #self.__projectSettings.addStretch(1) self.__projectAdmin = QHBoxLayout() self.__projectAdmin.addWidget(self.__resetProjectButton) self.__projectAdmin.addWidget(self.__detachProjectButton) #self.__projectAdmin.addStretch(1) self.__mainLayout.addWidget(self.__projectInfo, 0, 0) self.__mainLayout.addLayout(self.__projectSettings, 2, 0) self.__mainLayout.addLayout(self.__projectAdmin, 3, 0) self.__masterUrlLabel = QLabel(self.tr("Master URL")) self.__projectNameLabel = QLabel(self.tr("Project Name")) self.__userNameLabel = QLabel(self.tr("User Name")) self.__teamNameLabel = QLabel(self.tr("Team Name")) self.__userTotalCreditLabel = QLabel(self.tr("Total User Credits")) self.__hostTotalCreditLabel = QLabel(self.tr("Total Host Credits")) self.__suspendedLabel = QLabel(self.tr("Suspended by user")) self.__newTasksLabel = QLabel(self.tr("Won't get new tasks")) self.__masterUrlText = QLabel() self.__projectNameText = QLabel() self.__userNameText = QLabel() self.__teamNameText = QLabel() self.__userTotalCreditText = QLabel() self.__hostTotalCreditText = QLabel() self.__masterUrlText.setTextFormat(Qt.PlainText) self.__projectNameText.setTextFormat(Qt.PlainText) self.__userNameText.setTextFormat(Qt.PlainText) self.__teamNameText.setTextFormat(Qt.PlainText) self.__userTotalCreditText.setTextFormat(Qt.PlainText) self.__hostTotalCreditText.setTextFormat(Qt.PlainText) self.__masterUrlLabel.hide() self.__projectNameLabel.hide() self.__userNameLabel.hide() self.__teamNameLabel.hide() self.__userTotalCreditLabel.hide() self.__hostTotalCreditLabel.hide() self.__masterUrlText.hide() self.__projectNameText.hide() self.__userNameText.hide() self.__teamNameText.hide() self.__userTotalCreditText.hide() self.__hostTotalCreditText.hide() self.__suspendedLabel.hide() self.__newTasksLabel.hide() self.__projectInfoLayout.addWidget(self.__masterUrlLabel, 0, 0) self.__projectInfoLayout.addWidget(self.__projectNameLabel, 1, 0) self.__projectInfoLayout.addWidget(self.__userNameLabel, 2, 0) self.__projectInfoLayout.addWidget(self.__teamNameLabel, 3, 0) self.__projectInfoLayout.addWidget(self.__userTotalCreditLabel, 4, 0) self.__projectInfoLayout.addWidget(self.__hostTotalCreditLabel, 5, 0) self.__projectInfoLayout.addWidget(self.__masterUrlText, 0, 1) self.__projectInfoLayout.addWidget(self.__projectNameText, 1, 1) self.__projectInfoLayout.addWidget(self.__userNameText, 2, 1) self.__projectInfoLayout.addWidget(self.__teamNameText, 3, 1) self.__projectInfoLayout.addWidget(self.__userTotalCreditText, 4, 1) self.__projectInfoLayout.addWidget(self.__hostTotalCreditText, 5, 1) self.__projectInfoLayout.addWidget(self.__suspendedLabel, 6, 0, 1, 2) self.__projectInfoLayout.addWidget(self.__newTasksLabel, 7, 0, 1, 2) self.__master_url = project.data(0, Qt.UserRole + 1).toString() self.__projectCached = None self.__projectSettingsMenu = QMenu() self.__projectLinksButton.setPopupMode(QToolButton.InstantPopup) self.__projectLinksButton.setMenu(self.__projectSettingsMenu) projects = client.projectState() if not projects is None: self.updateProjects(projects) self.connect(client, SIGNAL("projectState(PyQt_PyObject)"), self.updateProjects) self.connect(client, SIGNAL("projectUpdateRecv(PyQt_PyObject)"), self.__updateProjectRecv) self.connect(client, SIGNAL("projectSuspendRecv(PyQt_PyObject)"), self.__suspendProjectRecv) self.connect(client, SIGNAL("projectResumeRecv(PyQt_PyObject)"), self.__resumeProjectRecv) self.connect(client, SIGNAL("projectNomoreworkRecv(PyQt_PyObject)"), self.__nomoreworkProjectRecv) self.connect(client, SIGNAL("projectAllowmoreworkRecv(PyQt_PyObject)"), self.__allowmoreworkProjectRecv) def __updateProject(self): self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Updating project")) self.client().projectUpdate(self.__projectCached['master_url']) def __suspendProject(self): if self.__projectCached['suspended_via_gui']: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Resuming project")) self.client().projectResume(self.__projectCached['master_url']) else: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Suspending project")) self.client().projectSuspend(self.__projectCached['master_url']) def __allowNewTasksProject(self): if self.__projectCached['dont_request_more_work']: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Allowing new tasks")) self.client().projectAllowmorework(self.__projectCached['master_url']) else: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Disallowing new tasks")) self.client().projectNomorework(self.__projectCached['master_url']) def __updateProjectRecv(self, status): if status: self.emit(SIGNAL("showStatusBarMsg(QString)"), status) else: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Project updated")) self.client().getState() def __suspendProjectRecv(self, status): if status: self.emit(SIGNAL("showStatusBarMsg(QString)"), status) else: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Project suspended")) self.__projectCached['suspended_via_gui'] = 1 self.__suspendedLabel.show() self.__suspendProjectButton.setText(self.tr("Resume")) self.client().getState() def __resumeProjectRecv(self, status): if status: self.emit(SIGNAL("showStatusBarMsg(QString)"), status) else: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("Project restored")) self.__projectCached['suspended_via_gui'] = 0 self.__suspendedLabel.hide() self.__suspendProjectButton.setText(self.tr("Suspend")) self.client().getState() def __nomoreworkProjectRecv(self, status): if status: self.emit(SIGNAL("showStatusBarMsg(QString)"), status) else: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("New tasks disallowed")) self.__projectCached['dont_request_more_work'] = 1 self.__newTasksLabel.show() self.__allowNewTasksButton.setText(self.tr("Allow new tasks")) self.client().getState() def __allowmoreworkProjectRecv(self, status): if status: self.emit(SIGNAL("showStatusBarMsg(QString)"), status) else: self.emit(SIGNAL("showStatusBarMsg(QString)"), self.tr("New tasks allowed")) self.__projectCached['dont_request_more_work'] = 0 self.__newTasksLabel.hide() self.__allowNewTasksButton.setText(self.tr("No new tasks")) self.client().getState() def __changeLabels(self, project, key, label, text): try: inf = project[key] if type(inf) == type(u""): text.setText(inf) text.show() label.show() except KeyError: text.hide() label.hide() def updateProjects(self, projects): projects = projects['project'] project = None for proj in projects: if proj['master_url'] == self.__master_url: project = proj break # ak sme nenasli projekt if project is None: return if project != self.__projectCached: self.__projectCached = project try: self.setTitle(titleFrame(project['project_name'])) except KeyError: pass self.__changeLabels(project, 'master_url', self.__masterUrlLabel, self.__masterUrlText) self.__changeLabels(project, 'project_name', self.__projectNameLabel, self.__projectNameText) self.__changeLabels(project, 'user_name', self.__userNameLabel, self.__userNameText) self.__changeLabels(project, 'team_name', self.__teamNameLabel, self.__teamNameText) self.__changeLabels(project, 'user_total_credit', self.__userTotalCreditLabel, self.__userTotalCreditText) self.__changeLabels(project, 'host_total_credit', self.__hostTotalCreditLabel, self.__hostTotalCreditText) if project['suspended_via_gui']: self.__suspendProjectButton.setText(self.tr("Resume")) self.__suspendedLabel.show() else: self.__suspendProjectButton.setText(self.tr("Suspend")) self.__suspendedLabel.hide() if project['dont_request_more_work']: self.__allowNewTasksButton.setText(self.tr("Allow new tasks")) self.__newTasksLabel.show() else: self.__allowNewTasksButton.setText(self.tr("No new tasks")) self.__newTasksLabel.hide() self.__updateProjectButton.show() self.__suspendProjectButton.show() self.__allowNewTasksButton.show() self.__resetProjectButton.show() self.__detachProjectButton.show() try: self.__projectSettingsMenu.clear() guiUrls = project['gui_urls']['gui_url'] if type(guiUrls) == type({}): self.__projectSettingsMenu.addAction(urlAction(guiUrls['url'], guiUrls['name'], guiUrls['description'], self.__projectSettingsMenu)) else: for url in guiUrls: self.__projectSettingsMenu.addAction(urlAction(url['url'], url['name'], url['description'], self.__projectSettingsMenu)) try: ifTeamUrls = project['gui_urls']['ifteam']['gui_url'] self.__projectSettingsMenu.addSeparator() if type(ifTeamUrls) == type({}): self.__projectSettingsMenu.addAction(urlAction(ifTeamUrls['url'], ifTeamUrls['name'], ifTeamUrls['description'], self.__projectSettingsMenu)) else: for url in ifTeamUrls: self.__projectSettingsMenu.addAction(urlAction(url['url'], url['name'], url['description'], self.__projectSettingsMenu)) except KeyError, msg: pass self.__projectLinksButton.show() except KeyError: self.__projectLinksButton.hide()