Example #1
0
    def construct_results(self, add_btn_text):
        """
        Construct the results widget

        Returns
        -------
        QtGui.QGroupBox
            group box that contains the results widget along with the 'add'
            button
        """
        # declare a group box
        _results = QtGui.QGroupBox(title="Results")
        # declare the layout as a vertical box
        layout = QtGui.QVBoxLayout()

        # declare the tree widget
        self._tree = RecursiveTreeWidget()
        # declare the "add to canvas" button
        self._add_btn = QtGui.QPushButton(text=add_btn_text)
        # connect the add button clicked signal to the externally facing
        # "add_btn_signal" QtCore.SIGNAL
        self._add_btn.clicked.connect(self.add)

        # add the tree widget to the layout
        layout.addWidget(self._tree)
        # add the button to the layout
        layout.addWidget(self._add_btn)

        # set the layout of the group box
        _results.setLayout(layout)

        # return the results group box
        return _results
Example #2
0
    def construct_results(self, add_btn_text):
        """
        Construct the results widget

        Returns
        -------
        QtGui.QGroupBox
            group box that contains the results widget along with the 'add'
            button
        """
        # declare a group box
        _results = QtGui.QGroupBox(title="Results")
        # declare the layout as a vertical box
        layout = QtGui.QVBoxLayout()

        # declare the tree widget
        self._tree = RecursiveTreeWidget()
        # declare the "add to canvas" button
        self._add_btn = QtGui.QPushButton(text=add_btn_text)
        # connect the add button clicked signal to the externally facing
        # "add_btn_signal" QtCore.SIGNAL
        self._add_btn.clicked.connect(self.add)

        # add the tree widget to the layout
        layout.addWidget(self._tree)
        # add the button to the layout
        layout.addWidget(self._add_btn)

        # set the layout of the group box
        _results.setLayout(layout)

        # return the results group box
        return _results
