librarymodel progress

This commit is contained in:
olari
2021-06-12 18:58:10 +03:00
parent 1c24573b34
commit 904e3ca57e

257
main.py
View File

@@ -1,13 +1,19 @@
import sys
import json import json
import sys
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
from PySide2.QtCore import QAbstractItemModel, QModelIndex, QObject, QUrl, Qt, Signal, Slot from PySide2.QtCore import (
from PySide2.QtGui import QIcon, QImage, QPicture, QPixmap QAbstractItemModel,
from PySide2.QtWebChannel import QWebChannel QModelIndex,
from PySide2.QtWebEngineWidgets import QWebEngineView QObject,
QUrl,
Qt,
Signal,
Slot,
)
from PySide2.QtWidgets import ( from PySide2.QtWidgets import (
QApplication, QApplication,
QDockWidget, QDockWidget,
@@ -16,15 +22,22 @@ from PySide2.QtWidgets import (
QPushButton, QPushButton,
QTreeView, QTreeView,
QVBoxLayout, QVBoxLayout,
QWidget QWidget,
) )
from PySide2.QtGui import QIcon, QImage, QPixmap
from PySide2.QtWebChannel import QWebChannel
from PySide2.QtWebEngineWidgets import QWebEngineView
def qurl_from_local(fpath): def qurl_from_local(fpath):
return QUrl.fromLocalFile(str(Path(fpath).absolute())) return QUrl.fromLocalFile(str(Path(fpath).absolute()))
def file_url_from_local(fpath): def file_url_from_local(fpath):
return f'file://{Path(fpath).absolute()}' return f"file://{Path(fpath).absolute()}"
class Bridge(QObject): class Bridge(QObject):
@Slot(str, result=str) @Slot(str, result=str)
def call_python(self, data): def call_python(self, data):
@@ -32,11 +45,12 @@ class Bridge(QObject):
call_javascript = Signal(str) call_javascript = Signal(str)
@dataclass @dataclass
class TreeItem: class TreeItem:
name: str name: str = "Untitled"
parent: "TreeItem" parent: "TreeItem" = None
children: list["TreeItem"] children: list["TreeItem"] = []
def row(self): def row(self):
return self.parent.children.index(self) if self.parent else 0 return self.parent.children.index(self) if self.parent else 0
@@ -50,14 +64,54 @@ class TreeItem:
item.children.append(TreeItem.load(child, item)) item.children.append(TreeItem.load(child, item))
return item return item
class LibraryModel(QAbstractItemModel): class LibraryModel(QAbstractItemModel):
UNTITLED_NODE_NAME = "Untitled"
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.root = TreeItem.load( self.root = TreeItem.load(["root", [["first", [["second", [["third", []]]]]]]])
['root', [
['first', [ def index(self, row: int, column: int, parent=QModelIndex()) -> QModelIndex:
['second', [ if not self.hasIndex(row, column, parent):
['third', []]]]]]]]) return QModelIndex()
parent_item = parent.internalPointer() if parent.isValid() else self.root
if len(parent_item.children) > row:
return self.createIndex(row, column, parent_item.children[row])
return QModelIndex()
def parent(self, index: QModelIndex) -> QModelIndex:
if not index.isValid():
return QModelIndex()
child_item = index.internalPointer()
parent_item = child_item.parent
if parent_item == self.root:
return QModelIndex()
return self.createIndex(parent_item.row(), 0, parent_item)
def flags(self, index: QModelIndex) -> Qt.ItemFlags:
if index.isValid():
return (
Qt.ItemIsEnabled
| Qt.ItemIsSelectable
| Qt.ItemIsDragEnabled
| Qt.ItemIsDropEnabled
)
else:
return Qt.ItemIsEnabled
def rowCount(self, parent=QModelIndex()):
parent_item = parent.internalPointer() if parent.isValid() else self.root
return len(parent_item.children)
def columnCount(self, parent=QModelIndex()):
return 1
def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> Any: def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> Any:
if not index.isValid(): if not index.isValid():
@@ -68,20 +122,9 @@ class LibraryModel(QAbstractItemModel):
return item.name return item.name
elif role == Qt.DecorationRole: elif role == Qt.DecorationRole:
img = QImage() img = QImage()
img.load('test.png') img.load("test.png")
return QIcon(QPixmap.fromImage(img)) return QIcon(QPixmap.fromImage(img))
def insertRows(self, row: int, count: int, parent: QModelIndex) -> bool:
item: TreeItem = parent.internalPointer()
self.beginInsertRows(parent, row, row)
item.children.insert(row, TreeItem('', item, []))
self.endInsertRows()
return True
def setData(self, index: QModelIndex, value: str, role: Qt.ItemDataRole): def setData(self, index: QModelIndex, value: str, role: Qt.ItemDataRole):
if not index.isValid(): if not index.isValid():
return False return False
@@ -93,73 +136,41 @@ class LibraryModel(QAbstractItemModel):
return True return True
def index(self, row: int, column: int, parent=QModelIndex()) -> QModelIndex: def insertRows(self, row: int, count: int, parent: QModelIndex) -> bool:
if not self.hasIndex(row, column, parent): item: TreeItem = parent.internalPointer() or self.root
return QModelIndex() self.beginInsertRows(parent, row, row + count)
item.children.insert(row, TreeItem(LibraryModel.UNTITLED_NODE_NAME, item, []))
self.endInsertRows()
return True
if not parent.isValid(): def removeRows(self, row: int, count: int, parent: QModelIndex) -> bool:
parentItem = self.root item: TreeItem = parent.internalPointer() or self.root
else: self.beginRemoveRows(parent, row, row + count)
parentItem = parent.internalPointer() del item.children[row]
self.endRemoveRows()
return True
if len(parentItem.children) > row: def supportedDragActions(self) -> Qt.DropActions:
return self.createIndex(row, column, parentItem.children[row]) return Qt.CopyAction | Qt.MoveAction
else:
return QModelIndex()
def parent(self, index: QModelIndex) -> QModelIndex: def supportedDropActions(self) -> Qt.DropActions:
if not index.isValid(): return Qt.CopyAction | Qt.MoveAction
return QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.parent
if parentItem == self.root:
return QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent=QModelIndex()):
if not parent.isValid():
parentItem = self.root
else:
parentItem = parent.internalPointer()
return len(parentItem.children)
def columnCount(self, parent=QModelIndex()):
return 1
def flags(self, index: QModelIndex) -> Qt.ItemFlags:
flags = super().flags(index)
return Qt.ItemIsEditable | flags
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.widget = QWidget() self.widget = QWidget()
self.setCentralWidget(self.widget) self.setCentralWidget(self.widget)
self._layout = QVBoxLayout() self._layout = QVBoxLayout()
self.widget.setLayout(self._layout) self.widget.setLayout(self._layout)
self.web_view = QWebEngineView() self.web_view = QWebEngineView()
self._layout.addWidget(self.web_view) self._layout.addWidget(self.web_view)
self.library_model = LibraryModel()
self.library_view = QTreeView()
self.library_view.setHeaderHidden(True)
self.library_view.setModel(self.library_model)
def on_insert_row(p: QModelIndex, f, l): self.dock_widget = QDockWidget("Library")
self.library_view.setExpanded(p, True)
self.library_view.edit(p.child(f, 0))
self.library_model.rowsInserted.connect(on_insert_row)
self.dock_widget = QDockWidget('Library')
self.dock_qwidget = QWidget() self.dock_qwidget = QWidget()
self.dock_widget.setWidget(self.dock_qwidget) self.dock_widget.setWidget(self.dock_qwidget)
@@ -167,55 +178,88 @@ class MainWindow(QMainWindow):
self.dock_layout = QVBoxLayout() self.dock_layout = QVBoxLayout()
self.dock_qwidget.setLayout(self.dock_layout) self.dock_qwidget.setLayout(self.dock_layout)
self.new_node = QPushButton("New node") self.library_model = LibraryModel()
self.library_view = QTreeView()
self.dock_layout.addWidget(self.library_view) self.dock_layout.addWidget(self.library_view)
self.library_view.setModel(self.library_model)
self.library_view.setDragEnabled(True)
self.library_view.setAcceptDrops(True)
self.library_view.setDefaultDropAction(Qt.MoveAction)
self.library_view.setHeaderHidden(True)
def on_insert_row(p: QModelIndex, f, l):
self.library_view.setExpanded(p, True)
self.library_view.edit(p.child(f, 0))
self.library_model.rowsInserted.connect(on_insert_row)
self.new_node = QPushButton("New node")
self.dock_layout.addWidget(self.new_node) self.dock_layout.addWidget(self.new_node)
self.new_node.clicked.connect(lambda: self.new_node.clicked.connect(
self.library_model.insertRow(0, self.library_view.currentIndex()) lambda: self.library_model.insertRow(0, self.library_view.currentIndex())
) )
self.delete_node = QPushButton("Delete node")
self.dock_layout.addWidget(self.delete_node)
self.delete_node.clicked.connect(
lambda: self.library_model.removeRow(
self.library_view.currentIndex().row(),
self.library_view.currentIndex().parent(),
)
)
self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_widget) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_widget)
self.web_view.load(qurl_from_local('pdf.js/build/generic/web/viewer.html')) self.web_view.load(qurl_from_local("pdf.js/build/generic/web/viewer.html"))
def on_load(): def on_load():
def load_javascript_file(filepath): def load_javascript_file(filepath):
self.web_view.page().runJavaScript( self.web_view.page().runJavaScript(
'var s = document.createElement("script");' 'var s = document.createElement("script");'
f's.src="{filepath}";' f's.src="{filepath}";'
'document.body.appendChild(s);' "document.body.appendChild(s);"
) )
load_javascript_file('qrc:///qtwebchannel/qwebchannel.js') load_javascript_file("qrc:///qtwebchannel/qwebchannel.js")
load_javascript_file(file_url_from_local('controller.js')) load_javascript_file(file_url_from_local("controller.js"))
self.web_view.loadFinished.connect(on_load) self.web_view.loadFinished.connect(on_load)
self.channel = QWebChannel() self.channel = QWebChannel()
self.web_view.page().setWebChannel(self.channel) self.web_view.page().setWebChannel(self.channel)
self.bridge = Bridge() self.bridge = Bridge()
self.channel.registerObject('bridge', self.bridge) self.channel.registerObject("bridge", self.bridge)
def on_command(command): def on_command(command):
if command['type'] == 'ready': if command["type"] == "ready":
print('webchannel ready') print("webchannel ready")
self.bridge.handler = on_command self.bridge.handler = on_command
def call_javascript(command): def call_javascript(command):
self.bridge.call_javascript.emit(json.dumps(command)) self.bridge.call_javascript.emit(json.dumps(command))
self.button = QPushButton('Load PDF') self.button = QPushButton("Load PDF")
self._layout.addWidget(self.button) self._layout.addWidget(self.button)
self.button.clicked.connect(lambda: self.button.clicked.connect(
call_javascript({'type': 'load_pdf', 'url': file_url_from_local(QFileDialog.getOpenFileName()[0])})) lambda: call_javascript(
{
"type": "load_pdf",
"url": file_url_from_local(QFileDialog.getOpenFileName()[0]),
}
)
)
def main(): def main():
app = QApplication() app = QApplication()
window = MainWindow() window = MainWindow()
availableGeometry = app.desktop().availableGeometry(window) availableGeometry = app.desktop().availableGeometry(window)
@@ -225,5 +269,6 @@ def main():
sys.exit(app.exec_()) sys.exit(app.exec_())
if __name__ == '__main__':
main() if __name__ == "__main__":
main()