class XFindWidget(QWidget): """ """ __designer_icon__ = resources.find('img/search.png') def __init__(self, parent=None): super(XFindWidget, self).__init__(parent) # define custom properties self._textEdit = None self._webView = None self._lastCursor = QTextCursor() self._lastText = '' self._closeButton = QToolButton(self) self._closeButton.setIcon(QIcon(resources.find('img/close.png'))) self._closeButton.setAutoRaise(True) self._closeButton.setToolTip('Hide the Find Field.') self._searchEdit = XLineEdit(self) self._searchEdit.setHint('search for...') self._previousButton = QToolButton(self) self._previousButton.setIcon(QIcon(resources.find('img/back.png'))) self._previousButton.setAutoRaise(True) self._previousButton.setToolTip('Find Previous') self._nextButton = QToolButton(self) self._nextButton.setIcon(QIcon(resources.find('img/forward.png'))) self._nextButton.setAutoRaise(True) self._nextButton.setToolTip('Find Next') self._caseSensitiveCheckbox = QCheckBox(self) self._caseSensitiveCheckbox.setText('Case Sensitive') self._wholeWordsCheckbox = QCheckBox(self) self._wholeWordsCheckbox.setText('Whole Words Only') self._regexCheckbox = QCheckBox(self) self._regexCheckbox.setText('Use Regex') self._findAction = QAction(self) self._findAction.setText('Find...') self._findAction.setIcon(QIcon(resources.find('img/search.png'))) self._findAction.setToolTip('Find in Text') self._findAction.setShortcut(QKeySequence('Ctrl+F')) self._findAction.setShortcutContext(Qt.WidgetWithChildrenShortcut) # layout the widgets layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._closeButton) layout.addWidget(self._searchEdit) layout.addWidget(self._previousButton) layout.addWidget(self._nextButton) layout.addWidget(self._caseSensitiveCheckbox) layout.addWidget(self._wholeWordsCheckbox) layout.addWidget(self._regexCheckbox) self.setLayout(layout) # create connections self._findAction.triggered.connect(self.show) self._searchEdit.textChanged.connect(self.findNext) self._closeButton.clicked.connect(self.hide) self._previousButton.clicked.connect(self.findPrev) self._nextButton.clicked.connect(self.findNext) self._caseSensitiveCheckbox.clicked.connect(self.findNext) self._wholeWordsCheckbox.clicked.connect(self.findNext) self._searchEdit.returnPressed.connect(self.findNext) self._regexCheckbox.clicked.connect(self.findNext) def find(self, flags=0): """ Looks throught the text document based on the current criteria. The \ inputed flags will be merged with the generated search flags. :param flags | <QTextDocument.FindFlag> :return <bool> | success """ # check against the web and text views if (not (self._textEdit or self._webView)): fg = QColor('darkRed') bg = QColor('red').lighter(180) palette = self.palette() palette.setColor(palette.Text, fg) palette.setColor(palette.Base, bg) self._searchEdit.setPalette(palette) self._searchEdit.setToolTip('No Text Edit is linked.') return False if (self._caseSensitiveCheckbox.isChecked()): flags |= QTextDocument.FindCaseSensitively if (self._textEdit and self._wholeWordsCheckbox.isChecked()): flags |= QTextDocument.FindWholeWords terms = self._searchEdit.text() if (terms != self._lastText): self._lastCursor = QTextCursor() if (self._regexCheckbox.isChecked()): terms = QRegExp(terms) palette = self.palette() # search on a text edit if (self._textEdit): cursor = self._textEdit.document().find( terms, self._lastCursor, QTextDocument.FindFlags(flags)) found = not cursor.isNull() self._lastCursor = cursor self._textEdit.setTextCursor(cursor) elif (QWebPage): flags = QWebPage.FindFlags(flags) flags |= QWebPage.FindWrapsAroundDocument found = self._webView.findText(terms, flags) self._lastText = self._searchEdit.text() if (not terms or found): fg = palette.color(palette.Text) bg = palette.color(palette.Base) else: fg = QColor('darkRed') bg = QColor('red').lighter(180) palette.setColor(palette.Text, fg) palette.setColor(palette.Base, bg) self._searchEdit.setPalette(palette) return found def findNext(self): """ Looks for the search terms that come up next based on the criteria. :return <bool> | success """ return self.find() def findPrev(self): """ Looks for the search terms that come up last based on the criteria. :return <bool> | success """ return self.find(QTextDocument.FindBackward) def setTextEdit(self, textEdit): """ Sets the text edit that this find widget will use to search. :param textEdit | <QTextEdit> """ if (self._textEdit): self._textEdit.removeAction(self._findAction) self._textEdit = textEdit if (textEdit): textEdit.addAction(self._findAction) def setWebView(self, webView): """ Sets the web view edit that this find widget will use to search. :param webView | <QWebView> """ if (self._webView): self._webView.removeAction(self._findAction) self._webView = webView if (webView): webView.addAction(self._findAction) def show(self): """ Sets this widget visible and then makes the find field have focus. """ super(XFindWidget, self).show() self._searchEdit.setFocus() def textEdit(self): """ Returns the text edit linked with this find widget. :return <QTextEdit> """ return self._textEdit def webView(self): """ Returns the text edit linked with this find widget. :return <QWebView> """ return self._webView
class XUrlWidget(QWidget): urlChanged = qt.Signal(str) urlEdited = qt.Signal() def __init__(self, parent): super(XUrlWidget, self).__init__(parent) # define the interface self._urlEdit = XLineEdit(self) self._urlButton = QToolButton(self) self._urlButton.setAutoRaise(True) self._urlButton.setIcon(QIcon(resources.find('img/web.png'))) self._urlButton.setToolTip('Browse Link') self._urlButton.setFocusPolicy(Qt.NoFocus) self._urlEdit.setHint('http://') layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self._urlEdit) layout.addWidget(self._urlButton) self.setLayout(layout) self.setFocusPolicy(Qt.StrongFocus) # create connections self._urlEdit.textChanged.connect(self.urlChanged) self._urlEdit.textEdited.connect(self.urlEdited) self._urlButton.clicked.connect(self.browse) def blockSignals(self, state): """ Blocks the signals for this widget and its sub-parts. :param state | <bool> """ super(XUrlWidget, self).blockSignals(state) self._urlEdit.blockSignals(state) self._urlButton.blockSignals(state) def browse(self): """ Brings up a web browser with the address in a Google map. """ webbrowser.open(self.url()) def hint(self): """ Returns the hint associated with this widget. :return <str> """ return self._urlEdit.hint() def lineEdit(self): """ Returns the line edit linked with this widget. :return <XLineEdit> """ return self._urlEdit def setFocus(self): """ Sets the focus for this widget on its line edit. """ self._urlEdit.setFocus() @qt.Slot(str) def setHint(self, hint): """ Sets the hint associated with this widget. :param hint | <str> """ self._urlEdit.setHint(hint) @qt.Slot(str) def setUrl(self, url): """ Sets the url for this widget to the inputed url. :param url | <str> """ self._urlEdit.setText(str(url)) def url(self): """ Returns the current url from the edit. :return <str> """ return str(self._urlEdit.text()) x_hint = qt.Property(str, hint, setHint) x_url = qt.Property(str, url, setUrl)
class XFindWidget(QWidget): """ """ __designer_icon__ = resources.find('img/search.png') def __init__( self, parent = None ): super(XFindWidget, self).__init__( parent ) # define custom properties self._textEdit = None self._webView = None self._lastCursor = QTextCursor() self._lastText = '' self._closeButton = QToolButton(self) self._closeButton.setIcon(QIcon(resources.find('img/close.png'))) self._closeButton.setAutoRaise(True) self._closeButton.setToolTip('Hide the Find Field.') self._searchEdit = XLineEdit(self) self._searchEdit.setHint('search for...') self._previousButton = QToolButton(self) self._previousButton.setIcon(QIcon(resources.find('img/back.png'))) self._previousButton.setAutoRaise(True) self._previousButton.setToolTip('Find Previous') self._nextButton = QToolButton(self) self._nextButton.setIcon(QIcon(resources.find('img/forward.png'))) self._nextButton.setAutoRaise(True) self._nextButton.setToolTip('Find Next') self._caseSensitiveCheckbox = QCheckBox(self) self._caseSensitiveCheckbox.setText('Case Sensitive') self._wholeWordsCheckbox = QCheckBox(self) self._wholeWordsCheckbox.setText('Whole Words Only') self._regexCheckbox = QCheckBox(self) self._regexCheckbox.setText('Use Regex') self._findAction = QAction(self) self._findAction.setText('Find...') self._findAction.setIcon(QIcon(resources.find('img/search.png'))) self._findAction.setToolTip('Find in Text') self._findAction.setShortcut(QKeySequence('Ctrl+F')) self._findAction.setShortcutContext(Qt.WidgetWithChildrenShortcut) # layout the widgets layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget( self._closeButton ) layout.addWidget( self._searchEdit ) layout.addWidget( self._previousButton ) layout.addWidget( self._nextButton ) layout.addWidget( self._caseSensitiveCheckbox ) layout.addWidget( self._wholeWordsCheckbox ) layout.addWidget( self._regexCheckbox ) self.setLayout(layout) # create connections self._findAction.triggered.connect( self.show ) self._searchEdit.textChanged.connect( self.findNext ) self._closeButton.clicked.connect( self.hide ) self._previousButton.clicked.connect( self.findPrev ) self._nextButton.clicked.connect( self.findNext ) self._caseSensitiveCheckbox.clicked.connect( self.findNext ) self._wholeWordsCheckbox.clicked.connect( self.findNext ) self._searchEdit.returnPressed.connect( self.findNext ) self._regexCheckbox.clicked.connect( self.findNext ) def find( self, flags = 0 ): """ Looks throught the text document based on the current criteria. The \ inputed flags will be merged with the generated search flags. :param flags | <QTextDocument.FindFlag> :return <bool> | success """ # check against the web and text views if ( not (self._textEdit or self._webView) ): fg = QColor('darkRed') bg = QColor('red').lighter(180) palette = self.palette() palette.setColor(palette.Text, fg) palette.setColor(palette.Base, bg) self._searchEdit.setPalette(palette) self._searchEdit.setToolTip( 'No Text Edit is linked.' ) return False if ( self._caseSensitiveCheckbox.isChecked() ): flags |= QTextDocument.FindCaseSensitively if ( self._textEdit and self._wholeWordsCheckbox.isChecked() ): flags |= QTextDocument.FindWholeWords terms = self._searchEdit.text() if ( terms != self._lastText ): self._lastCursor = QTextCursor() if ( self._regexCheckbox.isChecked() ): terms = QRegExp(terms) palette = self.palette() # search on a text edit if ( self._textEdit ): cursor = self._textEdit.document().find(terms, self._lastCursor, QTextDocument.FindFlags(flags)) found = not cursor.isNull() self._lastCursor = cursor self._textEdit.setTextCursor(cursor) elif ( QWebPage ): flags = QWebPage.FindFlags(flags) flags |= QWebPage.FindWrapsAroundDocument found = self._webView.findText(terms, flags) self._lastText = self._searchEdit.text() if ( not terms or found ): fg = palette.color(palette.Text) bg = palette.color(palette.Base) else: fg = QColor('darkRed') bg = QColor('red').lighter(180) palette.setColor(palette.Text, fg) palette.setColor(palette.Base, bg) self._searchEdit.setPalette(palette) return found def findNext( self ): """ Looks for the search terms that come up next based on the criteria. :return <bool> | success """ return self.find() def findPrev( self ): """ Looks for the search terms that come up last based on the criteria. :return <bool> | success """ return self.find(QTextDocument.FindBackward) def setTextEdit( self, textEdit ): """ Sets the text edit that this find widget will use to search. :param textEdit | <QTextEdit> """ if ( self._textEdit ): self._textEdit.removeAction(self._findAction) self._textEdit = textEdit if ( textEdit ): textEdit.addAction(self._findAction) def setWebView( self, webView ): """ Sets the web view edit that this find widget will use to search. :param webView | <QWebView> """ if ( self._webView ): self._webView.removeAction(self._findAction) self._webView = webView if ( webView ): webView.addAction(self._findAction) def show( self ): """ Sets this widget visible and then makes the find field have focus. """ super(XFindWidget, self).show() self._searchEdit.setFocus() def textEdit( self ): """ Returns the text edit linked with this find widget. :return <QTextEdit> """ return self._textEdit def webView( self ): """ Returns the text edit linked with this find widget. :return <QWebView> """ return self._webView
class XKeyValueDialog(QDialog): def __init__( self, parent = None ): super(XKeyValueDialog, self).__init__(parent) # create the interface self._keyEdit = XLineEdit(self) self._keyEdit.setMaximumWidth(80) self._keyEdit.setHint( 'set key' ) self._valueEdit = XLineEdit(self) self._valueEdit.setHint( 'set value' ) hbox = QHBoxLayout() hbox.addWidget(self._keyEdit) hbox.addWidget(self._valueEdit) opts = QDialogButtonBox.Ok | QDialogButtonBox.Cancel buttons = QDialogButtonBox( opts, Qt.Horizontal, self ) vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(buttons) # update the look and size self.setLayout(vbox) self.setWindowTitle('Edit Pair') self.setMinimumWidth(350) self.adjustSize() self.setFixedHeight(self.height()) # create connections buttons.accepted.connect( self.accept ) buttons.rejected.connect( self.reject ) def key( self ): """ Returns the current value of the current pair's key. :return <str> """ return nativestring(self._keyEdit.text()) def setKey( self, key ): """ Sets the current value of the current pair's key. :param key | <str> """ self._keyEdit.setText(key) def setValue( self, value ): """ Sets the current value of the current pair's value. :param value | <str> """ self._valueEdit.setText(value) def value( self ): """ Returns the current value of the current pair's value. :return <str> """ return nativestring(self._valueEdit.text()) @staticmethod def edit( key = '', value = '', parent = None ): """ Prompts the user to edit the inputed key/value pairing. :param key | <str> value | <str> parent | <QWidget> :return (<bool> accepted, <str> key, <str> value) """ dlg = XKeyValueDialog(parent) dlg.setKey(key) dlg.setValue(value) if ( dlg.exec_() ): return (True, dlg.key(), dlg.value()) return (False, '', '')
class XLocationWidget(QWidget): locationChanged = qt.Signal(str) locationEdited = qt.Signal() def __init__(self, parent): super(XLocationWidget, self).__init__(parent) # define the interface self._locationEdit = XLineEdit(self) self._locationButton = QToolButton(self) self._urlTemplate = 'http://maps.google.com/maps?%(params)s' self._urlQueryKey = 'q' self._locationButton.setAutoRaise(True) self._locationButton.setIcon(QIcon(resources.find('img/map.png'))) self._locationEdit.setHint('no location set') layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self._locationEdit) layout.addWidget(self._locationButton) self.setLayout(layout) # create connections self._locationEdit.textChanged.connect(self.locationChanged) self._locationEdit.textEdited.connect(self.locationEdited) self._locationButton.clicked.connect(self.browseMaps) def blockSignals(self, state): """ Blocks the signals for this widget and its sub-parts. :param state | <bool> """ super(XLocationWidget, self).blockSignals(state) self._locationEdit.blockSignals(state) self._locationButton.blockSignals(state) def browseMaps(self): """ Brings up a web browser with the address in a Google map. """ url = self.urlTemplate() params = urllib.urlencode({self.urlQueryKey(): self.location()}) url = url % {'params': params} webbrowser.open(url) def hint(self): """ Returns the hint associated with this widget. :return <str> """ return self._locationEdit.hint() def lineEdit(self): """ Returns the line edit linked with this widget. :return <XLineEdit> """ return self._locationEdit def location(self): """ Returns the current location from the edit. :return <str> """ return str(self._locationEdit.text()) @qt.Slot(str) def setHint(self, hint): """ Sets the hint associated with this widget. :param hint | <str> """ self._locationEdit.setHint(hint) @qt.Slot(str) def setLocation(self, location): """ Sets the location for this widget to the inputed location. :param location | <str> """ self._locationEdit.setText(str(location)) def setUrlQueryKey(self, key): """ Sets the key for the URL to the inputed key. :param key | <str> """ self._urlQueryKey = str(key) def setUrlTemplate(self, templ): """ Sets the URL path template that will be used when looking up locations on the web. :param templ | <str> """ self._urlQueryTemplate = str(templ) def urlQueryKey(self): """ Returns the query key that will be used for this location. :return <str> """ return self._urlQueryKey def urlTemplate(self): """ Returns the url template that will be used when mapping this location. :return <str> """ return self._urlTemplate x_hint = qt.Property(str, hint, setHint) x_location = qt.Property(str, location, setLocation) x_urlQueryKey = qt.Property(str, urlQueryKey, setUrlQueryKey) x_urlTemplate = qt.Property(str, urlTemplate, setUrlTemplate)
class XFilepathEdit(QWidget): """ The XFilepathEdit class provides a common interface to prompt the user to select a filepath from the filesystem. It can be configured to load directories, point to a save file path location, or to an open file path location. It can also be setup to color changed based on the validity of the existance of the filepath. == Example == |>>> from projexui.widgets.xfilepathedit import XFilepathEdit |>>> import projexui | |>>> # create the edit |>>> edit = projexui.testWidget(XFilepathEdit) | |>>> # set the filepath |>>> edit.setFilepath('/path/to/file') | |>>> # prompt the user to select the filepath |>>> edit.pickFilepath() | |>>> # enable the coloring validation |>>> edit.setValidated(True) """ __designer_icon__ = projexui.resources.find('img/file.png') Mode = enum('OpenFile', 'SaveFile', 'Path', 'OpenFiles') filepathChanged = qt.Signal(str) def __init__(self, parent=None): super(XFilepathEdit, self).__init__(parent) # define custom properties self._validated = False self._validForeground = QColor(0, 120, 0) self._validBackground = QColor(0, 120, 0, 100) self._invalidForeground = QColor(255, 0, 0) self._invalidBackground = QColor(255, 0, 0, 100) self._normalizePath = False self._filepathMode = XFilepathEdit.Mode.OpenFile self._filepathEdit = XLineEdit(self) self._filepathButton = QToolButton(self) self._filepathTypes = 'All Files (*.*)' # set default properties ico = projexui.resources.find('img/folder.png') self._filepathEdit.setReadOnly(False) self._filepathButton.setText('...') self._filepathButton.setFixedSize(25, 23) self._filepathButton.setAutoRaise(True) self._filepathButton.setIcon(QIcon(ico)) self._filepathEdit.setContextMenuPolicy(Qt.CustomContextMenu) self.setWindowTitle('Load File') self.setAcceptDrops(True) # define the layout layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self._filepathEdit) layout.addWidget(self._filepathButton) self.setLayout(layout) # create connections self._filepathEdit.installEventFilter(self) self._filepathButton.clicked.connect(self.pickFilepath) self._filepathEdit.textChanged.connect(self.emitFilepathChanged) self._filepathEdit.textChanged.connect(self.validateFilepath) self._filepathEdit.customContextMenuRequested.connect(self.showMenu) def autoRaise(self): """ Returns whether or not the tool button will auto raise. :return <bool> """ return self._filepathButton.autoRaise() @qt.Slot() def clearFilepath(self): """ Clears the filepath contents for this path. """ self.setFilepath('') @qt.Slot() def copyFilepath(self): """ Copies the current filepath contents to the current clipboard. """ clipboard = QApplication.instance().clipboard() clipboard.setText(self.filepath()) clipboard.setText(self.filepath(), clipboard.Selection) def dragEnterEvent(self, event): """ Processes drag enter events. :param event | <QDragEvent> """ if (event.mimeData().hasUrls()): event.acceptProposedAction() def dragMoveEvent(self, event): """ Processes drag move events. :param event | <QDragEvent> """ if (event.mimeData().hasUrls()): event.acceptProposedAction() def dropEvent(self, event): """ Processes drop event. :param event | <QDropEvent> """ if (event.mimeData().hasUrls()): url = event.mimeData().urls()[0] filepath = url.toLocalFile() if (filepath): self.setFilepath(filepath) def emitFilepathChanged(self): """ Emits the filepathChanged signal for this widget if the signals are \ not being blocked. """ if (not self.signalsBlocked()): self.filepathChanged.emit(self.filepath()) def eventFilter(self, object, event): """ Overloads the eventFilter to look for click events on the line edit. :param object | <QObject> event | <QEvent> """ if ( object == self._filepathEdit and \ self._filepathEdit.isReadOnly() and \ event.type() == event.MouseButtonPress and \ event.button() == Qt.LeftButton ): self.pickFilepath() return False def filepath(self, validated=False): """ Returns the filepath for this widget. If the validated flag is set \ then this method will only return if the file or folder actually \ exists for this path. In the case of a SaveFile, only the base folder \ needs to exist on the system, in other modes the actual filepath must \ exist. If not validated, the text will return whatever is currently \ entered. :return <str> """ paths = self.filepaths() if not paths: return '' if not validated or self.isValid(): return paths[0] return '' def filepaths(self): """ Returns a list of the filepaths for this edit. :return [<str>, ..] """ return str(self._filepathEdit.text()).split(os.path.pathsep) def filepathMode(self): """ Returns the filepath mode for this widget. :return <XFilepathEdit.Mode> """ return self._filepathMode def filepathModeText(self): """ Returns the text representation for this filepath mode. :return <str> """ return XFilepathEdit.Mode[self._filepathMode] def filepathTypes(self): """ Returns the filepath types that will be used for this widget. :return <str> """ return self._filepathTypes def hint(self): """ Returns the hint for this filepath. :return <str> """ return self._filepathEdit.hint() def icon(self): """ Returns the icon that is used for this filepath widget. :return <QIcon> """ return self._filepathButton.icon() def invalidBackground(self): """ Returns the invalid background color for this widget. :return <QColor> """ return self._invalidBackground def invalidForeground(self): """ Returns the invalid foreground color for this widget. :return <QColor> """ return self._invalidForeground def isValid(self): """ Returns whether or not the filepath exists on the system. \ In the case of a SaveFile, only the base folder \ needs to exist on the system, in other modes the actual filepath must \ exist. :return <bool> """ check = str(self._filepathEdit.text()).split(os.path.pathsep)[0] if (self.filepathMode() == XFilepathEdit.Mode.SaveFile): check = os.path.dirname(check) return os.path.exists(check) def isValidated(self): """ Set whether or not to validate the filepath as the user is working \ with it. :return <bool> """ return self._validated def isReadOnly(self): """ Returns if the widget is read only for text editing or not. :return <bool> """ return self._filepathEdit.isReadOnly() def normalizePath(self): """ Returns whether or not the path should be normalized for the current operating system. When off, it will be defaulted to forward slashes (/). :return <bool> """ return self._normalizePath def pickFilepath(self): """ Prompts the user to select a filepath from the system based on the \ current filepath mode. """ mode = self.filepathMode() filepath = '' filepaths = [] curr_dir = str(self._filepathEdit.text()) if (not curr_dir): curr_dir = QDir.currentPath() if mode == XFilepathEdit.Mode.SaveFile: filepath = QFileDialog.getSaveFileName(self, self.windowTitle(), curr_dir, self.filepathTypes()) elif mode == XFilepathEdit.Mode.OpenFile: filepath = QFileDialog.getOpenFileName(self, self.windowTitle(), curr_dir, self.filepathTypes()) elif mode == XFilepathEdit.Mode.OpenFiles: filepaths = QFileDialog.getOpenFileNames(self, self.windowTitle(), curr_dir, self.filepathTypes()) else: filepath = QFileDialog.getExistingDirectory( self, self.windowTitle(), curr_dir) if filepath: if type(filepath) == tuple: filepath = filepath[0] self.setFilepath(str(filepath)) elif filepaths: self.setFilepaths(map(str, filepaths)) def setAutoRaise(self, state): """ Sets whether or not the tool button will auto raise. :param state | <bool> """ self._filepathButton.setAutoRaise(state) @qt.Slot(int) def setFilepathMode(self, mode): """ Sets the filepath mode for this widget to the inputed mode. :param mode | <XFilepathEdit.Mode> """ self._filepathMode = mode @qt.Slot(str) def setFilepathModeText(self, text): """ Sets the filepath mode for this widget based on the inputed text. :param text | <str> :return <bool> | success """ try: self.setFilepathMode(XFilepathEdit.Mode[str(text)]) return True except KeyError: return False @qt.Slot(str) def setFilepathTypes(self, filepathTypes): """ Sets the filepath type string that will be used when looking up \ filepaths. :param filepathTypes | <str> """ self._filepathTypes = filepathTypes @qt.Slot(str) def setFilepath(self, filepath): """ Sets the filepath text for this widget to the inputed path. :param filepath | <str> """ if self.normalizePath(): filepath = os.path.normpath(str(filepath)) else: filepath = os.path.normpath(str(filepath)).replace('\\', '/') self._filepathEdit.setText(filepath) def setFilepaths(self, filepaths): """ Sets the list of the filepaths for this widget to the inputed paths. :param filepaths | [<str>, ..] """ self.setFilepath(os.path.pathsep.join(filepaths)) def setHint(self, hint): """ Sets the hint for this filepath. :param hint | <str> """ if self.normalizePath(): filepath = os.path.normpath(str(hint)) else: filepath = os.path.normpath(str(hint)).replace('\\', '/') self._filepathEdit.setHint(hint) def setIcon(self, icon): """ Sets the icon that will be used for this widget's tool button. :param icon | <QIcon> || <str> """ self._filepathButton.setIcon(QIcon(icon)) def setInvalidBackground(self, bg): """ Sets the invalid background color for this widget to the inputed widget. :param bg | <QColor> """ self._invalidBackground = QColor(bg) def setInvalidForeground(self, fg): """ Sets the invalid foreground color for this widget to the inputed widget. :param fg | <QColor> """ self._invalidForeground = QColor(fg) def setNormalizePath(self, state): """ Sets whether or not the path should be normalized for the current operating system. When off, it will be defaulted to forward slashes (/). :param state | <bool> """ self._normalizePath = state @qt.Slot(bool) def setReadOnly(self, state): """ Sets whether or not this filepath widget is readonly in the text edit. :param state | <bool> """ self._filepathEdit.setReadOnly(state) @qt.Slot(bool) def setValidated(self, state): """ Set whether or not to validate the path as the user edits it. :param state | <bool> """ self._validated = state palette = self.palette() # reset the palette to default, revalidate self._filepathEdit.setPalette(palette) self.validate() def setValidBackground(self, bg): """ Sets the valid background color for this widget to the inputed color. :param bg | <QColor> """ self._validBackground = QColor(bg) def setValidForeground(self, fg): """ Sets the valid foreground color for this widget to the inputed color. :param fg | <QColor> """ self._validForeground = QColor(fg) def showMenu(self, pos): """ Popups a menu for this widget. """ menu = QMenu(self) menu.setAttribute(Qt.WA_DeleteOnClose) menu.addAction('Clear').triggered.connect(self.clearFilepath) menu.addSeparator() menu.addAction('Copy Filepath').triggered.connect(self.copyFilepath) menu.exec_(self.mapToGlobal(pos)) def validBackground(self): """ Returns the valid background color for this widget. :return <QColor> """ return self._validBackground def validForeground(self): """ Returns the valid foreground color for this widget. :return <QColor> """ return self._validForeground def validateFilepath(self): """ Alters the color scheme based on the validation settings. """ if (not self.isValidated()): return valid = self.isValid() if (not valid): fg = self.invalidForeground() bg = self.invalidBackground() else: fg = self.validForeground() bg = self.validBackground() palette = self.palette() palette.setColor(palette.Base, bg) palette.setColor(palette.Text, fg) self._filepathEdit.setPalette(palette) # map Qt properties x_autoRaise = qt.Property(bool, autoRaise, setAutoRaise) x_filepathTypes = qt.Property(str, filepathTypes, setFilepathTypes) x_filepath = qt.Property(str, filepath, setFilepath) x_readOnly = qt.Property(bool, isReadOnly, setReadOnly) x_validated = qt.Property(bool, isValidated, setValidated) x_hint = qt.Property(str, hint, setHint) x_icon = qt.Property('QIcon', icon, setIcon) x_normalizePath = qt.Property(bool, normalizePath, setNormalizePath) x_invalidForeground = qt.Property('QColor', invalidForeground, setInvalidForeground) x_invalidBackground = qt.Property('QColor', invalidBackground, setInvalidBackground) x_validForeground = qt.Property('QColor', validForeground, setValidForeground) x_validBackground = qt.Property('QColor', validBackground, setValidBackground) x_filepathModeText = qt.Property(str, filepathModeText, setFilepathModeText)
class XLocationWidget(QWidget): locationChanged = Signal(str) locationEdited = Signal() def __init__( self, parent ): super(XLocationWidget, self).__init__(parent) # define the interface self._locationEdit = XLineEdit(self) self._locationButton = QToolButton(self) self._urlTemplate = 'http://maps.google.com/maps?%(params)s' self._urlQueryKey = 'q' self._locationButton.setAutoRaise(True) self._locationButton.setIcon(QIcon(resources.find('img/map.png'))) self._locationEdit.setHint('no location set') layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self._locationEdit) layout.addWidget(self._locationButton) self.setLayout(layout) # create connections self._locationEdit.textChanged.connect(self.locationChanged) self._locationEdit.textEdited.connect(self.locationEdited) self._locationButton.clicked.connect(self.browseMaps) def blockSignals( self, state ): """ Blocks the signals for this widget and its sub-parts. :param state | <bool> """ super(XLocationWidget, self).blockSignals(state) self._locationEdit.blockSignals(state) self._locationButton.blockSignals(state) def browseMaps( self ): """ Brings up a web browser with the address in a Google map. """ url = self.urlTemplate() params = urllib.urlencode({self.urlQueryKey(): self.location()}) url = url % {'params': params} webbrowser.open(url) def hint( self ): """ Returns the hint associated with this widget. :return <str> """ return self._locationEdit.hint() def lineEdit( self ): """ Returns the line edit linked with this widget. :return <XLineEdit> """ return self._locationEdit def location( self ): """ Returns the current location from the edit. :return <str> """ return nativestring(self._locationEdit.text()) @Slot(str) def setHint( self, hint ): """ Sets the hint associated with this widget. :param hint | <str> """ self._locationEdit.setHint(hint) @Slot(str) def setLocation( self, location ): """ Sets the location for this widget to the inputed location. :param location | <str> """ self._locationEdit.setText(nativestring(location)) def setUrlQueryKey( self, key ): """ Sets the key for the URL to the inputed key. :param key | <str> """ self._urlQueryKey = nativestring(key) def setUrlTemplate( self, templ ): """ Sets the URL path template that will be used when looking up locations on the web. :param templ | <str> """ self._urlQueryTemplate = nativestring(templ) def urlQueryKey( self ): """ Returns the query key that will be used for this location. :return <str> """ return self._urlQueryKey def urlTemplate( self ): """ Returns the url template that will be used when mapping this location. :return <str> """ return self._urlTemplate x_hint = Property(str, hint, setHint) x_location = Property(str, location, setLocation) x_urlQueryKey = Property(str, urlQueryKey, setUrlQueryKey) x_urlTemplate = Property(str, urlTemplate, setUrlTemplate)
class XFilepathEdit(QWidget): """ The XFilepathEdit class provides a common interface to prompt the user to select a filepath from the filesystem. It can be configured to load directories, point to a save file path location, or to an open file path location. It can also be setup to color changed based on the validity of the existance of the filepath. == Example == |>>> from projexui.widgets.xfilepathedit import XFilepathEdit |>>> import projexui | |>>> # create the edit |>>> edit = projexui.testWidget(XFilepathEdit) | |>>> # set the filepath |>>> edit.setFilepath('/path/to/file') | |>>> # prompt the user to select the filepath |>>> edit.pickFilepath() | |>>> # enable the coloring validation |>>> edit.setValidated(True) """ __designer_icon__ = projexui.resources.find('img/file.png') Mode = enum('OpenFile', 'SaveFile', 'Path', 'OpenFiles') filepathChanged = qt.Signal(str) def __init__( self, parent = None ): super(XFilepathEdit, self).__init__( parent ) # define custom properties self._validated = False self._validForeground = QColor(0, 120, 0) self._validBackground = QColor(0, 120, 0, 100) self._invalidForeground = QColor(255, 0, 0) self._invalidBackground = QColor(255, 0, 0, 100) self._normalizePath = False self._filepathMode = XFilepathEdit.Mode.OpenFile self._filepathEdit = XLineEdit(self) self._filepathButton = QToolButton(self) self._filepathTypes = 'All Files (*.*)' # set default properties ico = projexui.resources.find('img/folder.png') self._filepathEdit.setReadOnly(False) self._filepathButton.setText('...') self._filepathButton.setFixedSize(25, 23) self._filepathButton.setAutoRaise(True) self._filepathButton.setIcon(QIcon(ico)) self._filepathEdit.setContextMenuPolicy(Qt.CustomContextMenu) self.setWindowTitle('Load File') self.setAcceptDrops(True) # define the layout layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self._filepathEdit) layout.addWidget(self._filepathButton) self.setLayout(layout) # create connections self._filepathEdit.installEventFilter(self) self._filepathButton.clicked.connect( self.pickFilepath ) self._filepathEdit.textChanged.connect( self.emitFilepathChanged ) self._filepathEdit.textChanged.connect( self.validateFilepath ) self._filepathEdit.customContextMenuRequested.connect( self.showMenu ) def autoRaise( self ): """ Returns whether or not the tool button will auto raise. :return <bool> """ return self._filepathButton.autoRaise() @qt.Slot() def clearFilepath( self ): """ Clears the filepath contents for this path. """ self.setFilepath('') @qt.Slot() def copyFilepath( self ): """ Copies the current filepath contents to the current clipboard. """ clipboard = QApplication.instance().clipboard() clipboard.setText(self.filepath()) clipboard.setText(self.filepath(), clipboard.Selection) def dragEnterEvent( self, event ): """ Processes drag enter events. :param event | <QDragEvent> """ if ( event.mimeData().hasUrls() ): event.acceptProposedAction() def dragMoveEvent( self, event ): """ Processes drag move events. :param event | <QDragEvent> """ if ( event.mimeData().hasUrls() ): event.acceptProposedAction() def dropEvent( self, event ): """ Processes drop event. :param event | <QDropEvent> """ if ( event.mimeData().hasUrls() ): url = event.mimeData().urls()[0] filepath = url.toLocalFile() if ( filepath ): self.setFilepath(filepath) def emitFilepathChanged( self ): """ Emits the filepathChanged signal for this widget if the signals are \ not being blocked. """ if ( not self.signalsBlocked() ): self.filepathChanged.emit(self.filepath()) def eventFilter( self, object, event ): """ Overloads the eventFilter to look for click events on the line edit. :param object | <QObject> event | <QEvent> """ if ( object == self._filepathEdit and \ self._filepathEdit.isReadOnly() and \ event.type() == event.MouseButtonPress and \ event.button() == Qt.LeftButton ): self.pickFilepath() return False def filepath( self, validated = False ): """ Returns the filepath for this widget. If the validated flag is set \ then this method will only return if the file or folder actually \ exists for this path. In the case of a SaveFile, only the base folder \ needs to exist on the system, in other modes the actual filepath must \ exist. If not validated, the text will return whatever is currently \ entered. :return <str> """ paths = self.filepaths() if not paths: return '' if not validated or self.isValid(): return paths[0] return '' def filepaths(self): """ Returns a list of the filepaths for this edit. :return [<str>, ..] """ return str(self._filepathEdit.text()).split(os.path.pathsep) def filepathMode( self ): """ Returns the filepath mode for this widget. :return <XFilepathEdit.Mode> """ return self._filepathMode def filepathModeText( self ): """ Returns the text representation for this filepath mode. :return <str> """ return XFilepathEdit.Mode[self._filepathMode] def filepathTypes( self ): """ Returns the filepath types that will be used for this widget. :return <str> """ return self._filepathTypes def hint( self ): """ Returns the hint for this filepath. :return <str> """ return self._filepathEdit.hint() def icon( self ): """ Returns the icon that is used for this filepath widget. :return <QIcon> """ return self._filepathButton.icon() def invalidBackground( self ): """ Returns the invalid background color for this widget. :return <QColor> """ return self._invalidBackground def invalidForeground( self ): """ Returns the invalid foreground color for this widget. :return <QColor> """ return self._invalidForeground def isValid( self ): """ Returns whether or not the filepath exists on the system. \ In the case of a SaveFile, only the base folder \ needs to exist on the system, in other modes the actual filepath must \ exist. :return <bool> """ check = str(self._filepathEdit.text()).split(os.path.pathsep)[0] if ( self.filepathMode() == XFilepathEdit.Mode.SaveFile ): check = os.path.dirname(check) return os.path.exists(check) def isValidated( self ): """ Set whether or not to validate the filepath as the user is working \ with it. :return <bool> """ return self._validated def isReadOnly( self ): """ Returns if the widget is read only for text editing or not. :return <bool> """ return self._filepathEdit.isReadOnly() def normalizePath(self): """ Returns whether or not the path should be normalized for the current operating system. When off, it will be defaulted to forward slashes (/). :return <bool> """ return self._normalizePath def pickFilepath( self ): """ Prompts the user to select a filepath from the system based on the \ current filepath mode. """ mode = self.filepathMode() filepath = '' filepaths = [] curr_dir = str(self._filepathEdit.text()) if ( not curr_dir ): curr_dir = QDir.currentPath() if mode == XFilepathEdit.Mode.SaveFile: filepath = QFileDialog.getSaveFileName( self, self.windowTitle(), curr_dir, self.filepathTypes() ) elif mode == XFilepathEdit.Mode.OpenFile: filepath = QFileDialog.getOpenFileName( self, self.windowTitle(), curr_dir, self.filepathTypes() ) elif mode == XFilepathEdit.Mode.OpenFiles: filepaths = QFileDialog.getOpenFileNames( self, self.windowTitle(), curr_dir, self.filepathTypes() ) else: filepath = QFileDialog.getExistingDirectory( self, self.windowTitle(), curr_dir ) if filepath: if type(filepath) == tuple: filepath = filepath[0] self.setFilepath(str(filepath)) elif filepaths: self.setFilepaths(map(str, filepaths)) def setAutoRaise( self, state ): """ Sets whether or not the tool button will auto raise. :param state | <bool> """ self._filepathButton.setAutoRaise(state) @qt.Slot(int) def setFilepathMode( self, mode ): """ Sets the filepath mode for this widget to the inputed mode. :param mode | <XFilepathEdit.Mode> """ self._filepathMode = mode @qt.Slot(str) def setFilepathModeText( self, text ): """ Sets the filepath mode for this widget based on the inputed text. :param text | <str> :return <bool> | success """ try: self.setFilepathMode(XFilepathEdit.Mode[str(text)]) return True except KeyError: return False @qt.Slot(str) def setFilepathTypes( self, filepathTypes ): """ Sets the filepath type string that will be used when looking up \ filepaths. :param filepathTypes | <str> """ self._filepathTypes = filepathTypes @qt.Slot(str) def setFilepath(self, filepath): """ Sets the filepath text for this widget to the inputed path. :param filepath | <str> """ if self.normalizePath(): filepath = os.path.normpath(str(filepath)) else: filepath = os.path.normpath(str(filepath)).replace('\\', '/') self._filepathEdit.setText(filepath) def setFilepaths(self, filepaths): """ Sets the list of the filepaths for this widget to the inputed paths. :param filepaths | [<str>, ..] """ self.setFilepath(os.path.pathsep.join(filepaths)) def setHint(self, hint): """ Sets the hint for this filepath. :param hint | <str> """ if self.normalizePath(): filepath = os.path.normpath(str(hint)) else: filepath = os.path.normpath(str(hint)).replace('\\', '/') self._filepathEdit.setHint(hint) def setIcon( self, icon ): """ Sets the icon that will be used for this widget's tool button. :param icon | <QIcon> || <str> """ self._filepathButton.setIcon(QIcon(icon)) def setInvalidBackground( self, bg ): """ Sets the invalid background color for this widget to the inputed widget. :param bg | <QColor> """ self._invalidBackground = QColor(bg) def setInvalidForeground( self, fg ): """ Sets the invalid foreground color for this widget to the inputed widget. :param fg | <QColor> """ self._invalidForeground = QColor(fg) def setNormalizePath(self, state): """ Sets whether or not the path should be normalized for the current operating system. When off, it will be defaulted to forward slashes (/). :param state | <bool> """ self._normalizePath = state @qt.Slot(bool) def setReadOnly( self, state ): """ Sets whether or not this filepath widget is readonly in the text edit. :param state | <bool> """ self._filepathEdit.setReadOnly(state) @qt.Slot(bool) def setValidated( self, state ): """ Set whether or not to validate the path as the user edits it. :param state | <bool> """ self._validated = state palette = self.palette() # reset the palette to default, revalidate self._filepathEdit.setPalette(palette) self.validate() def setValidBackground( self, bg ): """ Sets the valid background color for this widget to the inputed color. :param bg | <QColor> """ self._validBackground = QColor(bg) def setValidForeground( self, fg ): """ Sets the valid foreground color for this widget to the inputed color. :param fg | <QColor> """ self._validForeground = QColor(fg) def showMenu( self, pos ): """ Popups a menu for this widget. """ menu = QMenu(self) menu.setAttribute(Qt.WA_DeleteOnClose) menu.addAction('Clear').triggered.connect(self.clearFilepath) menu.addSeparator() menu.addAction('Copy Filepath').triggered.connect(self.copyFilepath) menu.exec_(self.mapToGlobal(pos)) def validBackground( self ): """ Returns the valid background color for this widget. :return <QColor> """ return self._validBackground def validForeground( self ): """ Returns the valid foreground color for this widget. :return <QColor> """ return self._validForeground def validateFilepath( self ): """ Alters the color scheme based on the validation settings. """ if ( not self.isValidated() ): return valid = self.isValid() if ( not valid ): fg = self.invalidForeground() bg = self.invalidBackground() else: fg = self.validForeground() bg = self.validBackground() palette = self.palette() palette.setColor(palette.Base, bg) palette.setColor(palette.Text, fg) self._filepathEdit.setPalette(palette) # map Qt properties x_autoRaise = qt.Property(bool, autoRaise, setAutoRaise) x_filepathTypes = qt.Property(str, filepathTypes, setFilepathTypes) x_filepath = qt.Property(str, filepath, setFilepath) x_readOnly = qt.Property(bool, isReadOnly, setReadOnly) x_validated = qt.Property(bool, isValidated, setValidated) x_hint = qt.Property(str, hint, setHint) x_icon = qt.Property('QIcon', icon, setIcon) x_normalizePath = qt.Property(bool, normalizePath, setNormalizePath) x_invalidForeground = qt.Property('QColor', invalidForeground, setInvalidForeground) x_invalidBackground = qt.Property('QColor', invalidBackground, setInvalidBackground) x_validForeground = qt.Property('QColor', validForeground, setValidForeground) x_validBackground = qt.Property('QColor', validBackground, setValidBackground) x_filepathModeText = qt.Property(str, filepathModeText, setFilepathModeText)
class XUrlWidget(QWidget): urlChanged = Signal(str) urlEdited = Signal() def __init__( self, parent ): super(XUrlWidget, self).__init__(parent) # define the interface self._urlEdit = XLineEdit(self) self._urlButton = QToolButton(self) self._urlButton.setAutoRaise(True) self._urlButton.setIcon(QIcon(resources.find('img/web.png'))) self._urlButton.setToolTip('Browse Link') self._urlButton.setFocusPolicy(Qt.NoFocus) self._urlEdit.setHint('http://') layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self._urlEdit) layout.addWidget(self._urlButton) self.setLayout(layout) self.setFocusPolicy(Qt.StrongFocus) # create connections self._urlEdit.textChanged.connect(self.urlChanged) self._urlEdit.textEdited.connect(self.urlEdited) self._urlButton.clicked.connect(self.browse) def blockSignals( self, state ): """ Blocks the signals for this widget and its sub-parts. :param state | <bool> """ super(XUrlWidget, self).blockSignals(state) self._urlEdit.blockSignals(state) self._urlButton.blockSignals(state) def browse( self ): """ Brings up a web browser with the address in a Google map. """ webbrowser.open(self.url()) def hint( self ): """ Returns the hint associated with this widget. :return <str> """ return self._urlEdit.hint() def lineEdit( self ): """ Returns the line edit linked with this widget. :return <XLineEdit> """ return self._urlEdit def setFocus(self): """ Sets the focus for this widget on its line edit. """ self._urlEdit.setFocus() @Slot(str) def setHint( self, hint ): """ Sets the hint associated with this widget. :param hint | <str> """ self._urlEdit.setHint(hint) @Slot(str) def setUrl( self, url ): """ Sets the url for this widget to the inputed url. :param url | <str> """ self._urlEdit.setText(nativestring(url)) def url( self ): """ Returns the current url from the edit. :return <str> """ return nativestring(self._urlEdit.text()) x_hint = Property(str, hint, setHint) x_url = Property(str, url, setUrl)