Example #3
0
class QueryController(QtCore.QObject):
    """
    The QueryController is a QObject that contains the search widget which is a
    QDockWidget and the tree widget which is a QTreeWidget

    Attributes
    ----------
    _keys : list
        List of search keys that will be displayed in the _query_input widget
    _key_descriptions : list
        List of descriptions for the keys that will appear as a tool tip on
        mouse hover
    _query_input : QtGui.QWidget
        The widget that displays a series of text input boxes with a 'search'
        button
    _results_tree : xray_vision.qt_widgets.displaydict.RecursiveTreeWidget
        The widget that displays the results as a tree with an 'add' button
    _search_dict : dict
        Dictionary that was unpacked into the search function. This attribute
        gets stored every time the 'search' button gets clicked
    _search_results : list
        List of dictionaries that the search function returns

    Methods
    -------
    update_search_results(results_list)
        Populate the RecursiveTreeWidget with the results_list
    enable_add_btn(bool)
        Enable/disable the add button
    enable_search_btn(bool)
        Enable/disable the search button
    add()
        Function that executes when the 'add' button is clicked
    search()
        Function that executes when the 'search' button is clicked
    read_search_boxes()
        Read the text from the search boxes to form a search dictionary, stored
        as _search_dict
    update_query_keys(keys, key_descriptions=None)
        Remake the query widget with new query keys and key_descriptions

    """
    # external handles for the add button and search button
    add_btn_sig = QtCore.Signal(dict, dict, dict, list)
    search_btn_sig = QtCore.Signal(dict)

    ###################################################################
    #                Construction time behavior                       #
    ###################################################################
    def __init__(self, keys, add_btn_text="Add", *args, **kwargs):
        """

        Parameters
        ----------
        keys : dict
            keys = {
                "key1" : {
                    "description" : "this is what key1 is for",
                    "type" : "this is the type of key1",
                }
            }
        add_btn_text : str
            Label for the add button
        """
        # call up the inheritance chain
        super(QueryController, self).__init__(*args, **kwargs)

        self._keys = keys

        # set up the query widget
        self._query_input = self.construct_query()

        # set up the results widget
        self._results_tree = self.construct_results(add_btn_text)

        self._search_dict = _defaults["empty_search"]

        self.update_search_results(self._search_dict)

    def construct_query(self):
        """
        Construct the query widget

        Returns
        -------
        QtGui.QGroupBox
            group box that contains the query widget
        """
        # declare the group box
        query = QtGui.QGroupBox(title="Query")

        # declare the search button
        self._search_btn = QtGui.QPushButton(text="&Search")
        # connect the search buttons clicked signal to the method which parses
        # the text boxes to create a search dictionary that gets emitted by the
        # externally facing search_btn_sig QtCore.Signal
        self._search_btn.clicked.connect(self.search)
        # declare the query widget
        query_widg = self.construct_query_input()

        # declare the layout as a vertical box layout
        layout = QtGui.QVBoxLayout()

        # add the widgets to the layout
        layout.addWidget(query_widg)
        layout.addWidget(self._search_btn)
        # set the layout of the group box
        query.setLayout(layout)
        # return the widget
        return query

    def construct_results(self, add_btn_text):
        """
        Construct the results widget

        Returns
        -------
        QtGui.QGroupBox
            group box that contains the results widget along with the 'add'
            button
        """
        # declare a group box
        _results = QtGui.QGroupBox(title="Results")
        # declare the layout as a vertical box
        layout = QtGui.QVBoxLayout()

        # declare the tree widget
        self._tree = RecursiveTreeWidget()
        # declare the "add to canvas" button
        self._add_btn = QtGui.QPushButton(text=add_btn_text)
        # connect the add button clicked signal to the externally facing
        # "add_btn_signal" QtCore.SIGNAL
        self._add_btn.clicked.connect(self.add)

        # add the tree widget to the layout
        layout.addWidget(self._tree)
        # add the button to the layout
        layout.addWidget(self._add_btn)

        # set the layout of the group box
        _results.setLayout(layout)

        # return the results group box
        return _results

    def construct_query_input(self, keys=None):
        """
        Construct the input boxes for the query.

        Parameters
        -------
        keys : dict
            keys = {
                "key1" : {
                    "description" : "this is what key1 is for",
                    "type" : "this is the type of key1",
                }
            }

        Returns
        -------
        QWidget
            This is the widget that contains the search keys as labels and
            their input boxes typed on "type"
        """
        # default behavior of keys input parameter
        if keys is None:
            keys = self._keys

        self._keys = keys
        # declare a vertical layout
        vert_layout = QtGui.QVBoxLayout()

        try:
            # if the input boxes dictionary exists, empty it
            self._input_boxes.clear()
        except AttributeError:
            # create a new dictionary
            self._input_boxes = {}

        _lookup_dict = {str: LineEdit,
                        int: LineEdit,
                        float: LineEdit,
                        datetime.datetime: DateTimeBox,
                        bool: CheckBox,
                        list: ComboBox}

        # loop over the keys to create an input box for each key
        for key in keys:
            # declare a new horizontal layout
            horz_layout = QtGui.QHBoxLayout()
            # declare the label
            lbl = QtGui.QLabel(key)
            try:
                # get the description from the nested dict
                description = keys[key]["description"]
            except KeyError:
                # use the key as the description
                description = key
            try:
                # get the key_type from the nested dict
                key_type = keys[key]["type"]
            except KeyError:
                # default to string typed
                key_type = str

            input_box_type = _lookup_dict[key_type]

            # declare the input box
            input_box = input_box_type(label_text=key, hover_text=description,
                                       has_check_box=_defaults["has_check_box"])
            # add the input box to the input_boxes dict
            self._input_boxes[key] = input_box
            # add the widgets to the layout
            horz_layout.addWidget(input_box)
            # set a dummy widget
            widg = QtGui.QWidget()
            widg.setLayout(horz_layout)
            # add the horizontal layout to the vertical layout
            vert_layout.addWidget(widg)

        query_input = QtGui.QWidget()
        query_input.setLayout(vert_layout)
        # return the vertical layout
        return query_input

    ############################################################################
    #                        Runtime behavior                                  #
    ############################################################################
    def register_unique_id_gen_func(self, unique_id_func):
        """

        Parameters
        ----------
        unique_id_func : function
            Function that generates a unique ID for a results dictionary.  For
            now, this function should probably just pick out the header_id
        """
        self._unique_id_func = unique_id_func

    def enable_search_btn(self, is_enabled):
        """
        Function to enable/disable the search button

        Parameters
        ----------
        is_enabled : bool
            enables/disables the search button

        """
        self._search_btn.setEnabled(is_enabled)

    def enable_add_btn(self, is_enabled):
        """
        Function to enable/disable the search button

        Parameters
        ----------
        is_enabled : bool
            enables/disables the search button

        """
        self._add_btn.setEnabled(is_enabled)

    @QtCore.Slot()
    def add(self):
        """
        Figure out which result is clicked and emit the add_btn_sig with the
        following arguments:
        dict1 : dict
            Dictionary of search keys used to generate the results shown in the
            tree widget
        dict2 : dict
            unique id dictionary that is guaranteed to return dict3 when
            unpacked into the registered search function
        dict3 : dict
            One results dictionary
        list : list
            path to the currently selected node in the tree widget
        """
        # TODO Change this to debugger level logging
        logger.debug("add_clicked")
        path_to_node, result_idx = self._tree.find_root()
        print(self._search_results.__class__)
        res_keys = list(self._search_results)
        res_keys.sort()
        cur_result_dict = self._search_results[res_keys[result_idx]]
        print(list(cur_result_dict))
        # todo ask the tree nicely for its currently selected dictionary
        # unique_id = tree.get_current()
        self.add_btn_sig.emit(self._search_dict,
                              self.create_unique_id(cur_result_dict),
                              cur_result_dict, path_to_node)

    def create_unique_id(self, result_dict):
        """
        Call the unique id function that was registered

        Parameters
        ----------
        result_dict : dict
            Dictionary that will be used to generate a unique id dictionary.

        Returns
        -------
        unique_id : dict
            The unique id dictionary is guaranteed to produce "result_dict" when
            unpacked into the search function
        """
        return self._unique_id_func(result_dict)

    @QtCore.Slot()
    def search(self):
        """
        Parse the search boxes and emit it as a signal
        """
        self.read_search_boxes()
        # once the dictionary is constructed, emit it as a signal
        self.search_btn_sig.emit(self._search_dict)

    @QtCore.Slot()
    def read_search_boxes(self):
        """
        Parse the search boxes to set up the query dictionary and store it as an
        instance variable "_search_dict"
        """
        # declare the search dict
        # TODO Change this to debugger level logging @tacaswell
        logger.debug("read_search_boxes")
        self._search_dict = {}
        print(self._input_boxes)
        try:
            # loop over the list of input boxes to extract the search string
            # todo need better list comprehension
            self._search_dict = {key: self._input_boxes[key].getValue()
                                 for key in self._input_boxes if
                                 self._input_boxes[key].getValue() is not None}
        except AttributeError as e:
            tb = traceback.format_exc()
            logger.error(tb)
            # the only time this will be caught is in the initial setup and it
            # is therefore ok to ignore this error
            pass

    @QtCore.Slot(list)
    def update_search_results(self, results):
        """
        Pass the search results to the recursive tree widget which displays them

        Parameters
        ----------
        results : array, list, object

        """
        # stash the search results for later use
        self._search_results = results
        self._tree.fill_widget(results)
        self.enable_add_btn(is_enabled=True)
