Last active
August 26, 2017 05:15
-
-
Save Dayof/057f7d0e7e2baf29877875d54252fc2e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import toga | |
from collections import namedtuple | |
# Structure of the main data source of the tree | |
GRADES = namedtuple('Grades', 'cl grade') | |
class TreeStructure: | |
def __init__(self): | |
# Data source of the tree | |
self.data = ( | |
GRADES('A', () ), | |
GRADES('B', ('7.5', '6.1', '8.5') ), | |
GRADES('C', ('1.4', '6.1', '2.5') ), | |
GRADES('D', ('5.5', ) ), | |
GRADES('E', ('2.1', '5.5') ) | |
) | |
# Data visualization of the tree | |
self._visualization = self.tree_visualization_show_grades() | |
@property | |
def data(self): | |
""" | |
:returns: The data source of the tree | |
:rtype: ``tuple`` | |
""" | |
return self._data | |
@data.setter | |
def data(self, data): | |
''' | |
Set the data of the tree | |
:param data: Data source of the tree | |
:type data: ``tuple`` | |
''' | |
self._data = data | |
self.update_visualization() | |
def update_visualization(self, condition=False): | |
''' | |
Update the data visualization | |
:param condition: Condition to expand a branch on the tree. | |
True to show classes that contains students who | |
passed, False to show classes that contains | |
students who failed. | |
:type condition: ``bool`` | |
''' | |
self._visualization = self.tree_visualization_show_grades(condition) | |
def tree_visualization_show_grades(self, condition=False): | |
''' | |
Tree visualization | |
:param condition: Condition to expand a branch on the tree. | |
True to show classes that contains students who | |
passed, False to show classes that contains | |
students who failed. | |
:type condition: ``bool`` | |
:return: Return the data visualization of the Tree. | |
The dictionary contains items identified with the id of the | |
node and values that informs its icon's url and a bool that | |
indicates if the node is collapsed or expanded. | |
(default is True) | |
E.g. {node_id : (None, True)} | |
:rtype: ``dict``` | |
''' | |
# Icons url and nodes that will be returned | |
icons, nodes = {'check': 'check.png', 'fail': 'icon.png'}, {} | |
for item in self.data: | |
passed, failed = False, False | |
for grade in item.grade: | |
# Condition to a student pass in this class | |
if float(grade) >= 5.0: | |
icon, passed = icons['check'], True | |
else: | |
icon, failed = icons['fail'], True | |
nodes[id(item)+id(grade)] = (icon, True) | |
# If the condition to expand the branch is True when there are | |
# students that has passed in the class (>=5.0) or the condition | |
# is to expand the tree when there are student that has failed | |
# (<5.0). | |
if condition and passed or not condition and failed: | |
nodes[id(item)] = (None, False) | |
return nodes | |
def roots(self): | |
''' | |
Top level of the tree | |
:return: Return the nodes of the top level of the tree. | |
Each node information is represent with a dictionary that | |
contains the text of the node, icon's url and a bool that | |
indicates if the node is collapsed or expanded. | |
:rtype: ``list`` of ``dict`` | |
''' | |
final_data = [] | |
for item in self.data: | |
# Joins the node data according with the current visualization of | |
# the tree. A root node in this application doesn't have an icon. | |
if id(item) in self._visualization.keys(): | |
data = {'text': item[0], | |
'icon': None, | |
'collapsed': self._visualization[id(item)][1]} | |
else: | |
data = item[0] | |
final_data.append(data) | |
return final_data | |
# list of tuples | |
def search_node(self, text, branch=None): | |
for item in self.data: | |
if item[0] == text: | |
return self._make_data(id(item), item[1]) | |
return [] | |
def _make_data(self, node_id, children): | |
''' | |
Joins tha data of a node | |
:param node_id: Id of the node's parent | |
:type node_id: ``int`` | |
:param children: Texts of the children of the node's parent | |
:type children: ``tuple`` | |
:return: Return the information about each child of a node's parent. | |
Each node information is represent with a tuple that | |
contains the text of the node, icon's url and a bool that | |
indicates if the node is collapsed or expanded. | |
:rtype: ``list`` of ``tuple`` | |
''' | |
children_data = [] | |
for child in children: | |
# Adds the node id of the node's parent with the id of the current | |
# child node, key will be the path of the child | |
key = node_id+id(child) | |
# Joins the child node data according with the current | |
# visualization of the tree | |
if key in self._visualization.keys(): | |
new_data = (child, self._visualization[key][0], | |
self._visualization[key][1]) | |
else: | |
new_data = (child, None, True) | |
children_data.append(new_data) | |
return children_data | |
class TogaDataSource: | |
''' | |
Toga Data Source | |
''' | |
def __init__(self, data): | |
''' | |
Instantiate a new instance of the Toga data source | |
:param data: Data source and data visualization of the tree | |
:type data: :class:`TreeStructure` | |
''' | |
self._source = data | |
def roots(self): | |
''' | |
Top level of the tree | |
:return: Return the nodes of the top level of the tree. | |
Each node information is represent with a dictionary that | |
contains the text of the node, icon's url and a bool that | |
indicates if the node is collapsed or expanded | |
(default is True). | |
It's possible to pass just a string data instead of the | |
dictionary if the user don't want to bother with icons | |
or if a branch of the tree is expanded. | |
E.g. [{'text': None, 'icon': None, 'collapsed': True}] or | |
['text'] | |
:rtype: ``list`` of ``dict`` or ``list`` of ``str`` | |
''' | |
return self._source.roots() | |
def children(self, node): | |
''' | |
Children of the node | |
:param node: Parent node | |
:type node: :class:`tree.Node` | |
:return: Return the information about each child of the node's parent. | |
Each node information is represent with a dictionary that | |
contains the text of the node, icon's url and a bool that | |
indicates if the node is collapsed or expanded | |
(default is True). | |
It's possible to pass just a string data instead of the | |
dictionary if the user don't want to bother with icons | |
or if a branch of the tree is expanded. | |
E.g. [{'text': None, 'icon': None, 'collapsed': True}] or | |
['text'] | |
:rtype: ``list`` of ``dict`` or ``list`` of ``str`` | |
''' | |
# default data of a node | |
data = {'text': None, | |
'icon': None, | |
'collapsed': True} | |
# children is a list of tuples that contains text, icon and a bool that | |
# indicates if the child is collapsed | |
children = self._source.search_node(node.data['text']) | |
return [{k : value for (k,v), value in zip(data.items(), child)} for | |
child in children] | |
class StartApp(toga.App): | |
''' | |
Main Application | |
''' | |
def startup(self): | |
''' | |
Initial method to start a Toga application inside of a class | |
''' | |
# Main window | |
self.main_window = toga.MainWindow(self.name) | |
self.main_window.app = self | |
# Tree structure of this application | |
self.tree_data = TreeStructure() | |
# Tree widget from Toga | |
self.tree = toga.Tree(['Classes and Grades'], | |
data=TogaDataSource(self.tree_data)) | |
# Button to add a node on the tree | |
update_tree_node_button = toga.Button('Add F grades', | |
on_press=self.callbackUpdateNode) | |
# Button to update the data visualization of the tree and show who has | |
# passed | |
update_tree_display_button_pass = toga.Button('Show who passed', | |
on_press=self.callbackUpdateDisplayPass) | |
# Button to update the data visualization of the tree and show who has | |
# failed | |
update_tree_display_button_fail = toga.Button('Show who failed', | |
on_press=self.callbackUpdateDisplayFail) | |
# Widget to control the application using buttons | |
self.control_box = toga.Box(children=[update_tree_node_button, | |
update_tree_display_button_pass, | |
update_tree_display_button_fail]) | |
# Main widget of the application, show both the Ttee data and the | |
# buttons to control thee application | |
frame = toga.SplitContainer() | |
frame.content = [self.tree, self.control_box] | |
# Add the main widget inside of the main application | |
self.main_window.content = frame | |
# Show the application | |
self.main_window.show() | |
def callbackUpdateNode(self, event): | |
# New node to be add on the data source | |
self.tree_data.data += (GRADES('F', ('0.1', ) ),) | |
# Update the tree | |
self.tree.update() | |
def callbackUpdateDisplayPass(self, event): | |
# Update the data source visualization | |
self.tree_data.update_visualization(True) | |
# Update the tree | |
self.tree.update() | |
def callbackUpdateDisplayFail(self, event): | |
# Update the data source visualization, default is False | |
self.tree_data.update_visualization() | |
# Update the tree | |
self.tree.update() | |
def main(): | |
# Start the application with the title and the name of the organization | |
app = StartApp('Test Tree using data source construction', | |
'org.pybee.test') | |
app.main_loop() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment