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)
Beispiel #2
0
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)