Advertisement
Uno-Dan

The Tree

Sep 13th, 2019
361
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.04 KB | None | 0 0
  1. class Treeview(Base, ttk.Treeview):
  2.     def __init__(self, parent, key, **kwargs):
  3.         Base.__init__(self, parent, key, **kwargs)
  4.         self.columns = columns = dict(kwargs.get('settings', ())).get('columns', ())
  5.         self.headings = headings = dict(kwargs.get('settings', ())).get('headings', ())
  6.         ttk.Treeview.__init__(self, parent, columns=tuple(range(1, len(columns))), **self.options_args)
  7.         # self['columns'] = range(1, len(columns))
  8.         self.column_sort = {}
  9.  
  10.         for index, column in enumerate(columns):
  11.             self.column(f'#{index}', **dict(column))
  12.  
  13.         for index, heading in enumerate(headings):
  14.             self.column_sort[f'#{index}'] = True
  15.             self.heading(f'#{index}', **dict(heading))
  16.  
  17.         self.grid(**self.grid_args)
  18.         parent.winfo_toplevel().style.configure("Treeview", fieldbackground="black")
  19.  
  20.         def on_click(event):
  21.             region = self.identify("region", event.x, event.y)
  22.             if region == "heading":
  23.                 column_number = self.identify_column(event.x)
  24.                 if column_number in self.column_sort:
  25.                     reverse = False if self.column_sort[column_number] else True
  26.                     self.column_sort[column_number] = reverse
  27.                     self.sort(column_number, reverse)
  28.  
  29.             if region == "separator":
  30.                 column_number = self.identify_column(event.x)
  31.                 self.separator_double_click(column_number)
  32.  
  33.         self.bind("<Double-1>", on_click)
  34.  
  35.     def __str__(self):
  36.         return str(self.get_nodes())
  37.  
  38.     def cut(self):
  39.         self.copy()
  40.         self.remove()
  41.  
  42.     def copy(self):
  43.         self.winfo_toplevel().clipboard_clear()
  44.         self.winfo_toplevel().clipboard_append(str(self.selection()))
  45.  
  46.     def paste(self):
  47.         _cache = Cache()
  48.         items = sorted(literal_eval(self.winfo_toplevel().clipboard_get()))
  49.  
  50.         for node in items:
  51.             dest_node = self.selection()[0]
  52.  
  53.             def walk(_node, _parent=''):
  54.                 nodes = _node.rsplit("_", 1)
  55.                 _target = f'{_parent}/{dest_node}_{nodes.pop()}'.lstrip('/')
  56.                 _cache.set(_target, **self.item(_node))
  57.  
  58.                 children = self.get_children(_node)
  59.                 for child in children:
  60.                     walk(child, _target)
  61.  
  62.             walk(node)
  63.  
  64.         self.populate(self.selection()[0], **_cache.get())
  65.  
  66.         _cache.destroy()
  67.  
  68.     def sort(self, col, reverse):
  69.  
  70.         def do_sort(_col, _reverse):
  71.             if col != '#0':
  72.                 _data = [(self.set(k, col), k) for k in self.get_children()]
  73.             else:
  74.                 _data = [(self.item(k)['text'], k) for k in self.get_children()]
  75.  
  76.             _data.sort(reverse=reverse)
  77.             for _index, (_value, _parent) in enumerate(_data):
  78.                 self.move(_parent, '', _index)
  79.  
  80.         self.heading(col, command=lambda: do_sort(col, not reverse))
  81.  
  82.         def walk(children):
  83.             for child in children:
  84.                 if col != '#0':
  85.                     data = [(self.set(k, col), k) for k in self.get_children(child)]
  86.                 else:
  87.                     data = [(self.item(k)['text'], k) for k in self.get_children(child)]
  88.  
  89.                 data.sort(reverse=reverse)
  90.                 for index, (val, parent) in enumerate(data):
  91.                     self.move(parent, child, index)
  92.                     if self.get_children(child):
  93.                         walk(self.get_children(child))
  94.  
  95.         walk(self.get_children())
  96.  
  97.     def add(self, parent, index=tk.END, **kwargs):
  98.         try:
  99.             self.insert(parent, index, **kwargs)
  100.         except TclError as err:
  101.             if 'already exists' in str(err):
  102.                 messagebox.showerror(
  103.                     title='Create Project',
  104.                     message=f'The name you entered," {kwargs.get("text", "")}" already exists. '
  105.                             f'Choose another name and try again.'
  106.                     )
  107.  
  108.     def append(self, parent, **kwargs):
  109.         self.add(parent, tk.END, **kwargs)
  110.  
  111.     def remove(self):
  112.         selection = self.selection()[0]
  113.  
  114.         _prev = self.prev(selection)
  115.         _next = self.next(selection)
  116.  
  117.         self.delete(selection)
  118.         if _next:
  119.             self.selection_set(_next)
  120.         else:
  121.             _next = '_'.join(selection.split('_')[:-1])
  122.             if not self.next(_next):
  123.                 _next = '_'.join(_next.split('_')[:-1])
  124.                 if not self.next(_next):
  125.                     self.select_tail()
  126.             if self.next(_next):
  127.                 self.selection_set(self.next(_next))
  128.  
  129.     def populate(self, parent, index=tk.END, **data):
  130.         _cache = Cache(**data)
  131.  
  132.         def walk(_cfg, iid, _parent):
  133.             attrs = {}
  134.             cfg = deepcopy(_cfg)
  135.  
  136.             for _key, value in _cfg.items():
  137.                 if not isinstance(value, dict):
  138.                     attrs[_key] = cfg.pop(_key)
  139.  
  140.             iid = f'{_parent}_{iid.split("_")[-1]}'.lstrip('_')
  141.  
  142.             try:
  143.                 self.insert(_parent, index, iid=iid, **attrs)
  144.             except TclError as err:
  145.                 if 'already exists' in str(err):
  146.                     text = attrs["text"]
  147.                     messagebox.showerror(
  148.                         title='Create Projectx',
  149.                         message=f'The name you entered, "{text}" already exists. Choose another name and try again.'
  150.                     )
  151.                     return
  152.  
  153.             for _key, value in cfg.items():
  154.                 walk(value, f'{_key.split("_")[-1]}', iid)
  155.  
  156.         for key, node in data.items():
  157.             walk(node, key, parent)
  158.  
  159.     def get_nodes(self, _uri=None):
  160.         data = Cache()
  161.  
  162.         def walk(*args):
  163.             parent = args[0]
  164.             children = args[1]
  165.  
  166.             for child in children:
  167.                 uri = f'{parent}/{child}'
  168.                 data.set(uri, **self.item(child))
  169.  
  170.                 child_children = self.get_children(child)
  171.  
  172.                 if child_children:
  173.                     walk(uri, child_children)
  174.  
  175.         if _uri is not None and not isinstance(_uri, set):
  176.             _uri = (_uri,)
  177.  
  178.         if _uri:
  179.             for __uri in _uri:
  180.                 data.set(__uri, **self.item(__uri))
  181.                 walk(__uri, self.get_children(__uri))
  182.         else:
  183.             for _uri in self.get_children():
  184.                 data.set(_uri, **self.item(_uri))
  185.                 walk(_uri, self.get_children(_uri))
  186.  
  187.         return deepcopy(data.get())
  188.  
  189.     def separator_double_click(self, column):
  190.         _cache = Cache(**self.get_nodes())
  191.         _frame = ttk.Frame(self.winfo_toplevel())
  192.  
  193.         def get_size(item):
  194.             _text = self.item(item).get('text') if column == '#0' else self.set(item, column)
  195.             _lbl = tk.Label(_frame, text=_text)
  196.             _lbl.grid()
  197.             _frame.update_idletasks()
  198.             _size = _lbl.winfo_width()
  199.             _lbl.grid_forget()
  200.             return _size
  201.  
  202.         def walk(_children, _largest=0):
  203.             _depth = 0
  204.             for _child in _children:
  205.                 _depth = len(_child.split('_'))
  206.                 if self.item(_child)['open']:
  207.                     return walk(self.get_children(_child))
  208.                 else:
  209.                     _size = get_size(_child) + 6
  210.                     if _size > _largest:
  211.                         _largest = _size
  212.  
  213.             return _largest, _depth
  214.  
  215.         width, depth = walk(self.get_children())
  216.         if column == '#0':
  217.             width += depth * 20
  218.         self.column(column, width=width)
  219.  
  220.     def select_tail(self):
  221.         def walk(children):
  222.             if children:
  223.                 child = list(children).pop()
  224.                 if self.item(child)['open']:
  225.                     walk(self.get_children(child))
  226.                     if len(self.get_children(child)) == 0:
  227.                         self.selection_set(child)
  228.                 else:
  229.                     self.selection_set(child)
  230.  
  231.         walk(self.get_children())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement