class XQueryBuilderWidget(QWidget): """ """ saveRequested = Signal() resetRequested = Signal() cancelRequested = Signal() def __init__(self, parent=None): super(XQueryBuilderWidget, self).__init__(parent) # load the user interface projexui.loadUi(__file__, self) self.setMinimumWidth(470) # define custom properties self._rules = {} self._defaultQuery = [] self._completionTerms = [] self._minimumCount = 1 # set default properties self._container = QWidget(self) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) layout.addStretch(1) self._container.setLayout(layout) self.uiQueryAREA.setWidget(self._container) # create connections self.uiResetBTN.clicked.connect(self.emitResetRequested) self.uiSaveBTN.clicked.connect(self.emitSaveRequested) self.uiCancelBTN.clicked.connect(self.emitCancelRequested) self.resetRequested.connect(self.reset) def addLineWidget(self, query=None): """ Adds a new line widget to the system with the given values. :param query | (<str> term, <str> operator, <str> vlaue) || None """ widget = XQueryLineWidget(self) widget.setTerms(sorted(self._rules.keys())) widget.setQuery(query) index = self._container.layout().count() - 1 self._container.layout().insertWidget(index, widget) widget.addRequested.connect(self.addLineWidget) widget.removeRequested.connect(self.removeLineWidget) # update the remove enabled options for these widgets self.updateRemoveEnabled() def addRule(self, rule): """ Adds a rule to the system. :param rule | <XQueryRule> """ self._rules[rule.term()] = rule self.updateRules() def clear(self): """ Clears out all the widgets from the system. """ for lineWidget in self.lineWidgets(): lineWidget.setParent(None) lineWidget.deleteLater() def completionTerms(self): """ Returns the list of terms that will be used as a global override for completion terms when the query rule generates a QLineEdit instance. :return [<str>, ..] """ return self._completionTerms def count(self): """ Returns the count of the line widgets in the system. :return <int> """ return len(self.lineWidgets()) def currentQuery(self): """ Returns the current query string for this widget. :return [(<str> term, <str> operator, <str> value), ..] """ widgets = self.lineWidgets() output = [] for widget in widgets: output.append(widget.query()) return output def defaultQuery(self): """ Returns the default query for the system. :return [(<str> term, <str> operator, <str> value), ..] """ return self._defaultQuery def keyPressEvent(self, event): """ Emits the save requested signal for this builder for when the enter or return press is clicked. :param event | <QKeyEvent> """ if (event.key() in (Qt.Key_Enter, Qt.Key_Return)): self.emitSaveRequested() super(XQueryBuilderWidget, self).keyPressEvent(event) def emitCancelRequested(self): """ Emits the cancel requested signal. """ if (not self.signalsBlocked()): self.cancelRequested.emit() def emitResetRequested(self): """ Emits the reste requested signal. """ if (not self.signalsBlocked()): self.resetRequested.emit() def emitSaveRequested(self): """ Emits the save requested signal. """ if (not self.signalsBlocked()): self.saveRequested.emit() def findRule(self, term): """ Looks up a rule by the inputed term. :param term | <str> :return <XQueryRule> || None """ return self._rules.get(nativestring(term)) def removeLineWidget(self, widget): """ Removes the line widget from the query. :param widget | <XQueryLineWidget> """ widget.setParent(None) widget.deleteLater() self.updateRemoveEnabled() def minimumCount(self): """ Defines the minimum number of query widgets that are allowed. :return <int> """ return self._minimumCount def lineWidgets(self): """ Returns a list of line widgets for this system. :return [<XQueryLineWidget>, ..] """ return self.findChildren(XQueryLineWidget) def reset(self): """ Resets the system to the default query. """ self.setCurrentQuery(self.defaultQuery()) def setCompletionTerms(self, terms): """ Sets the list of terms that will be used as a global override for completion terms when the query rule generates a QLineEdit instance. :param terms | [<str>, ..] """ self._completionTerms = terms def setCurrentQuery(self, query): """ Sets the query for this system to the inputed query. :param query | [(<str> term, <str> operator, <str> value), ..] """ self.clear() for entry in query: self.addLineWidget(entry) # make sure we have the minimum number of widgets for i in range(self.minimumCount() - len(query)): self.addLineWidget() def setDefaultQuery(self, query): """ Sets the default query that will be used when the user clicks on the \ reset button or the reset method is called. :param query | [(<str> term, <str> operator, <str> value), ..] """ self._defaultQuery = query[:] def setMinimumCount(self, count): """ Sets the minimum number of line widgets that are allowed at any \ given time. :param count | <int> """ self._minimumCount = count def setRules(self, rules): """ Sets all the rules for this builder. :param rules | [<XQueryRule>, ..] """ if (type(rules) in (list, tuple)): self._rules = dict([(x.term(), x) for x in rules]) self.updateRules() return True elif (type(rules) == dict): self._rules = rules.copy() self.updateRules() return True else: return False def setTerms(self, terms): """ Sets a simple rule list by accepting a list of strings for terms. \ This is a convenience method for the setRules method. :param rules | [<str> term, ..] """ return self.setRules([XQueryRule(term=term) for term in terms]) def updateRemoveEnabled(self): """ Updates the remove enabled baesd on the current number of line widgets. """ lineWidgets = self.lineWidgets() count = len(lineWidgets) state = self.minimumCount() < count for widget in lineWidgets: widget.setRemoveEnabled(state) def updateRules(self): """ Updates the query line items to match the latest rule options. """ terms = sorted(self._rules.keys()) for child in self.lineWidgets(): child.setTerms(terms)
class XOrbQueryContainer(QWidget): """ """ entriesUpdated = Signal() enterCompoundRequested = Signal(object, object) exitCompoundRequested = Signal() def __init__(self, parent=None): super(XOrbQueryContainer, self).__init__(parent) # load the user interface projexui.loadUi(__file__, self) # define custom properties self._queryWidget = parent self._entryWidget = QWidget(self) self._currentJoiner = QueryCompound.Op.And layout = QVBoxLayout() layout.addStretch(1) layout.setSpacing(3) self._entryWidget.setLayout(layout) self.uiQueryAREA.setWidget(self._entryWidget) # set default properties self.setContextMenuPolicy(Qt.CustomContextMenu) # create connections (use old-style syntax or PySide errors) self.connect(self.uiBackBTN, SIGNAL('clicked()'), self.exitCompound) self.entriesUpdated.connect(self.refreshEntries) def addEntry(self, query=None, entry=None): if query is None: query = Query() layout = self._entryWidget.layout() index = layout.count() - 1 if entry: index = layout.indexOf(entry) + 1 widget = XOrbQueryEntryWidget(self, self.tableType()) layout.insertWidget(index, widget) widget.setQuery(query) if not self.signalsBlocked(): self.entriesUpdated.emit() return widget def checkedEntries(self): """ Returns the widgets that are checked for this widget. :return [<XOrbQueryEntryWidget>, ..] """ return [entry for entry in self.entries() if entry.isChecked()] def clear(self): """ Clears out the widgets for this query builder. """ layout = self._entryWidget.layout() for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() widget.close() def createCompoundFromChecked(self): """ Creates a new compound query from the checked entry list. :return <orb.QueryCompound> """ checked_entries = self.checkedEntries() if len(checked_entries) <= 1: return QueryCompound() self.setUpdatesEnabled(False) joiner = self.currentJoiner() query = Query() for entry in checked_entries: if joiner == QueryCompound.Op.And: query &= entry.query() else: query |= entry.query() # clear out the existing containers first = checked_entries[0] first.setQuery(query) first.setChecked(False) layout = self._entryWidget.layout() for i in range(len(checked_entries) - 1, 0, -1): w = checked_entries[i] layout.takeAt(layout.indexOf(w)) w.close() self.refreshEntries() self.setUpdatesEnabled(True) if not self.signalsBlocked(): self.enterCompound(first, query) def currentJoiner(self): return self._currentJoiner def enterCompound(self, entry, query): # enter an existing compound if QueryCompound.typecheck(query): self.enterCompoundRequested.emit(entry, query) # create a new compound from the checked entries else: self.createCompoundFromChecked() def entries(self): """ Returns the entry widgets for this widget. :return [<XOrbQueryEntryWidget>, ..] """ layout = self._entryWidget.layout() output = [] for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() if not isinstance(widget, XOrbQueryEntryWidget): continue output.append(widget) return output def exitCompound(self): self.exitCompoundRequested.emit() def isNull(self): """ Returns whether or not any widgets have been defined for this container yet. :return <bool> """ return self._entryWidget.layout().count() <= 1 def moveDown(self, entry): """ Moves the current query down one entry. """ if not entry: return entries = self.entries() next = entries[entries.index(entry) + 1] entry_q = entry.query() next_q = next.query() next.setQuery(entry_q) entry.setQuery(next_q) def moveUp(self, entry): """ Moves the current query down up one entry. """ if not entry: return entries = self.entries() next = entries[entries.index(entry) - 1] entry_q = entry.query() next_q = next.query() next.setQuery(entry_q) entry.setQuery(next_q) def pluginFactory(self): """ Returns the plugin factory for this widget. You can define a custom factory for handling specific columns or column types based on your table type. :return <XOrbQueryPluginFactory> """ return self._queryWidget.pluginFactory() def query(self): """ Returns the query that is defined by this current panel. :return <orb.Query> """ joiner = self.currentJoiner() query = Query() for entry in self.entries(): if joiner == QueryCompound.Op.And: query &= entry.query() else: query |= entry.query() query.setName(self.uiNameTXT.text()) return query def queryWidget(self): """ Returns the query widget linked with this container. :return <XOrbQueryWidget> """ return self._queryWidget def removeEntry(self, entry): if not entry: return layout = self._entryWidget.layout() if layout.count() == 2: entry.setQuery(Query()) return layout.takeAt(layout.indexOf(entry)) entry.close() if not self.signalsBlocked(): self.entriesUpdated.emit() def refreshEntries(self): layout = self._entryWidget.layout() for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() widget.setFirst(i == 0) widget.setLast(i == (layout.count() - 2)) def setCurrentJoiner(self, joiner): self._currentJoiner = joiner layout = self._entryWidget.layout() for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() widget.setJoiner(joiner) def setQuery(self, query): """ Sets the query for this wigdet to the inputed query instance. :param query | <orb.Query> || <orb.QueryCompound> """ if not self.isNull() and hash(query) == hash(self.query()): return # add entries table = self.tableType() self.setUpdatesEnabled(False) self.blockSignals(True) self.clear() if query is None or table is None: self.setEnabled(False) self.setUpdatesEnabled(True) self.blockSignals(False) return else: self.setEnabled(True) # load the queries for this item if QueryCompound.typecheck(query): queries = query.queries() self.setCurrentJoiner(query.operatorType()) else: queries = [query] self.uiNameTXT.setText(query.name()) layout = self._entryWidget.layout() for index, query in enumerate(queries): widget = self.addEntry(query) widget.setFirst(index == 0) widget.setLast(index == (len(queries) - 1)) widget.setJoiner(self.currentJoiner()) self.setUpdatesEnabled(True) self.blockSignals(False) def setShowBack(self, state): # check to see if we're working on the current query self.uiBackBTN.setVisible(state) self.uiNameTXT.setVisible(state) def tableType(self): """ Returns the table type instance for this widget. :return <subclass of orb.Table> """ return self._queryWidget.tableType()
class XOrbQueryContainer(QWidget): """ """ entriesUpdated = Signal() enterCompoundRequested = Signal(object, object) exitCompoundRequested = Signal() def __init__( self, parent = None ): super(XOrbQueryContainer, self).__init__( parent ) # load the user interface projexui.loadUi(__file__, self) # define custom properties self._queryWidget = parent self._entryWidget = QWidget(self) self._currentJoiner = QueryCompound.Op.And layout = QVBoxLayout() layout.addStretch(1) layout.setSpacing(3) self._entryWidget.setLayout(layout) self.uiQueryAREA.setWidget(self._entryWidget) # set default properties self.setContextMenuPolicy(Qt.CustomContextMenu) # create connections (use old-style syntax or PySide errors) self.connect(self.uiBackBTN, SIGNAL('clicked()'), self.exitCompound) self.entriesUpdated.connect(self.refreshEntries) def addEntry(self, query=None, entry=None): if query is None: query = Query() layout = self._entryWidget.layout() index = layout.count() - 1 if entry: index = layout.indexOf(entry) + 1 widget = XOrbQueryEntryWidget(self, self.tableType()) layout.insertWidget(index, widget) widget.setQuery(query) if not self.signalsBlocked(): self.entriesUpdated.emit() return widget def checkedEntries(self): """ Returns the widgets that are checked for this widget. :return [<XOrbQueryEntryWidget>, ..] """ return [entry for entry in self.entries() if entry.isChecked()] def clear(self): """ Clears out the widgets for this query builder. """ layout = self._entryWidget.layout() for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() widget.close() def createCompoundFromChecked(self): """ Creates a new compound query from the checked entry list. :return <orb.QueryCompound> """ checked_entries = self.checkedEntries() if len(checked_entries) <= 1: return QueryCompound() self.setUpdatesEnabled(False) joiner = self.currentJoiner() query = Query() for entry in checked_entries: if joiner == QueryCompound.Op.And: query &= entry.query() else: query |= entry.query() # clear out the existing containers first = checked_entries[0] first.setQuery(query) first.setChecked(False) layout = self._entryWidget.layout() for i in range(len(checked_entries) - 1, 0, -1): w = checked_entries[i] layout.takeAt(layout.indexOf(w)) w.close() self.refreshEntries() self.setUpdatesEnabled(True) if not self.signalsBlocked(): self.enterCompound(first, query) def currentJoiner(self): return self._currentJoiner def enterCompound(self, entry, query): # enter an existing compound if QueryCompound.typecheck(query): self.enterCompoundRequested.emit(entry, query) # create a new compound from the checked entries else: self.createCompoundFromChecked() def entries(self): """ Returns the entry widgets for this widget. :return [<XOrbQueryEntryWidget>, ..] """ layout = self._entryWidget.layout() output = [] for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() if not isinstance(widget, XOrbQueryEntryWidget): continue output.append(widget) return output def exitCompound(self): self.exitCompoundRequested.emit() def isNull(self): """ Returns whether or not any widgets have been defined for this container yet. :return <bool> """ return self._entryWidget.layout().count() <= 1 def moveDown(self, entry): """ Moves the current query down one entry. """ if not entry: return entries = self.entries() next = entries[entries.index(entry) + 1] entry_q = entry.query() next_q = next.query() next.setQuery(entry_q) entry.setQuery(next_q) def moveUp(self, entry): """ Moves the current query down up one entry. """ if not entry: return entries = self.entries() next = entries[entries.index(entry) - 1] entry_q = entry.query() next_q = next.query() next.setQuery(entry_q) entry.setQuery(next_q) def pluginFactory(self): """ Returns the plugin factory for this widget. You can define a custom factory for handling specific columns or column types based on your table type. :return <XOrbQueryPluginFactory> """ return self._queryWidget.pluginFactory() def query(self): """ Returns the query that is defined by this current panel. :return <orb.Query> """ joiner = self.currentJoiner() query = Query() for entry in self.entries(): if joiner == QueryCompound.Op.And: query &= entry.query() else: query |= entry.query() query.setName(self.uiNameTXT.text()) return query def queryWidget(self): """ Returns the query widget linked with this container. :return <XOrbQueryWidget> """ return self._queryWidget def removeEntry(self, entry): if not entry: return layout = self._entryWidget.layout() if layout.count() == 2: entry.setQuery(Query()) return layout.takeAt(layout.indexOf(entry)) entry.close() if not self.signalsBlocked(): self.entriesUpdated.emit() def refreshEntries(self): layout = self._entryWidget.layout() for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() widget.setFirst(i == 0) widget.setLast(i == (layout.count() - 2)) def setCurrentJoiner(self, joiner): self._currentJoiner = joiner layout = self._entryWidget.layout() for i in range(layout.count() - 1): widget = layout.itemAt(i).widget() widget.setJoiner(joiner) def setQuery(self, query): """ Sets the query for this wigdet to the inputed query instance. :param query | <orb.Query> || <orb.QueryCompound> """ if not self.isNull() and hash(query) == hash(self.query()): return # add entries table = self.tableType() self.setUpdatesEnabled(False) self.blockSignals(True) self.clear() if query is None or table is None: self.setEnabled(False) self.setUpdatesEnabled(True) self.blockSignals(False) return else: self.setEnabled(True) # load the queries for this item if QueryCompound.typecheck(query): queries = query.queries() self.setCurrentJoiner(query.operatorType()) else: queries = [query] self.uiNameTXT.setText(query.name()) layout = self._entryWidget.layout() for index, query in enumerate(queries): widget = self.addEntry(query) widget.setFirst(index == 0) widget.setLast(index == (len(queries) - 1)) widget.setJoiner(self.currentJoiner()) self.setUpdatesEnabled(True) self.blockSignals(False) def setShowBack(self, state): # check to see if we're working on the current query self.uiBackBTN.setVisible(state) self.uiNameTXT.setVisible(state) def tableType(self): """ Returns the table type instance for this widget. :return <subclass of orb.Table> """ return self._queryWidget.tableType()
class XQueryBuilderWidget(QWidget): """ """ saveRequested = Signal() resetRequested = Signal() cancelRequested = Signal() def __init__( self, parent = None ): super(XQueryBuilderWidget, self).__init__( parent ) # load the user interface projexui.loadUi(__file__, self) self.setMinimumWidth(470) # define custom properties self._rules = {} self._defaultQuery = [] self._completionTerms = [] self._minimumCount = 1 # set default properties self._container = QWidget(self) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) layout.addStretch(1) self._container.setLayout(layout) self.uiQueryAREA.setWidget(self._container) # create connections self.uiResetBTN.clicked.connect( self.emitResetRequested ) self.uiSaveBTN.clicked.connect( self.emitSaveRequested ) self.uiCancelBTN.clicked.connect( self.emitCancelRequested ) self.resetRequested.connect( self.reset ) def addLineWidget( self, query = None ): """ Adds a new line widget to the system with the given values. :param query | (<str> term, <str> operator, <str> vlaue) || None """ widget = XQueryLineWidget(self) widget.setTerms(sorted(self._rules.keys())) widget.setQuery(query) index = self._container.layout().count() - 1 self._container.layout().insertWidget(index, widget) widget.addRequested.connect( self.addLineWidget ) widget.removeRequested.connect( self.removeLineWidget ) # update the remove enabled options for these widgets self.updateRemoveEnabled() def addRule( self, rule ): """ Adds a rule to the system. :param rule | <XQueryRule> """ self._rules[rule.term()] = rule self.updateRules() def clear( self ): """ Clears out all the widgets from the system. """ for lineWidget in self.lineWidgets(): lineWidget.setParent(None) lineWidget.deleteLater() def completionTerms( self ): """ Returns the list of terms that will be used as a global override for completion terms when the query rule generates a QLineEdit instance. :return [<str>, ..] """ return self._completionTerms def count( self ): """ Returns the count of the line widgets in the system. :return <int> """ return len(self.lineWidgets()) def currentQuery( self ): """ Returns the current query string for this widget. :return [(<str> term, <str> operator, <str> value), ..] """ widgets = self.lineWidgets() output = [] for widget in widgets: output.append(widget.query()) return output def defaultQuery( self ): """ Returns the default query for the system. :return [(<str> term, <str> operator, <str> value), ..] """ return self._defaultQuery def keyPressEvent( self, event ): """ Emits the save requested signal for this builder for when the enter or return press is clicked. :param event | <QKeyEvent> """ if ( event.key() in (Qt.Key_Enter, Qt.Key_Return) ): self.emitSaveRequested() super(XQueryBuilderWidget, self).keyPressEvent(event) def emitCancelRequested( self ): """ Emits the cancel requested signal. """ if ( not self.signalsBlocked() ): self.cancelRequested.emit() def emitResetRequested( self ): """ Emits the reste requested signal. """ if ( not self.signalsBlocked() ): self.resetRequested.emit() def emitSaveRequested( self ): """ Emits the save requested signal. """ if ( not self.signalsBlocked() ): self.saveRequested.emit() def findRule( self, term ): """ Looks up a rule by the inputed term. :param term | <str> :return <XQueryRule> || None """ return self._rules.get(nativestring(term)) def removeLineWidget( self, widget ): """ Removes the line widget from the query. :param widget | <XQueryLineWidget> """ widget.setParent(None) widget.deleteLater() self.updateRemoveEnabled() def minimumCount( self ): """ Defines the minimum number of query widgets that are allowed. :return <int> """ return self._minimumCount def lineWidgets( self ): """ Returns a list of line widgets for this system. :return [<XQueryLineWidget>, ..] """ return self.findChildren(XQueryLineWidget) def reset( self ): """ Resets the system to the default query. """ self.setCurrentQuery(self.defaultQuery()) def setCompletionTerms( self, terms ): """ Sets the list of terms that will be used as a global override for completion terms when the query rule generates a QLineEdit instance. :param terms | [<str>, ..] """ self._completionTerms = terms def setCurrentQuery( self, query ): """ Sets the query for this system to the inputed query. :param query | [(<str> term, <str> operator, <str> value), ..] """ self.clear() for entry in query: self.addLineWidget(entry) # make sure we have the minimum number of widgets for i in range(self.minimumCount() - len(query)): self.addLineWidget() def setDefaultQuery( self, query ): """ Sets the default query that will be used when the user clicks on the \ reset button or the reset method is called. :param query | [(<str> term, <str> operator, <str> value), ..] """ self._defaultQuery = query[:] def setMinimumCount( self, count ): """ Sets the minimum number of line widgets that are allowed at any \ given time. :param count | <int> """ self._minimumCount = count def setRules( self, rules ): """ Sets all the rules for this builder. :param rules | [<XQueryRule>, ..] """ if ( type(rules) in (list, tuple) ): self._rules = dict([(x.term(), x) for x in rules]) self.updateRules() return True elif ( type(rules) == dict ): self._rules = rules.copy() self.updateRules() return True else: return False def setTerms( self, terms ): """ Sets a simple rule list by accepting a list of strings for terms. \ This is a convenience method for the setRules method. :param rules | [<str> term, ..] """ return self.setRules([XQueryRule(term = term) for term in terms]) def updateRemoveEnabled( self ): """ Updates the remove enabled baesd on the current number of line widgets. """ lineWidgets = self.lineWidgets() count = len(lineWidgets) state = self.minimumCount() < count for widget in lineWidgets: widget.setRemoveEnabled(state) def updateRules( self ): """ Updates the query line items to match the latest rule options. """ terms = sorted(self._rules.keys()) for child in self.lineWidgets(): child.setTerms(terms)