Example #4
0
class QueryController(QtCore.QObject):
    """
    The QueryController is a QObject that contains the search widget which is a
    QDockWidget and the tree widget which is a QTreeWidget

    Attributes
    ----------
    _keys : list
        List of search keys that will be displayed in the _query_input widget
    _key_descriptions : list
        List of descriptions for the keys that will appear as a tool tip on
        mouse hover
    _query_input : QtGui.QWidget
        The widget that displays a series of text input boxes with a 'search'
        button
    _results_tree : xray_vision.qt_widgets.displaydict.RecursiveTreeWidget
        The widget that displays the results as a tree with an 'add' button
    _search_dict : dict
        Dictionary that was unpacked into the search function. This attribute
        gets stored every time the 'search' button gets clicked
    _search_results : list
        List of dictionaries that the search function returns

    Methods
    -------
    update_search_results(results_list)
        Populate the RecursiveTreeWidget with the results_list
    enable_add_btn(bool)
        Enable/disable the add button
    enable_search_btn(bool)
        Enable/disable the search button
    add()
        Function that executes when the 'add' button is clicked
    search()
        Function that executes when the 'search' button is clicked
    read_search_boxes()
        Read the text from the search boxes to form a search dictionary, stored
        as _search_dict
    update_query_keys(keys, key_descriptions=None)
        Remake the query widget with new query keys and key_descriptions

    """
    # external handles for the add button and search button
    add_btn_sig = QtCore.Signal(dict, dict, dict, list)
    search_btn_sig = QtCore.Signal(dict)

    ###################################################################
    #                Construction time behavior                       #
    ###################################################################
    def __init__(self, keys, add_btn_text="Add", *args, **kwargs):
        """

        Parameters
        ----------
        keys : dict
            keys = {
                "key1" : {
                    "description" : "this is what key1 is for",
                    "type" : "this is the type of key1",
                }
            }
        add_btn_text : str
            Label for the add button
        """
        # call up the inheritance chain
        super(QueryController, self).__init__(*args, **kwargs)

        self._keys = keys

        # set up the query widget
        self._query_input = self.construct_query()

        # set up the results widget
        self._results_tree = self.construct_results(add_btn_text)

        self._search_dict = _defaults["empty_search"]

        self.update_search_results(self._search_dict)

    def construct_query(self):
        """
        Construct the query widget

        Returns
        -------
        QtGui.QGroupBox
            group box that contains the query widget
        """
        # declare the group box
        query = QtGui.QGroupBox(title="Query")

        # declare the search button
        self._search_btn = QtGui.QPushButton(text="&Search")
        # connect the search buttons clicked signal to the method which parses
        # the text boxes to create a search dictionary that gets emitted by the
        # externally facing search_btn_sig QtCore.Signal
        self._search_btn.clicked.connect(self.search)
        # declare the query widget
        query_widg = self.construct_query_input()

        # declare the layout as a vertical box layout
        layout = QtGui.QVBoxLayout()

        # add the widgets to the layout
        layout.addWidget(query_widg)
        layout.addWidget(self._search_btn)
        # set the layout of the group box
        query.setLayout(layout)
        # return the widget
        return query

    def construct_results(self, add_btn_text):
        """
        Construct the results widget

        Returns
        -------
        QtGui.QGroupBox
            group box that contains the results widget along with the 'add'
            button
        """
        # declare a group box
        _results = QtGui.QGroupBox(title="Results")
        # declare the layout as a vertical box
        layout = QtGui.QVBoxLayout()

        # declare the tree widget
        self._tree = RecursiveTreeWidget()
        # declare the "add to canvas" button
        self._add_btn = QtGui.QPushButton(text=add_btn_text)
        # connect the add button clicked signal to the externally facing
        # "add_btn_signal" QtCore.SIGNAL
        self._add_btn.clicked.connect(self.add)

        # add the tree widget to the layout
        layout.addWidget(self._tree)
        # add the button to the layout
        layout.addWidget(self._add_btn)

        # set the layout of the group box
        _results.setLayout(layout)

        # return the results group box
        return _results

    def construct_query_input(self, keys=None):
        """
        Construct the input boxes for the query.

        Parameters
        -------
        keys : dict
            keys = {
                "key1" : {
                    "description" : "this is what key1 is for",
                    "type" : "this is the type of key1",
                }
            }

        Returns
        -------
        QWidget
            This is the widget that contains the search keys as labels and
            their input boxes typed on "type"
        """
        # default behavior of keys input parameter
        if keys is None:
            keys = self._keys

        self._keys = keys
        # declare a vertical layout
        vert_layout = QtGui.QVBoxLayout()

        try:
            # if the input boxes dictionary exists, empty it
            self._input_boxes.clear()
        except AttributeError:
            # create a new dictionary
            self._input_boxes = {}

        _lookup_dict = {
            str: LineEdit,
            int: LineEdit,
            float: LineEdit,
            datetime.datetime: DateTimeBox,
            bool: CheckBox,
            list: ComboBox
        }

        # loop over the keys to create an input box for each key
        for key in keys:
            # declare a new horizontal layout
            horz_layout = QtGui.QHBoxLayout()
            # declare the label
            lbl = QtGui.QLabel(key)
            try:
                # get the description from the nested dict
                description = keys[key]["description"]
            except KeyError:
                # use the key as the description
                description = key
            try:
                # get the key_type from the nested dict
                key_type = keys[key]["type"]
            except KeyError:
                # default to string typed
                key_type = str

            input_box_type = _lookup_dict[key_type]

            # declare the input box
            input_box = input_box_type(
                label_text=key,
                hover_text=description,
                has_check_box=_defaults["has_check_box"])
            # add the input box to the input_boxes dict
            self._input_boxes[key] = input_box
            # add the widgets to the layout
            horz_layout.addWidget(input_box)
            # set a dummy widget
            widg = QtGui.QWidget()
            widg.setLayout(horz_layout)
            # add the horizontal layout to the vertical layout
            vert_layout.addWidget(widg)

        query_input = QtGui.QWidget()
        query_input.setLayout(vert_layout)
        # return the vertical layout
        return query_input

    ############################################################################
    #                        Runtime behavior                                  #
    ############################################################################
    def register_unique_id_gen_func(self, unique_id_func):
        """

        Parameters
        ----------
        unique_id_func : function
            Function that generates a unique ID for a results dictionary.  For
            now, this function should probably just pick out the header_id
        """
        self._unique_id_func = unique_id_func

    def enable_search_btn(self, is_enabled):
        """
        Function to enable/disable the search button

        Parameters
        ----------
        is_enabled : bool
            enables/disables the search button

        """
        self._search_btn.setEnabled(is_enabled)

    def enable_add_btn(self, is_enabled):
        """
        Function to enable/disable the search button

        Parameters
        ----------
        is_enabled : bool
            enables/disables the search button

        """
        self._add_btn.setEnabled(is_enabled)

    @QtCore.Slot()
    def add(self):
        """
        Figure out which result is clicked and emit the add_btn_sig with the
        following arguments:
        dict1 : dict
            Dictionary of search keys used to generate the results shown in the
            tree widget
        dict2 : dict
            unique id dictionary that is guaranteed to return dict3 when
            unpacked into the registered search function
        dict3 : dict
            One results dictionary
        list : list
            path to the currently selected node in the tree widget
        """
        # TODO Change this to debugger level logging
        logger.debug("add_clicked")
        path_to_node, result_idx = self._tree.find_root()
        print(self._search_results.__class__)
        res_keys = list(self._search_results)
        res_keys.sort()
        cur_result_dict = self._search_results[res_keys[result_idx]]
        print(list(cur_result_dict))
        # todo ask the tree nicely for its currently selected dictionary
        # unique_id = tree.get_current()
        self.add_btn_sig.emit(self._search_dict,
                              self.create_unique_id(cur_result_dict),
                              cur_result_dict, path_to_node)

    def create_unique_id(self, result_dict):
        """
        Call the unique id function that was registered

        Parameters
        ----------
        result_dict : dict
            Dictionary that will be used to generate a unique id dictionary.

        Returns
        -------
        unique_id : dict
            The unique id dictionary is guaranteed to produce "result_dict" when
            unpacked into the search function
        """
        return self._unique_id_func(result_dict)

    @QtCore.Slot()
    def search(self):
        """
        Parse the search boxes and emit it as a signal
        """
        self.read_search_boxes()
        # once the dictionary is constructed, emit it as a signal
        self.search_btn_sig.emit(self._search_dict)

    @QtCore.Slot()
    def read_search_boxes(self):
        """
        Parse the search boxes to set up the query dictionary and store it as an
        instance variable "_search_dict"
        """
        # declare the search dict
        # TODO Change this to debugger level logging @tacaswell
        logger.debug("read_search_boxes")
        self._search_dict = {}
        print(self._input_boxes)
        try:
            # loop over the list of input boxes to extract the search string
            # todo need better list comprehension
            self._search_dict = {
                key: self._input_boxes[key].getValue()
                for key in self._input_boxes
                if self._input_boxes[key].getValue() is not None
            }
        except AttributeError as e:
            tb = traceback.format_exc()
            logger.error(tb)
            # the only time this will be caught is in the initial setup and it
            # is therefore ok to ignore this error
            pass

    @QtCore.Slot(list)
    def update_search_results(self, results):
        """
        Pass the search results to the recursive tree widget which displays them

        Parameters
        ----------
        results : array, list, object

        """
        # stash the search results for later use
        self._search_results = results
        self._tree.fill_widget(results)
        self.enable_add_btn(is_enabled=True)