diff --git a/Server/config_editor.py b/Server/config_editor.py index 2ace49f..ca488a2 100644 --- a/Server/config_editor.py +++ b/Server/config_editor.py @@ -13,7 +13,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_config_dialog(object): def setupUi(self, config_dialog): config_dialog.setObjectName("config_dialog") - config_dialog.resize(317, 247) + config_dialog.resize(600, 700) config_dialog.setModal(False) self.gridLayout = QtWidgets.QGridLayout(config_dialog) self.gridLayout.setObjectName("gridLayout") diff --git a/Server/config_editor.ui b/Server/config_editor.ui index a65b2b1..e76c48f 100644 --- a/Server/config_editor.ui +++ b/Server/config_editor.ui @@ -6,8 +6,8 @@ 0 0 - 317 - 247 + 310 + 399 @@ -17,22 +17,9 @@ false - - - - + - - - Delete - - - Del - - - - Restart @@ -42,7 +29,7 @@ - + Qt::Horizontal @@ -57,6 +44,54 @@ + + + + + + + + + Delete + + + Del + + + + + + + Add option + + + + + + + Add section + + + Ctrl+A + + + + + + + Mark for deletion + + + + + + + + + Qt::Horizontal + + + diff --git a/Server/config_editor_models.py b/Server/config_editor_models.py index 47f3a65..179eb05 100644 --- a/Server/config_editor_models.py +++ b/Server/config_editor_models.py @@ -1,13 +1,20 @@ +from copy import deepcopy + +import pickle + import config_editor from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import Qt as Qt +from PyQt5.QtGui import QCursor, QStandardItemModel +from PyQt5.QtWidgets import QAbstractItemView, QTreeView, QMenu class ConfigModelItem: - def __init__(self, label, value="", is_section=False, parent=None): + def __init__(self, label, value="", is_section=False, state='default', parent=None): self.itemData = [label, value] + self.is_section = is_section + self.state = state - self.is_section=is_section self.childItems = [] self.parentItem = parent @@ -18,6 +25,19 @@ class ConfigModelItem: self.childItems.append(item) item.parentItem = self + def addChildren(self, items, row): + if row == -1: + self.childItems.extend(items) + else: + #row -= 1 + print('row', row) + self.childItems[row:row] = items + + print(self.childItems) + + for item in items: + item.parentItem = self + def child(self, row): return self.childItems[row] @@ -53,11 +73,21 @@ class ConfigModelItem: def removeChild(self, position): if position < 0 or position > len(self.childItems): return False - + print('removing', position) child = self.childItems.pop(position) child.parentItem = None return True + def removeChildren(self, row, count): + print(range(row, row+count)) + for pos in range(row, row+count): + self.removeChild(pos) + + return True + + def __repr__(self): + return str(self.itemData) + class ConfigModel(QtCore.QAbstractItemModel): def __init__(self, data, parent=None): @@ -88,11 +118,7 @@ class ConfigModel(QtCore.QAbstractItemModel): if not self.hasIndex(row, column, parent): return QtCore.QModelIndex() - if not parent.isValid(): - parentItem = self.rootItem - else: - parentItem = parent.internalPointer() - + parentItem = self.nodeFromIndex(parent) childItem = parentItem.child(row) if childItem: @@ -112,6 +138,11 @@ class ConfigModel(QtCore.QAbstractItemModel): return self.createIndex(parentItem.row(), 0, parentItem) + def nodeFromIndex(self, index): + if index.isValid(): + return index.internalPointer() + return self.rootItem + def data(self, index, role): if not index.isValid(): return None @@ -138,31 +169,86 @@ class ConfigModel(QtCore.QAbstractItemModel): def flags(self, index): if not index.isValid(): - return Qt.NoItemFlags + return QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled # Qt.NoItemFlags item = index.internalPointer() flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable + if index.column() == 0: + flags |= int(QtCore.Qt.ItemIsDragEnabled) + if item.is_section: + flags |= int(QtCore.Qt.ItemIsDropEnabled) + if index.column() == 1 and not item.is_section: flags |= Qt.ItemIsEditable return flags + def supportedDropActions(self): + return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction + + def mimeTypes(self): + return ['bstream', 'text/xml'] + + def mimeData(self, indexes): + mimedata = QtCore.QMimeData() + index = indexes[0] + mimedata.setData('bstream', pickle.dumps(self.nodeFromIndex(index))) + return mimedata + + def dropMimeData(self, mimedata, action, row, column, parentIndex): + print(action) + print('mim', row) + if action == Qt.IgnoreAction: + return True + + parentNode = self.nodeFromIndex(parentIndex) + droppedNode = deepcopy(pickle.loads(mimedata.data('bstream'))) + print(droppedNode.itemData, 'node') + #droppedNode = pickle.loads(mimedata.data('bstream')) # + #self.removeRow()#self.index(row, column, parentIndex))#parentNode.child(row)) + self.insertItems(row, [droppedNode], parentIndex) + self.dataChanged.emit(parentIndex, parentIndex) + + return True + + def removeRows1(self, row, count, parent): + print('rem', row, count) + self.beginRemoveRows(parent, row, row+count-1) + parentItem = self.nodeFromIndex(parent) + print(parentItem, parentItem.itemData) + + #parentItem.removeChild(row) + parentItem.removeChildren(row, count) + print(parentItem.childItems) + + self.endRemoveRows() + print('removed') + return True + @QtCore.pyqtSlot() def removeRow(self, index): parent = index.parent() self.beginRemoveRows(parent, index.row(), index.row()) - if not parent.isValid(): - parentNode = self.rootItem - else: - parentNode = parent.internalPointer() - - parentNode.removeChild(index.row()) + parentItem = self.nodeFromIndex(parent) + parentItem.removeChild(index.row()) self.endRemoveRows() return True + def insertItems(self, row, items, parentIndex): + print('ins', row) + parent = self.nodeFromIndex(parentIndex) + self.beginInsertRows(parentIndex, row, row+len(items)-1) + + parent.addChildren(items, row) + print(parent.childItems) + + self.endInsertRows() + self.dataChanged.emit(parentIndex, parentIndex) + return True + def setup(self, data: dict, parent=None): if parent is None: parent = self.rootItem @@ -174,19 +260,23 @@ class ConfigModel(QtCore.QAbstractItemModel): else: parent.appendChild(ConfigModelItem(key, value)) - def to_dict(self): # TODO recursive - d = {} - for section in self.rootItem.childItems: - section_d = {} - section_name, _ = section.itemData + def to_dict(self, parent=None) -> dict: + if parent is None: + parent = self.rootItem - for item in section.childItems: - option, value = item.itemData - section_d[option] = value + data = {} + for item in parent.childItems: + item_name, item_data = item.itemData + if item.childItems: + data[item_name] = self.to_dict(item) + else: + data[item_name] = item_data - d[section_name] = section_d + return data - return d + @property + def dict(self): + return self.to_dict() class ConfigDialog(config_editor.Ui_config_dialog): @@ -197,17 +287,59 @@ class ConfigDialog(config_editor.Ui_config_dialog): def setupUi(self, config_dialog): super(ConfigDialog, self).setupUi(config_dialog) + #self.config_view = Tree() + + self.config_view = Tree() + self.config_view.setObjectName("config_view") self.config_view.setModel(self.model) + self.gridLayout.addWidget(self.config_view, 0, 0, 1, 1) + self.config_view.expandAll() + #self.config_view.setDragDropMode(True) + #self.setDragDropMode(QAbstractItemView.InternalMove) + #self.setDragEnabled(True) + #self.setAcceptDrops(True) + #self.setDropIndicatorShown(True) self.delete_button.pressed.connect(self.remove_selected) def remove_selected(self): index = self.config_view.selectedIndexes()[0] - self.model.removeRow(index) + self.model.removeRow(index)\ - #print(self.model.to_dict()) +class Tree(QTreeView): + def __init__(self): + QTreeView.__init__(self) + data = {"section 1": {"opt1": "str", "opt2": 123, "opt3": 1.23, "opt4": False, "...": {'subopt': 'bal'}}, + "section 2": {"opt1": "str", "opt2": [1.1, 2.3, 34], "opt3": 1.23, "opt4": False, "...": ""}} + #model = ConfigModel(data) + + #self.setModel(model) + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.customContextMenuRequested.connect(self.open_menu) + + self.setSelectionMode(self.SingleSelection) + self.setDragDropMode(QAbstractItemView.InternalMove) + self.setDragEnabled(True) + self.setAcceptDrops(True) + self.setDropIndicatorShown(True) + + # def dropEvent(self, e): + # print(e.dropAction()==QtCore.Qt.MoveAction) + # if e.keyboardModifiers() & QtCore.Qt.AltModifier: + # e.setDropAction() + # print('copy') + # else: + # e.setDropAction(QtCore.Qt.MoveAction) + # print("drop") + # print(e) + # e.accept() + + def open_menu(self): + menu = QMenu() + menu.addAction("Create new folder") + menu.exec_(QCursor.pos()) if __name__ == '__main__': import sys @@ -221,13 +353,13 @@ if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) Dialog = QtWidgets.QDialog() - data = {"section 1": {"opt1": "str", "opt2": 123, "opt3": 1.23, "opt4": False, "...": {'subopt': 'bal'}}, - "section 2": {"opt1": "str", "opt2": [1.1, 2.3, 34], "opt3": 1.23, "opt4": False, "...": ""}} + data = {"section 1": {"opt1": "str", "opt2": 123, "opt3": 1.23, "opt4": False, }}#"...": {'subopt': 'bal'}},} + #"section 2": {"opt1": "str", "opt2": [1.1, 2.3, 34], "opt3": 1.23, "opt4": False, "...": ""}} ui = ConfigDialog(data) ui.setupUi(Dialog) - + print(Qt.DisplayRole) Dialog.show() print(app.exec_()) diff --git a/requirements.txt b/requirements.txt index 728753f..c991080 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ +configobj indexed.py==0.0.1 -numpy==1.16.4 -PyQt5==5.13.0 -PyQt5-sip==4.19.18 +numpy==1.17.4 +PyQt5==5.13.2 +PyQt5-sip==12.7.0 selectors2==2.0.1