mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-06-17 10:24:34 +12:00
Adds: drag and drop
This commit is contained in:
parent
a3b9a8597e
commit
215a29d325
|
@ -64,6 +64,8 @@ def loadStandardItemModelXML(mdl, xml):
|
||||||
for l in root.find("header").find("vertical").findall("label"):
|
for l in root.find("header").find("vertical").findall("label"):
|
||||||
vLabels.append(l.attrib["text"])
|
vLabels.append(l.attrib["text"])
|
||||||
|
|
||||||
|
#print(root.find("header").find("vertical").text)
|
||||||
|
|
||||||
mdl.setVerticalHeaderLabels(vLabels)
|
mdl.setVerticalHeaderLabels(vLabels)
|
||||||
mdl.setHorizontalHeaderLabels(hLabels)
|
mdl.setHorizontalHeaderLabels(hLabels)
|
||||||
|
|
||||||
|
|
|
@ -143,14 +143,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.treePlanOutline.hideColumn(c)
|
self.treePlanOutline.hideColumn(c)
|
||||||
self.btnRedacAddFolder.clicked.connect(lambda: self.outlineAddItem("folder"))
|
self.btnRedacAddFolder.clicked.connect(lambda: self.outlineAddItem("folder"))
|
||||||
self.btnRedacAddScene.clicked.connect(lambda: self.outlineAddItem("scene"))
|
self.btnRedacAddScene.clicked.connect(lambda: self.outlineAddItem("scene"))
|
||||||
self.btnRedacRemoveItem.clicked.connect(self.outlineRemoveItem)
|
self.btnRedacRemoveItem.clicked.connect(self.outlineRemoveItems)
|
||||||
|
|
||||||
#Debug
|
#Debug
|
||||||
self.mdlFlatData.setVerticalHeaderLabels(["Infos générales", "Summary"])
|
self.mdlFlatData.setVerticalHeaderLabels(["Infos générales", "Summary"])
|
||||||
self.tblDebugFlatData.setModel(self.mdlFlatData)
|
self.tblDebugFlatData.setModel(self.mdlFlatData)
|
||||||
self.tblDebugPersos.setModel(self.mdlPersos)
|
self.tblDebugPersos.setModel(self.mdlPersos)
|
||||||
self.tblDebugPersosInfos.setModel(self.mdlPersosInfos)
|
self.tblDebugPersosInfos.setModel(self.mdlPersosInfos)
|
||||||
self.treeDebugOutline.setModel(self.mdlOutline)
|
self.treeDebugOutline.setModel(self.mdlOutline)
|
||||||
|
self.btnRedacPreview.clicked.connect(self.mdlOutline.saveToXML)
|
||||||
|
|
||||||
self.loadProject("test_project")
|
self.loadProject("test_project")
|
||||||
|
|
||||||
|
@ -161,11 +162,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
def outlineAddItem(self, type="folder"):
|
def outlineAddItem(self, type="folder"):
|
||||||
currentIndex = self.treeRedacOutline.currentIndex()
|
currentIndex = self.treeRedacOutline.currentIndex()
|
||||||
item = outlineItem("Nouveau", type)
|
item = outlineItem("Nouveau", type)
|
||||||
self.mdlOutline.appendRow(item, currentIndex)
|
self.mdlOutline.appendItem(item, currentIndex)
|
||||||
|
|
||||||
def outlineRemoveItem(self):
|
def outlineRemoveItems(self):
|
||||||
currentIndex = self.treeRedacOutline.currentIndex()
|
for idx in self.treeRedacOutline.selectedIndexes():
|
||||||
self.mdlOutline.removeIndex(currentIndex)
|
if idx.isValid():
|
||||||
|
self.mdlOutline.removeIndex(idx)
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
|
@ -7,6 +7,7 @@ from __future__ import unicode_literals
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from lxml import etree as ET
|
||||||
|
|
||||||
class Outline(Enum):
|
class Outline(Enum):
|
||||||
title = 0
|
title = 0
|
||||||
|
@ -24,7 +25,7 @@ class outlineModel(QAbstractItemModel):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QAbstractItemModel.__init__(self)
|
QAbstractItemModel.__init__(self)
|
||||||
|
|
||||||
self.rootItem = outlineItem()
|
self.rootItem = outlineItem("root", "folder")
|
||||||
|
|
||||||
def index(self, row, column, parent):
|
def index(self, row, column, parent):
|
||||||
|
|
||||||
|
@ -84,14 +85,6 @@ class outlineModel(QAbstractItemModel):
|
||||||
item.setData(index.column(), value)
|
item.setData(index.column(), value)
|
||||||
self.dataChanged.emit(index, index)
|
self.dataChanged.emit(index, index)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
flags = Qt.ItemIsEnabled | Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled
|
|
||||||
|
|
||||||
if index.isValid() and index.internalPointer().isFolder():
|
|
||||||
flags |= Qt.ItemIsDropEnabled
|
|
||||||
|
|
||||||
return flags
|
|
||||||
|
|
||||||
|
|
||||||
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
||||||
|
@ -99,6 +92,141 @@ class outlineModel(QAbstractItemModel):
|
||||||
return [i.name for i in Outline][section]
|
return [i.name for i in Outline][section]
|
||||||
else:
|
else:
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
return True
|
||||||
|
|
||||||
|
#################### DRAG AND DROP ########################
|
||||||
|
# http://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
flags = QAbstractItemModel.flags(self, index) | Qt.ItemIsEditable
|
||||||
|
|
||||||
|
if index.isValid() and index.internalPointer().isFolder():
|
||||||
|
flags |= Qt.ItemIsDropEnabled | Qt.ItemIsDragEnabled
|
||||||
|
|
||||||
|
elif index.isValid():
|
||||||
|
flags |= Qt.ItemIsDragEnabled
|
||||||
|
|
||||||
|
else:
|
||||||
|
flags |= Qt.ItemIsDropEnabled
|
||||||
|
|
||||||
|
return flags
|
||||||
|
|
||||||
|
def mimeTypes(self):
|
||||||
|
return ["application/xml"]
|
||||||
|
|
||||||
|
def mimeData(self, indexes):
|
||||||
|
mimeData = QMimeData()
|
||||||
|
#encodedData = QByteArray()
|
||||||
|
#stream = QDataStream(encodedData, QIODevice.WriteOnly)
|
||||||
|
encodedData = ""
|
||||||
|
|
||||||
|
root = ET.Element("outlineItems")
|
||||||
|
for index in indexes:
|
||||||
|
if index.isValid():
|
||||||
|
item = ET.XML(index.internalPointer().toXML())
|
||||||
|
root.append(item)
|
||||||
|
|
||||||
|
encodedData = ET.tostring(root)
|
||||||
|
|
||||||
|
mimeData.setData("application/xml", encodedData)
|
||||||
|
return mimeData
|
||||||
|
|
||||||
|
def supportedDropActions(self):
|
||||||
|
|
||||||
|
return Qt.MoveAction # Qt.CopyAction |
|
||||||
|
return Qt.CopyAction | Qt.MoveAction
|
||||||
|
|
||||||
|
def dropMimeData(self, data, action, row, column, parent):
|
||||||
|
|
||||||
|
if action == Qt.IgnoreAction:
|
||||||
|
return True # What is that?
|
||||||
|
|
||||||
|
if not data.hasFormat("application/xml"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if column > 0:
|
||||||
|
column = 0
|
||||||
|
|
||||||
|
if row <> -1:
|
||||||
|
beginRow = row
|
||||||
|
elif parent.isValid():
|
||||||
|
beginRow = self.rowCount(parent) + 1
|
||||||
|
else:
|
||||||
|
beginRow = self.rowCount() + 1
|
||||||
|
|
||||||
|
encodedData = str(data.data("application/xml"))
|
||||||
|
root = ET.XML(encodedData)
|
||||||
|
|
||||||
|
if root.tag <> "outlineItems":
|
||||||
|
return False
|
||||||
|
|
||||||
|
items = []
|
||||||
|
for child in root:
|
||||||
|
if child.tag == "outlineItem":
|
||||||
|
items.append(outlineItem(xml=ET.tostring(child)))
|
||||||
|
|
||||||
|
if not items:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.insertItems(items, beginRow, parent)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
################# ADDING AND REMOVING #################
|
||||||
|
|
||||||
|
def insertItem(self, item, row, parent=QModelIndex()):
|
||||||
|
return self.insertItems([item], row, parent)
|
||||||
|
|
||||||
|
def insertItems(self, items, row, parent=QModelIndex()):
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
# Insert only if parent is folder
|
||||||
|
if parentItem.isFolder():
|
||||||
|
self.beginInsertRows(parent, row, row + len(items) - 1)
|
||||||
|
|
||||||
|
for i in items:
|
||||||
|
parentItem.insertChild(row + items.index(i), i)
|
||||||
|
|
||||||
|
self.endInsertRows()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def appendItem(self, item, parent=QModelIndex()):
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
# If parent is folder, write into
|
||||||
|
if parentItem.isFolder():
|
||||||
|
self.insertItem(item, self.rowCount(parent), parent)
|
||||||
|
|
||||||
|
# If parent is not folder, write next to
|
||||||
|
else:
|
||||||
|
self.insertItem(item, parent.row()+1, parent.parent())
|
||||||
|
|
||||||
|
def removeIndex(self, index):
|
||||||
|
item = index.internalPointer()
|
||||||
|
self.removeRow(item.row(), index.parent())
|
||||||
|
|
||||||
|
def removeRow(self, row, parent=QModelIndex()):
|
||||||
|
return self.removeRows(row, 1, parent)
|
||||||
|
|
||||||
|
def removeRows(self, row, count, parent=QModelIndex()):
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
self.beginRemoveRows(parent, row, row + count - 1)
|
||||||
|
for i in range(count):
|
||||||
|
parentItem.removeChild(row)
|
||||||
|
|
||||||
|
self.endRemoveRows()
|
||||||
|
return True
|
||||||
|
|
||||||
#def insertRow(self, row, item, parent=QModelIndex()):
|
#def insertRow(self, row, item, parent=QModelIndex()):
|
||||||
#self.beginInsertRows(parent, row, row)
|
#self.beginInsertRows(parent, row, row)
|
||||||
|
@ -112,44 +240,28 @@ class outlineModel(QAbstractItemModel):
|
||||||
|
|
||||||
#self.endInsertRows()
|
#self.endInsertRows()
|
||||||
|
|
||||||
def appendRow(self, item, parent=QModelIndex()):
|
|
||||||
if not parent.isValid():
|
|
||||||
parentItem = self.rootItem
|
|
||||||
else:
|
|
||||||
parentItem = parent.internalPointer()
|
|
||||||
|
|
||||||
if parentItem.isFolder():
|
################# XML #################
|
||||||
self.beginInsertRows(parent, parentItem.childCount(), parentItem.childCount())
|
|
||||||
parentItem.appendChild(item)
|
def saveToXML(self):
|
||||||
self.endInsertRows()
|
root = ET.XML(self.rootItem.toXML())
|
||||||
|
print(ET.tostring(root, pretty_print=True))
|
||||||
def removeIndex(self, index):
|
# FIXME
|
||||||
item = index.internalPointer()
|
|
||||||
self.removeRow(item.row(), 1, index.parent())
|
|
||||||
|
|
||||||
|
|
||||||
def removeRow(self, row, count, parent=QModelIndex()):
|
|
||||||
if not parent.isValid():
|
|
||||||
parentItem = self.rootItem
|
|
||||||
else:
|
|
||||||
parentItem = parent.internalPointer()
|
|
||||||
|
|
||||||
self.beginRemoveRows(parent, row, row)
|
|
||||||
parentItem.removeChild(row)
|
|
||||||
self.endRemoveRows()
|
|
||||||
return True
|
|
||||||
|
|
||||||
class outlineItem():
|
class outlineItem():
|
||||||
def __init__(self, title="", type="folder", parent=None):
|
|
||||||
|
def __init__(self, title="", type="folder", xml=""):
|
||||||
self._parent = parent
|
|
||||||
|
|
||||||
self._data = {}
|
self._data = {}
|
||||||
self.childItems = []
|
self.childItems = []
|
||||||
|
|
||||||
self._data[Outline.title] = title
|
if title: self._data[Outline.title] = title
|
||||||
self._data[Outline.type] = type
|
self._data[Outline.type] = type
|
||||||
|
|
||||||
|
if xml:
|
||||||
|
self.setFromXML(xml)
|
||||||
|
|
||||||
|
|
||||||
def child(self, row):
|
def child(self, row):
|
||||||
return self.childItems[row]
|
return self.childItems[row]
|
||||||
|
@ -165,7 +277,7 @@ class outlineItem():
|
||||||
if Outline(column) in self._data:
|
if Outline(column) in self._data:
|
||||||
return self._data[Outline(column)]
|
return self._data[Outline(column)]
|
||||||
else:
|
else:
|
||||||
return QVariant()
|
return None
|
||||||
elif role == Qt.DecorationRole and column == Outline.title.value:
|
elif role == Qt.DecorationRole and column == Outline.title.value:
|
||||||
if self.isFolder():
|
if self.isFolder():
|
||||||
return QIcon.fromTheme("folder")
|
return QIcon.fromTheme("folder")
|
||||||
|
@ -173,18 +285,18 @@ class outlineItem():
|
||||||
return QIcon.fromTheme("document-new")
|
return QIcon.fromTheme("document-new")
|
||||||
|
|
||||||
def setData(self, column, data):
|
def setData(self, column, data):
|
||||||
self._data[Outline(column)] = data
|
self._data[Outline(column)] = str(data.toString())
|
||||||
|
|
||||||
def row(self):
|
def row(self):
|
||||||
if self.parent:
|
if self.parent:
|
||||||
return self.parent().childItems.index(self)
|
return self.parent().childItems.index(self)
|
||||||
|
|
||||||
def appendChild(self, child):
|
def appendChild(self, child):
|
||||||
self.childItems.append(child)
|
self.insertChild(self.childCount(), child)
|
||||||
child._parent = self
|
|
||||||
|
|
||||||
def insertChild(self, row, child):
|
def insertChild(self, row, child):
|
||||||
self.childItems.insert(row, child)
|
self.childItems.insert(row, child)
|
||||||
|
child._parent = self
|
||||||
|
|
||||||
def removeChild(self, row):
|
def removeChild(self, row):
|
||||||
self.childItems.pop(row)
|
self.childItems.pop(row)
|
||||||
|
@ -196,4 +308,28 @@ class outlineItem():
|
||||||
return self._data[Outline.type] == "folder"
|
return self._data[Outline.type] == "folder"
|
||||||
|
|
||||||
def isScene(self):
|
def isScene(self):
|
||||||
return self._data[Outline.type] == "scene"
|
return self._data[Outline.type] == "scene"
|
||||||
|
|
||||||
|
def toXML(self):
|
||||||
|
item = ET.Element("outlineItem")
|
||||||
|
|
||||||
|
for attrib in Outline:
|
||||||
|
val = self.data(attrib)
|
||||||
|
if val:
|
||||||
|
item.set(attrib.name, val)
|
||||||
|
|
||||||
|
for i in self.childItems:
|
||||||
|
item.append(ET.XML(i.toXML()))
|
||||||
|
|
||||||
|
return ET.tostring(item)
|
||||||
|
|
||||||
|
def setFromXML(self, xml):
|
||||||
|
root = ET.XML(xml)
|
||||||
|
|
||||||
|
for k in root.attrib:
|
||||||
|
if k in Outline.__members__:
|
||||||
|
self._data[Outline.__members__[k]] = root.attrib[k]
|
||||||
|
|
||||||
|
for child in root:
|
||||||
|
item = outlineItem(xml=ET.tostring(child))
|
||||||
|
self.appendChild(item)
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'src/ui/mainWindow.ui'
|
# Form implementation generated from reading ui file 'src/ui/mainWindow.ui'
|
||||||
#
|
#
|
||||||
# Created: Mon Jun 1 23:58:06 2015
|
# Created: Tue Jun 2 13:54:35 2015
|
||||||
# by: PyQt4 UI code generator 4.11.3
|
# by: PyQt4 UI code generator 4.11.3
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
@ -774,6 +774,8 @@ class Ui_MainWindow(object):
|
||||||
self.verticalLayout_19.setObjectName(_fromUtf8("verticalLayout_19"))
|
self.verticalLayout_19.setObjectName(_fromUtf8("verticalLayout_19"))
|
||||||
self.treeRedacOutline = QtGui.QTreeView(self.layoutWidget1)
|
self.treeRedacOutline = QtGui.QTreeView(self.layoutWidget1)
|
||||||
self.treeRedacOutline.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
|
self.treeRedacOutline.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
|
||||||
|
self.treeRedacOutline.setDefaultDropAction(QtCore.Qt.MoveAction)
|
||||||
|
self.treeRedacOutline.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||||
self.treeRedacOutline.setObjectName(_fromUtf8("treeRedacOutline"))
|
self.treeRedacOutline.setObjectName(_fromUtf8("treeRedacOutline"))
|
||||||
self.verticalLayout_19.addWidget(self.treeRedacOutline)
|
self.verticalLayout_19.addWidget(self.treeRedacOutline)
|
||||||
self.horizontalLayout_31 = QtGui.QHBoxLayout()
|
self.horizontalLayout_31 = QtGui.QHBoxLayout()
|
||||||
|
@ -798,6 +800,12 @@ class Ui_MainWindow(object):
|
||||||
self.horizontalLayout_31.addWidget(self.btnRedacRemoveItem)
|
self.horizontalLayout_31.addWidget(self.btnRedacRemoveItem)
|
||||||
spacerItem9 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
spacerItem9 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||||
self.horizontalLayout_31.addItem(spacerItem9)
|
self.horizontalLayout_31.addItem(spacerItem9)
|
||||||
|
self.btnRedacPreview = QtGui.QPushButton(self.layoutWidget1)
|
||||||
|
self.btnRedacPreview.setText(_fromUtf8(""))
|
||||||
|
icon = QtGui.QIcon.fromTheme(_fromUtf8("document-print"))
|
||||||
|
self.btnRedacPreview.setIcon(icon)
|
||||||
|
self.btnRedacPreview.setObjectName(_fromUtf8("btnRedacPreview"))
|
||||||
|
self.horizontalLayout_31.addWidget(self.btnRedacPreview)
|
||||||
self.verticalLayout_19.addLayout(self.horizontalLayout_31)
|
self.verticalLayout_19.addLayout(self.horizontalLayout_31)
|
||||||
self.layoutWidget2 = QtGui.QWidget(self.splitterRedac)
|
self.layoutWidget2 = QtGui.QWidget(self.splitterRedac)
|
||||||
self.layoutWidget2.setObjectName(_fromUtf8("layoutWidget2"))
|
self.layoutWidget2.setObjectName(_fromUtf8("layoutWidget2"))
|
||||||
|
|
|
@ -1452,6 +1452,12 @@
|
||||||
<property name="dragDropMode">
|
<property name="dragDropMode">
|
||||||
<enum>QAbstractItemView::DragDrop</enum>
|
<enum>QAbstractItemView::DragDrop</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="defaultDropAction">
|
||||||
|
<enum>Qt::MoveAction</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -1505,6 +1511,16 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnRedacPreview">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-print"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
Loading…
Reference in a new issue