def test_checkboxtreeview_methods(self):
     tree = CheckboxTreeview(self.window)
     tree.pack()
     self.window.update()
     tree.insert("", "end", "1", text="1")
     tree.insert("1", "end", "11", text="11")
     tree.insert("11", "end", "111", text="111")
     tree.insert("11", "end", "112", text="112")
     self.window.update()
     tree.state()
     self.window.update()
     tree.state(['disabled'])
     self.window.update()
     tree.state(['!disabled'])
     self.window.update()
     tree.collapse_all()
     self.window.update()
     tree.expand_all()
     self.window.update()
     tree.tag_add("1", "item")
     self.assertTrue(tree.tag_has("item", "1"))
     self.window.update()
     tree.change_state("1", "checked")
     self.assertTrue(tree.tag_has("checked", "1"))
     self.assertFalse(tree.tag_has("unchecked", "1"))
     self.assertFalse(tree.tag_has("tristate", "1"))
     self.assertTrue(tree.tag_has("item", "1"))
     self.window.update()
     tree.tag_del("1", "item")
     self.assertFalse(tree.tag_has("item", "1"))
     self.window.update()
     tree._check_descendant("1")
     self.assertTrue(tree.tag_has("checked", "11"))
     self.assertTrue(tree.tag_has("checked", "111"))
     self.assertTrue(tree.tag_has("checked", "112"))
     self.window.update()
     tree._uncheck_descendant("1")
     self.assertTrue(tree.tag_has("unchecked", "11"))
     self.assertTrue(tree.tag_has("unchecked", "111"))
     self.assertTrue(tree.tag_has("unchecked", "112"))
     self.window.update()
     tree._check_ancestor("111")
     self.assertTrue(tree.tag_has("tristate", "11"))
     self.window.update()
     tree._check_ancestor("112")
     self.assertTrue(tree.tag_has("checked", "11"))
     self.window.update()
     tree._uncheck_ancestor("111")
     self.assertTrue(tree.tag_has("tristate", "11"))
     self.window.update()
     tree._uncheck_ancestor("112")
     self.assertTrue(tree.tag_has("unchecked", "11"))
     self.window.update()
     tree._tristate_parent("111")
     self.assertTrue(tree.tag_has("tristate", "11"))
     self.assertTrue(tree.tag_has("tristate", "1"))
     self.window.update()
     tree.change_state("1", "checked")
     tree._check_descendant("1")
     self.assertEqual(tree.get_checked(), ["111", "112"])
     self.window.update()
Exemple #2
0
class TreeviewConstructor(object):
    logger = CustomAdapter(logging.getLogger(str(__name__)), None)

    @debug(lvl=logging.NOTSET, prefix='')
    def __init__(self, master, frame_main, checkwidth=0):
        self.master = master  # Done
        self.frame = frame_main  # Done
        self.col_obj_dict = {}  # Done
        self.column_lst = []  # Done
        self.col_disp_lst = []  # Done
        self.item_obj_dict = {}
        self.treeview = CheckboxTreeview(self.frame)  # Done
        self.ysb = ttk.Scrollbar(self.frame)  # Done
        self.xsb = ttk.Scrollbar(self.frame)  # Done
        self.checkwidth = checkwidth
        self.manager = BusyManager(self.frame)
        self.populate_frame()  # Done

    @debug(lvl=logging.NOTSET, prefix='')
    def populate_frame(self):
        self.frame.columnconfigure(0, weight=1)  # Done
        self.frame.rowconfigure(0, weight=1)  # Done
        self.treeview.grid(row=0, column=0, sticky=tk.NSEW)  # Done
        self.ysb.config(orient=tk.VERTICAL, command=self.treeview.yview)  # Done
        self.xsb.config(orient=tk.HORIZONTAL, command=self.treeview.xview)  # Done
        self.treeview['yscroll'] = self.ysb.set  # Done
        self.treeview['xscroll'] = self.xsb.set  # Done
        self.ysb.grid(row=0, column=1, sticky=tk.NS)  # Done
        self.xsb.grid(row=1, column=0, sticky=tk.EW)  # Done

    @debug(lvl=logging.NOTSET, prefix='')
    def populate_cols(self):
        col_obj = TreeColumn(order=0,
                             col_id='#0',
                             hdr_txt="",
                             anchor=tk.W,
                             stretch=tk.NO,
                             minwidth=0,
                             width=self.checkwidth,
                             display=False)
        TreeviewConstructor.logger.log(logging.NOTSET, "Column ID: {col_id} Header Text: {hdr_txt}".
                                       format(col_id=col_obj.col_id, hdr_txt=col_obj.hdr_txt))
        self.col_obj_dict[col_obj.col_id] = col_obj

        for col_key, column in sorted(self.col_obj_dict.items(), key=lambda x: x[1].order):
            self.column_lst.append(column.col_id)
            if column.display:
                self.col_disp_lst.append(column.col_id)

        self.treeview.config(columns=self.column_lst, displaycolumns=self.col_disp_lst)
        self.treeview.tag_configure('red', foreground='red2')
        self.treeview.tag_configure('evenrow', background='gray85')
        self.treeview.tag_configure('oddrow', background='white')

        for col in self.col_obj_dict.values():
            TreeviewConstructor.logger.log(
                logging.NOTSET,
                "Column ID: {col_id} Header Text: {hdr_txt} Anchor: {anchor}".format(
                    col_id=col.col_id, hdr_txt=col.hdr_txt, anchor=col.anchor))
            if col.hdr_txt in (None, ""):
                header = col.col_id
            else:
                header = col.hdr_txt
            self.treeview.heading(column=col.col_id,
                                  text=header,
                                  anchor=col.anchor,
                                  command=lambda _col=col.col_id: self.treeview_sort_column(_col, False))
            self.treeview.column(col.col_id, minwidth=col.minwidth, width=col.width, stretch=col.stretch)

    @debug(lvl=logging.DEBUG, prefix='')
    def populate_items(self):
        for item in self.item_obj_dict.values():
            TreeRow.logger.log(logging.NOTSET, "Item Info: {0}".format(item.iid))
            self.treeview.insert(item.parent, item.index, iid=item.iid, values=item.values_list)
            for tag in item.tags_list:
                self.treeview.tag_add(item.iid, tag)

    @debug(lvl=logging.DEBUG, prefix='')
    def stripe_rows(self):
        for item in self.item_obj_dict.values():
            self.treeview.tag_del(item.iid, 'evenrow')
            self.treeview.tag_del(item.iid, 'oddrow')
            row_num = self.treeview.index(item.iid)
            if row_num % 2 == 0:
                self.treeview.tag_add(item.iid, 'evenrow')
            elif row_num % 2 != 0:
                self.treeview.tag_add(item.iid, 'oddrow')

    @debug(lvl=logging.DEBUG, prefix='')
    def treeview_sort_column(self, col, reverse):
        self.manager.busy()
        item_list = [(self.treeview.set(k, col), k) for k in self.treeview.get_children('')]
        item_list.sort(reverse=reverse)
        # rearrange items in sorted positions
        for index, (val, k) in enumerate(item_list):
            self.treeview.move(k, '', index)
        self.stripe_rows()
        # reverse sort next time
        self.treeview.heading(col, command=lambda: self.treeview_sort_column(col, not reverse))
        self.manager.not_busy()

    @debug(lvl=logging.DEBUG, prefix='')
    def tv_refresh(self):
        # self.manager.busy()
        item_list = list(self.treeview.get_children(''))
        item_list.sort(key=lambda x: int(x))
        for item_iid, item_obj in sorted(self.item_obj_dict.items()):
            TreeRow.logger.log(logging.NOTSET, "Item ID: {0}".format(item_iid))
            # l = self.treeview.get_children('')
            for index, k in enumerate(item_list):
                TreeRow.logger.log(logging.NOTSET, "k: {0}".format(k))
                if str(item_iid) == str(k):
                    self.treeview.delete(k)
                    item_obj.index = index
                    self.treeview.insert(item_obj.parent, item_obj.index, iid=item_obj.iid, values=item_obj.values_list)
                    item_list.remove(k)
                    break
        self.stripe_rows()
class TreeviewConstructor(ttk.Frame):
    logger = CustomAdapter(logging.getLogger(str(__name__)), None)

    @debug(lvl=logging.DEBUG, prefix='')
    def __init__(self, master, *args, **kwargs):
        self.col_obj_dict = {}
        self.column_lst = []
        self.col_disp_lst = []
        self.item_obj_dict = {}
        self.master = master

        # noinspection PyArgumentList
        super().__init__(self.master, *args, **kwargs)

        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.treeview = CheckboxTreeview(self)
        TreeviewConstructor.logger.log(logging.DEBUG, "10")
        self.treeview.grid(row=0, column=0, sticky=tk.NSEW)
        TreeviewConstructor.logger.log(logging.DEBUG, "11")

        self.ysb = ttk.Scrollbar(self)
        TreeviewConstructor.logger.log(logging.DEBUG, "12")
        self.ysb.grid(row=0, column=1, sticky=tk.NS)
        TreeviewConstructor.logger.log(logging.DEBUG, "13")
        self.ysb.config(orient=tk.VERTICAL, command=self.treeview.yview)
        TreeviewConstructor.logger.log(logging.DEBUG, "14")

        self.xsb = ttk.Scrollbar(self)
        TreeviewConstructor.logger.log(logging.DEBUG, "15")
        self.xsb.grid(row=1, column=0, sticky=tk.EW)
        TreeviewConstructor.logger.log(logging.DEBUG, "16")
        self.xsb.config(orient=tk.HORIZONTAL, command=self.treeview.xview)
        TreeviewConstructor.logger.log(logging.DEBUG, "17")

        self.treeview['yscroll'] = self.ysb.set
        TreeviewConstructor.logger.log(logging.DEBUG, "18")
        self.treeview['xscroll'] = self.xsb.set
        TreeviewConstructor.logger.log(logging.DEBUG, "19")
        # self.manager = BusyManager(self.frame)

    @debug(lvl=logging.DEBUG, prefix='')
    def populate_cols(self, checkwidth):
        col_obj = TreeColumn(order=0,
                             col_id='#0',
                             hdr_txt="",
                             anchor=tk.W,
                             stretch=tk.NO,
                             minwidth=0,
                             width=checkwidth,
                             display=False)
        TreeviewConstructor.logger.log(
            logging.DEBUG, "Column ID: {col_id} Header Text: {hdr_txt}".format(
                col_id=col_obj.col_id, hdr_txt=col_obj.hdr_txt))
        self.col_obj_dict[col_obj.col_id] = col_obj

        for col_key, column in sorted(self.col_obj_dict.items(),
                                      key=lambda x: x[1].order):
            self.column_lst.append(column.col_id)
            if column.display:
                self.col_disp_lst.append(column.col_id)

        self.treeview.config(columns=self.column_lst,
                             displaycolumns=self.col_disp_lst)
        self.treeview.tag_configure('red',
                                    foreground='red4',
                                    background='IndianRed1')
        self.treeview.tag_configure('parent_evenrow', background='gray85')
        self.treeview.tag_configure('child_evenrow', background="honeydew3")
        self.treeview.tag_configure('parent_oddrow', background='white')
        self.treeview.tag_configure('child_oddrow', background="honeydew2")

        for col in self.col_obj_dict.values():
            TreeviewConstructor.logger.log(
                logging.DEBUG,
                "Column ID: {col_id} Header Text: {hdr_txt} Anchor: {anchor}".
                format(col_id=col.col_id,
                       hdr_txt=col.hdr_txt,
                       anchor=col.anchor))
            if col.hdr_txt in (None, ""):
                header = col.col_id
            else:
                header = col.hdr_txt
            if col.col_id == '#0':
                self.treeview.heading(column=col.col_id,
                                      text="",
                                      anchor=col.anchor,
                                      command=lambda _col=col.col_id: self.
                                      treeview_sort_column(_col, False))
            else:
                self.treeview.heading(column=col.col_id,
                                      text=header,
                                      anchor=col.anchor,
                                      command=lambda _col=col.col_id: self.
                                      treeview_sort_column(_col, False))

            self.treeview.column(col.col_id,
                                 minwidth=col.minwidth,
                                 width=col.width,
                                 stretch=col.stretch)

    @debug(lvl=logging.DEBUG, prefix='')
    def populate_items(self):
        for item in self.item_obj_dict.values():
            TreeviewConstructor.logger.log(logging.NOTSET,
                                           "Item Info: {0}".format(item.iid))
            self.treeview.insert(item.parent,
                                 item.index,
                                 iid=item.iid,
                                 values=item.values_list)
            for tag in item.tags_list:
                self.treeview.tag_add(item.iid, tag)

    @debug(lvl=logging.DEBUG, prefix='')
    def stripe_rows(self):
        for item in self.item_obj_dict.values():
            self.treeview.tag_del(item.iid, 'parent_evenrow')
            self.treeview.tag_del(item.iid, 'child_evenrow')
            self.treeview.tag_del(item.iid, 'parent_oddrow')
            self.treeview.tag_del(item.iid, 'child_oddrow')
            row_num = self.treeview.index(item.iid)
            if row_num % 2 == 0:
                if item.parent == "":
                    self.treeview.tag_add(item.iid, 'child_evenrow')
                else:
                    self.treeview.tag_add(item.iid, 'parent_evenrow')
            elif row_num % 2 != 0:
                if item.parent == "":
                    self.treeview.tag_add(item.iid, 'child_oddrow')
                else:
                    self.treeview.tag_add(item.iid, 'parent_oddrow')

    @debug(lvl=logging.DEBUG, prefix='')
    def treeview_sort_column(self, col, reverse):
        # self.manager.busy()
        item_list = [(self.treeview.set(k, col), k)
                     for k in self.treeview.get_children('')]
        item_list.sort(reverse=reverse)
        # rearrange items in sorted positions
        for index, (val, k) in enumerate(item_list):
            self.treeview.move(k, '', index)
        self.stripe_rows()
        # reverse sort next time
        self.treeview.heading(
            col, command=lambda: self.treeview_sort_column(col, not reverse))
        # self.manager.not_busy()

    @debug(lvl=logging.DEBUG, prefix='')
    def tv_refresh(self):
        # self.manager.busy()
        item_list = list(self.treeview.get_children(''))
        item_list.sort(key=lambda x: int(x))
        for item_iid, item_obj in sorted(self.item_obj_dict.items()):
            TreeviewConstructor.logger.log(logging.DEBUG,
                                           "Item ID: {0}".format(item_iid))
            # l = self.treeview.get_children('')
            for index, k in enumerate(item_list):
                TreeviewConstructor.logger.log(logging.DEBUG,
                                               "k: {0}".format(k))
                if str(item_iid) == str(k):
                    self.treeview.delete(k)
                    item_obj.index = index
                    self.treeview.insert(item_obj.parent,
                                         item_obj.index,
                                         iid=item_obj.iid,
                                         values=item_obj.values_list)
                    item_list.remove(k)
                    break
        self.stripe_rows()
        # self.manager.not_busy()

    @debug(lvl=logging.DEBUG, prefix='')
    def add_column(self,
                   order=None,
                   col_id=None,
                   hdr_txt="",
                   anchor=tk.W,
                   stretch=tk.YES,
                   minwidth=0,
                   width=50,
                   display=True,
                   desc=None):
        col_obj = TreeColumn(order=order,
                             col_id=col_id,
                             hdr_txt=hdr_txt,
                             anchor=anchor,
                             stretch=stretch,
                             minwidth=minwidth,
                             width=width,
                             display=display,
                             desc=desc)
        self.col_obj_dict[col_obj.col_id] = col_obj

    @debug(lvl=logging.NOTSET, prefix='')
    def add_item(self, iid, parent="", index=tk.END, values_dict=None):
        item_obj = TreeRow(treeview_const=self,
                           iid=iid,
                           parent=parent,
                           index=index,
                           values_dict=values_dict)
        self.item_obj_dict[item_obj.iid] = item_obj

    @debug(lvl=logging.DEBUG, prefix='')
    def columns_from_query(self, query, hide_list=None, pref_order=None):
        if pref_order is None:
            pref_order = []
        if hide_list is None:
            hide_list = []

        col_order = 1
        col_order += len(pref_order)
        TreeviewConstructor.logger.log(
            logging.DEBUG,
            "Column Order Starting Value: {0}".format(str(col_order)))

        for desc in query.column_descriptions:
            name = desc.get('name').replace("'", "").replace('"', "")
            TreeviewConstructor.logger.log(logging.DEBUG,
                                           "Column Name: {0}".format(name))
            disp = True
            if name in hide_list:
                disp = False
            cust_order = col_order
            if name in pref_order:
                cust_order = pref_order.index(name) + 1
            self.add_column(order=cust_order,
                            col_id=name.replace(" ", "_"),
                            hdr_txt=name,
                            display=disp,
                            desc=desc)
            if name not in pref_order:
                col_order += 1

    @debug(lvl=logging.DEBUG, prefix='')
    def rows_from_query(self,
                        query,
                        id_col="line_number",
                        limit=None,
                        parent_col=None):
        counter = 1
        for row in query.all():
            temp_dict = {}
            for col_obj in self.col_obj_dict.values():
                # noinspection PyProtectedMember
                value = row._asdict().get(col_obj.hdr_txt)
                if isinstance(value, str):
                    value.replace("{", "").replace("}", "")
                temp_dict[str(col_obj.order)] = value
            counter += 1
            if counter == limit:
                break
            parent = ""
            if parent_col is not None:
                # noinspection PyProtectedMember
                if str(row._asdict().get(id_col)) != str(
                        row._asdict().get(parent_col)):
                    # noinspection PyProtectedMember
                    parent = str(row._asdict().get(parent_col))
            # noinspection PyProtectedMember
            self.add_item(iid=str(row._asdict().get(id_col)),
                          values_dict=temp_dict,
                          parent=parent)

    @debug(lvl=logging.DEBUG, prefix='')
    def populate_query(self,
                       query,
                       hide_list=None,
                       pref_order=None,
                       id_col="line_number",
                       limit=None,
                       checkwidth=0,
                       parent_col=None):
        the_query = query
        self.columns_from_query(the_query, hide_list, pref_order)
        self.populate_cols(checkwidth=checkwidth)
        self.rows_from_query(the_query, id_col, limit, parent_col)
        self.populate_items()
        self.stripe_rows()