From 2ac716f0a829cf72b35f476dbe63e21e4156bcab Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Sun, 19 Jun 2016 15:10:20 +0200 Subject: [PATCH 01/15] Add a Tree widget (when label is None and value ends with '.json') --- "examples/Tre\303\250 v\303\256ew.json" | 15 +++++++++++ examples/advanced.py | 1 + formlayout.py | 33 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 "examples/Tre\303\250 v\303\256ew.json" diff --git "a/examples/Tre\303\250 v\303\256ew.json" "b/examples/Tre\303\250 v\303\256ew.json" new file mode 100644 index 0000000..5609dc0 --- /dev/null +++ "b/examples/Tre\303\250 v\303\256ew.json" @@ -0,0 +1,15 @@ +{ +"Name": "QuickForm", +"Authors": + {"french" : ["Pièrre", "Flôrent"], + "english" : [ + {"Brit" : ["John", "Andrew"]}, + {"US" : [ + "Tim", + {"William" : ["Will","Bill"]} + ] + } + ] + }, +"Python": ["2", "3"] +} diff --git a/examples/advanced.py b/examples/advanced.py index 491bbb7..fbefbc9 100644 --- a/examples/advanced.py +++ b/examples/advanced.py @@ -19,6 +19,7 @@ def create_datalist_example(): test = [('str *', 'this is a string'), + (None, u'Treè vîew.json'), ('str_m *', """this is a MULTILINE string"""), diff --git a/formlayout.py b/formlayout.py index 30391ab..4a5abe3 100644 --- a/formlayout.py +++ b/formlayout.py @@ -361,6 +361,27 @@ def apply(self, callback): self.dialog.formwidget.get_widgets()) +class JSONTreeModel(QStandardItemModel): + def __init__(self, jsondata, header, parent=None): + QStandardItemModel.__init__(self, parent) + self.setHorizontalHeaderLabels([header]) + parent = self.invisibleRootItem() + self.add(jsondata, parent) + + def add(self, data, parent): + if isinstance(data, dict): + for key, value in data.items(): + item = QStandardItem(key) + parent.appendRow(item) + self.add(value, item) + elif isinstance(data, list): + for el in data: + self.add(el, parent) + else: + item = QStandardItem(data) + parent.appendRow(item) + + def font_is_installed(font): """Check if font is installed""" return [fam for fam in QFontDatabase().families() @@ -518,6 +539,18 @@ def setup(self): lab = QLabel() lab.setPixmap(pixmap) self.formlayout.addRow(lab) + elif value.endswith('.json'): + # JSON file + import json + from collections import OrderedDict + jsonfile = open(value, 'r') + jsondata = json.load(jsonfile, + object_pairs_hook=OrderedDict) + treemodel = JSONTreeModel(jsondata, value[:-5]) + tree = QTreeView() + tree.setModel(treemodel) + tree.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.formlayout.addRow(tree) else: # Comment self.formlayout.addRow(QLabel(value)) From 3fc3c9e66279b2231c9ff7aee828a5c14425cd8c Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Mon, 20 Jun 2016 19:07:42 +0200 Subject: [PATCH 02/15] Add XML support to Tree widget (when label is None and value ends with '.xml') --- "examples/Tre\303\250 v\303\256ew.xml" | 2 ++ examples/advanced.py | 1 - examples/tree.py | 19 ++++++++++++++++ formlayout.py | 30 ++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 "examples/Tre\303\250 v\303\256ew.xml" create mode 100644 examples/tree.py diff --git "a/examples/Tre\303\250 v\303\256ew.xml" "b/examples/Tre\303\250 v\303\256ew.xml" new file mode 100644 index 0000000..7956a15 --- /dev/null +++ "b/examples/Tre\303\250 v\303\256ew.xml" @@ -0,0 +1,2 @@ + +QuickFormPièrreFlôrentJohnAndrewTimWillBill23 diff --git a/examples/advanced.py b/examples/advanced.py index fbefbc9..491bbb7 100644 --- a/examples/advanced.py +++ b/examples/advanced.py @@ -19,7 +19,6 @@ def create_datalist_example(): test = [('str *', 'this is a string'), - (None, u'Treè vîew.json'), ('str_m *', """this is a MULTILINE string"""), diff --git a/examples/tree.py b/examples/tree.py new file mode 100644 index 0000000..5ac56a7 --- /dev/null +++ b/examples/tree.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009 Pierre Raybaut +# Licensed under the terms of the MIT License +# (see formlayout.py for details) + +""" +Tree examples +""" + +from formlayout import fedit + +datalist = [(None, 'JSON tree:'), + (None, u'Treè vîew.json'), + (None, 'XML tree:'), + (None, u'Treè vîew.xml') + ] + +print("result:", fedit(datalist, title="Tree examples")) diff --git a/formlayout.py b/formlayout.py index 4a5abe3..eea5133 100644 --- a/formlayout.py +++ b/formlayout.py @@ -382,6 +382,25 @@ def add(self, data, parent): parent.appendRow(item) +class XMLTreeModel(QStandardItemModel): + def __init__(self, xmldata, header, parent=None): + QStandardItemModel.__init__(self, parent) + self.setHorizontalHeaderLabels([header]) + parent = self.invisibleRootItem() + root = xmldata.getroot() + self.add(root, parent) + + def add(self, element, parent): + item = QStandardItem(element.tag) + parent.appendRow(item) + if element.text: + itemtext = QStandardItem(element.text) + item.appendRow(itemtext) + else: + for el in element: + self.add(el, item) + + def font_is_installed(font): """Check if font is installed""" return [fam for fam in QFontDatabase().families() @@ -551,6 +570,17 @@ def setup(self): tree.setModel(treemodel) tree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.formlayout.addRow(tree) + elif value.endswith('.xml'): + # XML file + global ET + import xml.etree.ElementTree as ET + xmlfile = open(value, 'r') + xmldata = ET.parse(xmlfile) + treemodel = XMLTreeModel(xmldata, value[:-4]) + tree = QTreeView() + tree.setModel(treemodel) + tree.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.formlayout.addRow(tree) else: # Comment self.formlayout.addRow(QLabel(value)) From 2e88ebcd5838b01dbf9cdc97bf213503e849c2c9 Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Tue, 21 Jun 2016 02:22:42 +0200 Subject: [PATCH 03/15] Add attributes support to XML Tree widget --- "examples/Tre\303\250 v\303\256ew.xml" | 2 +- formlayout.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git "a/examples/Tre\303\250 v\303\256ew.xml" "b/examples/Tre\303\250 v\303\256ew.xml" index 7956a15..821dba6 100644 --- "a/examples/Tre\303\250 v\303\256ew.xml" +++ "b/examples/Tre\303\250 v\303\256ew.xml" @@ -1,2 +1,2 @@ -QuickFormPièrreFlôrentJohnAndrewTimWillBill23 +QuickFormPièrreFlôrentJohnAndrewTimWillBill23 diff --git a/formlayout.py b/formlayout.py index eea5133..6259cb1 100644 --- a/formlayout.py +++ b/formlayout.py @@ -393,9 +393,20 @@ def __init__(self, xmldata, header, parent=None): def add(self, element, parent): item = QStandardItem(element.tag) parent.appendRow(item) + for key, value in element.attrib.items(): + itemattrib = QStandardItem(key) + item.appendRow(itemattrib) + itemleaf = QStandardItem(value) + itemattrib.appendRow(itemleaf) if element.text: - itemtext = QStandardItem(element.text) - item.appendRow(itemtext) + if not element.attrib: + itemtext = QStandardItem(element.text) + item.appendRow(itemtext) + else: + itemtext = QStandardItem('TEXT') + item.appendRow(itemtext) + itemleaf = QStandardItem(element.text) + itemtext.appendRow(itemleaf) else: for el in element: self.add(el, item) From 142836a67617355349142ecf52460bfc5a2c5432 Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Thu, 23 Jun 2016 03:08:48 +0200 Subject: [PATCH 04/15] Add mixed-content support to XML Tree widget --- "examples/Tre\303\250 v\303\256ew.xml" | 2 +- formlayout.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git "a/examples/Tre\303\250 v\303\256ew.xml" "b/examples/Tre\303\250 v\303\256ew.xml" index 821dba6..7dfcc28 100644 --- "a/examples/Tre\303\250 v\303\256ew.xml" +++ "b/examples/Tre\303\250 v\303\256ew.xml" @@ -1,2 +1,2 @@ -QuickFormPièrreFlôrentJohnAndrewTimWillBill23 +QuîckFormPièrreFlôrentJohnAndrewTimWillBill23 diff --git a/formlayout.py b/formlayout.py index 6259cb1..17a0fb8 100644 --- a/formlayout.py +++ b/formlayout.py @@ -398,14 +398,16 @@ def add(self, element, parent): item.appendRow(itemattrib) itemleaf = QStandardItem(value) itemattrib.appendRow(itemleaf) - if element.text: + if element.text or (element.getchildren() and element[0].tail): + text = ET.tostring(element, method='text', encoding='utf-8' + ).decode('utf-8') if not element.attrib: - itemtext = QStandardItem(element.text) + itemtext = QStandardItem(text) item.appendRow(itemtext) else: itemtext = QStandardItem('TEXT') item.appendRow(itemtext) - itemleaf = QStandardItem(element.text) + itemleaf = QStandardItem(text) itemtext.appendRow(itemleaf) else: for el in element: From 3ae0accf5a9069c96cd8d8d64cefc7f08520c076 Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Sun, 26 Jun 2016 07:05:46 +0200 Subject: [PATCH 05/15] Add regular form support to Tree widget (when value is a dict) --- examples/advanced.py | 2 ++ formlayout.py | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/examples/advanced.py b/examples/advanced.py index 491bbb7..32bbce2 100644 --- a/examples/advanced.py +++ b/examples/advanced.py @@ -23,6 +23,8 @@ def create_datalist_example(): MULTILINE string"""), ('file *', 'file'), + ('dict', {'Name': 'QuickForm', + 'Authors': {'French':[u'Pièrre', u'Flôrent']}}), ('list *', [0, '1', '3', '4']), ('tuple *', (0, '1', '3', '4')), ('list2', ['--', ('none', 'None'), ('--', 'Dashed'), diff --git a/formlayout.py b/formlayout.py index 17a0fb8..cdd9ba7 100644 --- a/formlayout.py +++ b/formlayout.py @@ -361,12 +361,13 @@ def apply(self, callback): self.dialog.formwidget.get_widgets()) -class JSONTreeModel(QStandardItemModel): - def __init__(self, jsondata, header, parent=None): +class DictTreeModel(QStandardItemModel): + def __init__(self, data, header=None, parent=None): QStandardItemModel.__init__(self, parent) - self.setHorizontalHeaderLabels([header]) + if header: + self.setHorizontalHeaderLabels([header]) parent = self.invisibleRootItem() - self.add(jsondata, parent) + self.add(data, parent) def add(self, data, parent): if isinstance(data, dict): @@ -578,7 +579,7 @@ def setup(self): jsonfile = open(value, 'r') jsondata = json.load(jsonfile, object_pairs_hook=OrderedDict) - treemodel = JSONTreeModel(jsondata, value[:-5]) + treemodel = DictTreeModel(jsondata, value[:-5]) tree = QTreeView() tree.setModel(treemodel) tree.setEditTriggers(QAbstractItemView.NoEditTriggers) @@ -647,6 +648,12 @@ def setup(self): field.setCurrentIndex(selindex) elif isinstance(save_value, tuple): field = RadioLayout(value, selindex, self) + elif isinstance(value, dict): + treemodel = DictTreeModel(value) + field = QTreeView() + field.header().hide() + field.setModel(treemodel) + field.setEditTriggers(QAbstractItemView.NoEditTriggers) elif isinstance(value, bool): field = QCheckBox(self) field.setCheckState(Qt.Checked if value else Qt.Unchecked) @@ -761,6 +768,8 @@ def get(self): value = value[index+1] if isinstance(value, (list, tuple)): value = value[0] + elif isinstance(value, dict): + pass elif isinstance(value, bool): value = field.checkState() == Qt.Checked elif isinstance(value, float): From 3faef89fcfbb7f2708a797763b02de768093e050 Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Sun, 26 Jun 2016 07:14:39 +0200 Subject: [PATCH 06/15] Make the Tree widget editable in regular form --- formlayout.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/formlayout.py b/formlayout.py index cdd9ba7..bd839fb 100644 --- a/formlayout.py +++ b/formlayout.py @@ -382,6 +382,36 @@ def add(self, data, parent): item = QStandardItem(data) parent.appendRow(item) + def value(self): + parent = self.invisibleRootItem() + ret = {} + for i in range(parent.rowCount()): + child = parent.child(i) + key = to_text_string(child.text()) + ret[key] = self.addvalue(child) + return ret + + def addvalue(self, parent): + if parent.rowCount() == 1: + child = parent.child(0) + if child.hasChildren(): + ret, key = {}, to_text_string(child.text()) + ret[key] = self.addvalue(child) + return ret + else: + return to_text_string(child.text()) + else: + children = [] + for i in range(parent.rowCount()): + child = parent.child(i) + if child.hasChildren(): + ret, key = {}, to_text_string(child.text()) + ret[key] = self.addvalue(child) + children.append(ret) + else: + children.append(to_text_string(child.text())) + return children + class XMLTreeModel(QStandardItemModel): def __init__(self, xmldata, header, parent=None): @@ -653,7 +683,6 @@ def setup(self): field = QTreeView() field.header().hide() field.setModel(treemodel) - field.setEditTriggers(QAbstractItemView.NoEditTriggers) elif isinstance(value, bool): field = QCheckBox(self) field.setCheckState(Qt.Checked if value else Qt.Unchecked) @@ -769,7 +798,7 @@ def get(self): if isinstance(value, (list, tuple)): value = value[0] elif isinstance(value, dict): - pass + value = field.model().value() elif isinstance(value, bool): value = field.checkState() == Qt.Checked elif isinstance(value, float): From d1d6dc144f50c3ae482e93874f0a25fc3ab43ecc Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Sun, 26 Jun 2016 20:23:35 +0200 Subject: [PATCH 07/15] Update Tree widget examples --- examples/advanced.py | 2 -- examples/tree.py | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/advanced.py b/examples/advanced.py index 32bbce2..491bbb7 100644 --- a/examples/advanced.py +++ b/examples/advanced.py @@ -23,8 +23,6 @@ def create_datalist_example(): MULTILINE string"""), ('file *', 'file'), - ('dict', {'Name': 'QuickForm', - 'Authors': {'French':[u'Pièrre', u'Flôrent']}}), ('list *', [0, '1', '3', '4']), ('tuple *', (0, '1', '3', '4')), ('list2', ['--', ('none', 'None'), ('--', 'Dashed'), diff --git a/examples/tree.py b/examples/tree.py index 5ac56a7..e5d3691 100644 --- a/examples/tree.py +++ b/examples/tree.py @@ -10,10 +10,24 @@ from formlayout import fedit -datalist = [(None, 'JSON tree:'), +datalist = [('dict:', {"Name": "QuickForm", + "Authors": + {"french" : [u"Pièrre", u"Flôrent"], + "english" : [ + {"Brit" : ["John", "Andrew"]}, + {"US" : [ + "Tim", + {"William" : ["Will","Bill"]} + ] + } + ] + }, + "Python": ["2", "3"] + }), + (None, 'JSON tree:'), (None, u'Treè vîew.json'), (None, 'XML tree:'), (None, u'Treè vîew.xml') ] -print("result:", fedit(datalist, title="Tree examples")) +print('result:', fedit(datalist, title='Tree examples', type='questions')) From 1fda942102f9e87279f537935e4d0d2c7ec09c0c Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Mon, 27 Jun 2016 15:55:26 +0200 Subject: [PATCH 08/15] Simplify Tree model code --- formlayout.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/formlayout.py b/formlayout.py index bd839fb..5331e89 100644 --- a/formlayout.py +++ b/formlayout.py @@ -383,8 +383,7 @@ def add(self, data, parent): parent.appendRow(item) def value(self): - parent = self.invisibleRootItem() - ret = {} + ret, parent = {}, self.invisibleRootItem() for i in range(parent.rowCount()): child = parent.child(i) key = to_text_string(child.text()) @@ -392,24 +391,18 @@ def value(self): return ret def addvalue(self, parent): - if parent.rowCount() == 1: - child = parent.child(0) + children = [] + for i in range(parent.rowCount()): + child = parent.child(i) if child.hasChildren(): ret, key = {}, to_text_string(child.text()) ret[key] = self.addvalue(child) - return ret + children.append(ret) else: - return to_text_string(child.text()) + children.append(to_text_string(child.text())) + if len(children) == 1: + return children[0] else: - children = [] - for i in range(parent.rowCount()): - child = parent.child(i) - if child.hasChildren(): - ret, key = {}, to_text_string(child.text()) - ret[key] = self.addvalue(child) - children.append(ret) - else: - children.append(to_text_string(child.text())) return children From c9c095ed36ce39a7aaa240877f4307f469a4ffeb Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Wed, 29 Jun 2016 04:25:33 +0200 Subject: [PATCH 09/15] Fix indented XML support in Tree widget --- formlayout.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/formlayout.py b/formlayout.py index 5331e89..17f47ea 100644 --- a/formlayout.py +++ b/formlayout.py @@ -422,7 +422,9 @@ def add(self, element, parent): item.appendRow(itemattrib) itemleaf = QStandardItem(value) itemattrib.appendRow(itemleaf) - if element.text or (element.getchildren() and element[0].tail): + if (element.text and not element.text.isspace()) or ( + element.getchildren() and element[0].tail + and not element[0].tail.isspace()): text = ET.tostring(element, method='text', encoding='utf-8' ).decode('utf-8') if not element.attrib: From ff427f0f376266de5e449bf77fb7cf2c08fa91de Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Fri, 1 Jul 2016 02:53:04 +0200 Subject: [PATCH 10/15] Add content support to JSON Tree view --- .../Tre\303\250 v\303\256ew_Node content.json" | 4 ++-- examples/tree.py | 2 +- formlayout.py | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 6 deletions(-) rename "examples/Tre\303\250 v\303\256ew.json" => "examples/Tre\303\250 v\303\256ew_Node content.json" (71%) diff --git "a/examples/Tre\303\250 v\303\256ew.json" "b/examples/Tre\303\250 v\303\256ew_Node content.json" similarity index 71% rename from "examples/Tre\303\250 v\303\256ew.json" rename to "examples/Tre\303\250 v\303\256ew_Node content.json" index 5609dc0..9857ac3 100644 --- "a/examples/Tre\303\250 v\303\256ew.json" +++ "b/examples/Tre\303\250 v\303\256ew_Node content.json" @@ -1,7 +1,7 @@ { "Name": "QuickForm", "Authors": - {"french" : ["Pièrre", "Flôrent"], + {"french" : {"old": "Pièrre", "new": "Flôrent"}, "english" : [ {"Brit" : ["John", "Andrew"]}, {"US" : [ @@ -11,5 +11,5 @@ } ] }, -"Python": ["2", "3"] +"Python": {"old": "2", "new": "3"} } diff --git a/examples/tree.py b/examples/tree.py index e5d3691..e327167 100644 --- a/examples/tree.py +++ b/examples/tree.py @@ -25,7 +25,7 @@ "Python": ["2", "3"] }), (None, 'JSON tree:'), - (None, u'Treè vîew.json'), + (None, u'Treè vîew_Node content.json'), (None, 'XML tree:'), (None, u'Treè vîew.xml') ] diff --git a/formlayout.py b/formlayout.py index 17f47ea..fccbd0a 100644 --- a/formlayout.py +++ b/formlayout.py @@ -364,8 +364,10 @@ def apply(self, callback): class DictTreeModel(QStandardItemModel): def __init__(self, data, header=None, parent=None): QStandardItemModel.__init__(self, parent) + self.columns = False if header: - self.setHorizontalHeaderLabels([header]) + self.columns = True + self.setHorizontalHeaderLabels(header) parent = self.invisibleRootItem() self.add(data, parent) @@ -374,7 +376,11 @@ def add(self, data, parent): for key, value in data.items(): item = QStandardItem(key) parent.appendRow(item) - self.add(value, item) + if self.columns and not isinstance(value, (dict,list)): + leaf = QStandardItem(value) + parent.setChild(self.indexFromItem(item).row(), 1, leaf) + else: + self.add(value, item) elif isinstance(data, list): for el in data: self.add(el, parent) @@ -604,7 +610,11 @@ def setup(self): jsonfile = open(value, 'r') jsondata = json.load(jsonfile, object_pairs_hook=OrderedDict) - treemodel = DictTreeModel(jsondata, value[:-5]) + if '_' in value: + header = value[:-5].split('_') + else: + header = [value[:-5], 'Content'] + treemodel = DictTreeModel(jsondata, header) tree = QTreeView() tree.setModel(treemodel) tree.setEditTriggers(QAbstractItemView.NoEditTriggers) From 271b53ca50c45f1eb5a44c201b79d5b169bdea52 Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Fri, 1 Jul 2016 03:15:37 +0200 Subject: [PATCH 11/15] Add icon support to Tree view --- formlayout.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/formlayout.py b/formlayout.py index fccbd0a..08b4c7e 100644 --- a/formlayout.py +++ b/formlayout.py @@ -364,6 +364,8 @@ def apply(self, callback): class DictTreeModel(QStandardItemModel): def __init__(self, data, header=None, parent=None): QStandardItemModel.__init__(self, parent) + self.ficon = qApp.style().standardIcon(QStyle.SP_FileIcon) + self.dicon = qApp.style().standardIcon(QStyle.SP_DirIcon) self.columns = False if header: self.columns = True @@ -377,15 +379,18 @@ def add(self, data, parent): item = QStandardItem(key) parent.appendRow(item) if self.columns and not isinstance(value, (dict,list)): + item.setIcon(self.ficon) leaf = QStandardItem(value) parent.setChild(self.indexFromItem(item).row(), 1, leaf) else: + item.setIcon(self.dicon) self.add(value, item) elif isinstance(data, list): for el in data: self.add(el, parent) else: item = QStandardItem(data) + item.setIcon(self.ficon) parent.appendRow(item) def value(self): @@ -415,6 +420,8 @@ def addvalue(self, parent): class XMLTreeModel(QStandardItemModel): def __init__(self, xmldata, header, parent=None): QStandardItemModel.__init__(self, parent) + self.ficon = qApp.style().standardIcon(QStyle.SP_FileIcon) + self.dicon = qApp.style().standardIcon(QStyle.SP_DirIcon) self.setHorizontalHeaderLabels([header]) parent = self.invisibleRootItem() root = xmldata.getroot() @@ -422,6 +429,7 @@ def __init__(self, xmldata, header, parent=None): def add(self, element, parent): item = QStandardItem(element.tag) + item.setIcon(self.dicon) parent.appendRow(item) for key, value in element.attrib.items(): itemattrib = QStandardItem(key) @@ -435,9 +443,11 @@ def add(self, element, parent): ).decode('utf-8') if not element.attrib: itemtext = QStandardItem(text) + itemtext.setIcon(self.ficon) item.appendRow(itemtext) else: itemtext = QStandardItem('TEXT') + itemtext.setIcon(self.ficon) item.appendRow(itemtext) itemleaf = QStandardItem(text) itemtext.appendRow(itemleaf) From 71305b5632d07f7b685a363d004768640de447b5 Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Sat, 2 Jul 2016 01:23:29 +0200 Subject: [PATCH 12/15] Add content support to XML Tree view --- .../Tre\303\250 v\303\256ew_Node content.xml" | 0 examples/tree.py | 2 +- formlayout.py | 37 +++++++++++++++---- 3 files changed, 30 insertions(+), 9 deletions(-) rename "examples/Tre\303\250 v\303\256ew.xml" => "examples/Tre\303\250 v\303\256ew_Node content.xml" (100%) diff --git "a/examples/Tre\303\250 v\303\256ew.xml" "b/examples/Tre\303\250 v\303\256ew_Node content.xml" similarity index 100% rename from "examples/Tre\303\250 v\303\256ew.xml" rename to "examples/Tre\303\250 v\303\256ew_Node content.xml" diff --git a/examples/tree.py b/examples/tree.py index e327167..d1d86ac 100644 --- a/examples/tree.py +++ b/examples/tree.py @@ -27,7 +27,7 @@ (None, 'JSON tree:'), (None, u'Treè vîew_Node content.json'), (None, 'XML tree:'), - (None, u'Treè vîew.xml') + (None, u'Treè vîew_Node content.xml') ] print('result:', fedit(datalist, title='Tree examples', type='questions')) diff --git a/formlayout.py b/formlayout.py index 08b4c7e..d70fb6c 100644 --- a/formlayout.py +++ b/formlayout.py @@ -418,11 +418,14 @@ def addvalue(self, parent): class XMLTreeModel(QStandardItemModel): - def __init__(self, xmldata, header, parent=None): + def __init__(self, xmldata, header=None, parent=None): QStandardItemModel.__init__(self, parent) self.ficon = qApp.style().standardIcon(QStyle.SP_FileIcon) self.dicon = qApp.style().standardIcon(QStyle.SP_DirIcon) - self.setHorizontalHeaderLabels([header]) + self.columns = False + if header: + self.columns = True + self.setHorizontalHeaderLabels(header) parent = self.invisibleRootItem() root = xmldata.getroot() self.add(root, parent) @@ -435,7 +438,11 @@ def add(self, element, parent): itemattrib = QStandardItem(key) item.appendRow(itemattrib) itemleaf = QStandardItem(value) - itemattrib.appendRow(itemleaf) + if self.columns: + item.setChild(self.indexFromItem(itemattrib).row(), 1, + itemleaf) + else: + itemattrib.appendRow(itemleaf) if (element.text and not element.text.isspace()) or ( element.getchildren() and element[0].tail and not element[0].tail.isspace()): @@ -443,14 +450,24 @@ def add(self, element, parent): ).decode('utf-8') if not element.attrib: itemtext = QStandardItem(text) - itemtext.setIcon(self.ficon) - item.appendRow(itemtext) + if self.columns: + item.setIcon(self.ficon) + parent.setChild(self.indexFromItem(item).row(), 1, + itemtext) + else: + itemtext.setIcon(self.ficon) + item.appendRow(itemtext) else: itemtext = QStandardItem('TEXT') - itemtext.setIcon(self.ficon) item.appendRow(itemtext) itemleaf = QStandardItem(text) - itemtext.appendRow(itemleaf) + if self.columns: + itemtext.setIcon(self.ficon) + item.setChild(self.indexFromItem(itemtext).row(), 1, + itemleaf) + else: + itemleaf.setIcon(self.ficon) + itemtext.appendRow(itemleaf) else: for el in element: self.add(el, item) @@ -635,7 +652,11 @@ def setup(self): import xml.etree.ElementTree as ET xmlfile = open(value, 'r') xmldata = ET.parse(xmlfile) - treemodel = XMLTreeModel(xmldata, value[:-4]) + if '_' in value: + header = value[:-4].split('_') + else: + header = [value[:-4], 'Content'] + treemodel = XMLTreeModel(xmldata, header) tree = QTreeView() tree.setModel(treemodel) tree.setEditTriggers(QAbstractItemView.NoEditTriggers) From ef3c4d9494c1a9daffa8eb6fbc8520dc80c149fc Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Sat, 2 Jul 2016 02:06:53 +0200 Subject: [PATCH 13/15] Allow to choose the Tree view style ('_' in the filename) --- "examples/Tre\303\250 v\303\256ew.json" | 15 +++++++++++++++ "examples/Tre\303\250 v\303\256ew.xml" | 2 ++ .../Tre\303\250 v\303\256ew_Node content.json" | 16 +--------------- .../Tre\303\250 v\303\256ew_Node content.xml" | 3 +-- examples/tree.py | 4 ++++ formlayout.py | 18 ++++++++++-------- 6 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 "examples/Tre\303\250 v\303\256ew.json" create mode 100644 "examples/Tre\303\250 v\303\256ew.xml" mode change 100644 => 120000 "examples/Tre\303\250 v\303\256ew_Node content.json" mode change 100644 => 120000 "examples/Tre\303\250 v\303\256ew_Node content.xml" diff --git "a/examples/Tre\303\250 v\303\256ew.json" "b/examples/Tre\303\250 v\303\256ew.json" new file mode 100644 index 0000000..9857ac3 --- /dev/null +++ "b/examples/Tre\303\250 v\303\256ew.json" @@ -0,0 +1,15 @@ +{ +"Name": "QuickForm", +"Authors": + {"french" : {"old": "Pièrre", "new": "Flôrent"}, + "english" : [ + {"Brit" : ["John", "Andrew"]}, + {"US" : [ + "Tim", + {"William" : ["Will","Bill"]} + ] + } + ] + }, +"Python": {"old": "2", "new": "3"} +} diff --git "a/examples/Tre\303\250 v\303\256ew.xml" "b/examples/Tre\303\250 v\303\256ew.xml" new file mode 100644 index 0000000..7dfcc28 --- /dev/null +++ "b/examples/Tre\303\250 v\303\256ew.xml" @@ -0,0 +1,2 @@ + +QuîckFormPièrreFlôrentJohnAndrewTimWillBill23 diff --git "a/examples/Tre\303\250 v\303\256ew_Node content.json" "b/examples/Tre\303\250 v\303\256ew_Node content.json" deleted file mode 100644 index 9857ac3..0000000 --- "a/examples/Tre\303\250 v\303\256ew_Node content.json" +++ /dev/null @@ -1,15 +0,0 @@ -{ -"Name": "QuickForm", -"Authors": - {"french" : {"old": "Pièrre", "new": "Flôrent"}, - "english" : [ - {"Brit" : ["John", "Andrew"]}, - {"US" : [ - "Tim", - {"William" : ["Will","Bill"]} - ] - } - ] - }, -"Python": {"old": "2", "new": "3"} -} diff --git "a/examples/Tre\303\250 v\303\256ew_Node content.json" "b/examples/Tre\303\250 v\303\256ew_Node content.json" new file mode 120000 index 0000000..f851fe2 --- /dev/null +++ "b/examples/Tre\303\250 v\303\256ew_Node content.json" @@ -0,0 +1 @@ +Treè vîew.json \ No newline at end of file diff --git "a/examples/Tre\303\250 v\303\256ew_Node content.xml" "b/examples/Tre\303\250 v\303\256ew_Node content.xml" deleted file mode 100644 index 7dfcc28..0000000 --- "a/examples/Tre\303\250 v\303\256ew_Node content.xml" +++ /dev/null @@ -1,2 +0,0 @@ - -QuîckFormPièrreFlôrentJohnAndrewTimWillBill23 diff --git "a/examples/Tre\303\250 v\303\256ew_Node content.xml" "b/examples/Tre\303\250 v\303\256ew_Node content.xml" new file mode 120000 index 0000000..e1d26e6 --- /dev/null +++ "b/examples/Tre\303\250 v\303\256ew_Node content.xml" @@ -0,0 +1 @@ +Treè vîew.xml \ No newline at end of file diff --git a/examples/tree.py b/examples/tree.py index d1d86ac..63e8985 100644 --- a/examples/tree.py +++ b/examples/tree.py @@ -25,8 +25,12 @@ "Python": ["2", "3"] }), (None, 'JSON tree:'), + (None, u'Treè vîew.json'), + (None, 'JSON tree + content:'), (None, u'Treè vîew_Node content.json'), (None, 'XML tree:'), + (None, u'Treè vîew.xml'), + (None, 'XML tree + content:'), (None, u'Treè vîew_Node content.xml') ] diff --git a/formlayout.py b/formlayout.py index d70fb6c..5ac81e4 100644 --- a/formlayout.py +++ b/formlayout.py @@ -362,14 +362,15 @@ def apply(self, callback): class DictTreeModel(QStandardItemModel): - def __init__(self, data, header=None, parent=None): + def __init__(self, data, header=[], parent=None): QStandardItemModel.__init__(self, parent) self.ficon = qApp.style().standardIcon(QStyle.SP_FileIcon) self.dicon = qApp.style().standardIcon(QStyle.SP_DirIcon) self.columns = False - if header: - self.columns = True + if len(header) > 0: self.setHorizontalHeaderLabels(header) + if len(header) > 1: + self.columns = True parent = self.invisibleRootItem() self.add(data, parent) @@ -418,14 +419,15 @@ def addvalue(self, parent): class XMLTreeModel(QStandardItemModel): - def __init__(self, xmldata, header=None, parent=None): + def __init__(self, xmldata, header=[], parent=None): QStandardItemModel.__init__(self, parent) self.ficon = qApp.style().standardIcon(QStyle.SP_FileIcon) self.dicon = qApp.style().standardIcon(QStyle.SP_DirIcon) self.columns = False - if header: - self.columns = True + if len(header) > 0: self.setHorizontalHeaderLabels(header) + if len(header) > 1: + self.columns = True parent = self.invisibleRootItem() root = xmldata.getroot() self.add(root, parent) @@ -640,7 +642,7 @@ def setup(self): if '_' in value: header = value[:-5].split('_') else: - header = [value[:-5], 'Content'] + header = [value[:-5]] treemodel = DictTreeModel(jsondata, header) tree = QTreeView() tree.setModel(treemodel) @@ -655,7 +657,7 @@ def setup(self): if '_' in value: header = value[:-4].split('_') else: - header = [value[:-4], 'Content'] + header = [value[:-4]] treemodel = XMLTreeModel(xmldata, header) tree = QTreeView() tree.setModel(treemodel) From 856192493e62306e57d67fc74ae911c50a8b3493 Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Wed, 6 Jul 2016 03:07:55 +0200 Subject: [PATCH 14/15] Simplify DictTree model code --- formlayout.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/formlayout.py b/formlayout.py index 5ac81e4..34e8faa 100644 --- a/formlayout.py +++ b/formlayout.py @@ -395,24 +395,23 @@ def add(self, data, parent): parent.appendRow(item) def value(self): - ret, parent = {}, self.invisibleRootItem() - for i in range(parent.rowCount()): - child = parent.child(i) - key = to_text_string(child.text()) - ret[key] = self.addvalue(child) - return ret + parent = self.invisibleRootItem() + return self.addvalue(parent) def addvalue(self, parent): - children = [] + children, ret = [], {} for i in range(parent.rowCount()): child = parent.child(i) if child.hasChildren(): - ret, key = {}, to_text_string(child.text()) + key = to_text_string(child.text()) ret[key] = self.addvalue(child) - children.append(ret) else: children.append(to_text_string(child.text())) - if len(children) == 1: + if ret and not children: + return ret + elif ret: + return children + [ret] + elif len(children) == 1: return children[0] else: return children From 61357da0ac2e39f401b72490959c8f257a8119fa Mon Sep 17 00:00:00 2001 From: Florent Gallaire Date: Wed, 3 Aug 2016 01:16:10 +0200 Subject: [PATCH 15/15] Fix default encoding with Python 3 --- formlayout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/formlayout.py b/formlayout.py index 34e8faa..0619d75 100644 --- a/formlayout.py +++ b/formlayout.py @@ -633,9 +633,9 @@ def setup(self): self.formlayout.addRow(lab) elif value.endswith('.json'): # JSON file - import json + import json, io from collections import OrderedDict - jsonfile = open(value, 'r') + jsonfile = io.open(value, 'r', encoding='utf-8') jsondata = json.load(jsonfile, object_pairs_hook=OrderedDict) if '_' in value: