manuskript/manuskript/models/worldModel.py
2017-11-14 14:56:11 +01:00

283 lines
9.1 KiB
Python

#!/usr/bin/env python
# --!-- coding: utf8 --!--
from PyQt5.QtCore import QModelIndex
from PyQt5.QtCore import QSize
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItem, QBrush, QFontMetrics
from PyQt5.QtGui import QStandardItemModel, QColor
from PyQt5.QtWidgets import QMenu, QAction, qApp
from manuskript.enums import World
from manuskript.functions import mainWindow
from manuskript.ui import style as S
class worldModel(QStandardItemModel):
def __init__(self, parent):
QStandardItemModel.__init__(self, 0, 3, parent)
self.mw = mainWindow()
###############################################################################
# SELECTION
###############################################################################
def selectedItem(self):
"""Returns the item selected in mw.treeWorld. invisibleRootItem if None."""
index = self.selectedIndex()
item = self.itemFromIndex(index)
if item:
return item
else:
return self.invisibleRootItem()
def selectedIndex(self):
"""Returns the selected index in the treeView."""
if self.mw.treeWorld.selectedIndexes():
return self.mw.treeWorld.currentIndex()
else:
return QModelIndex()
def selectedIndexes(self):
return self.mw.treeWorld.selectedIndexes()
###############################################################################
# GETTERS
###############################################################################
def ID(self, index):
"""Returns the ID of the given index."""
index = index.sibling(index.row(), World.ID.value)
return self.data(index)
def name(self, index):
"""Returns the name of the given index."""
index = index.sibling(index.row(), World.name.value)
return self.data(index)
def description(self, index):
index = index.sibling(index.row(), World.description.value)
return self.data(index)
def conflict(self, index):
index = index.sibling(index.row(), World.conflict.value)
return self.data(index)
def passion(self, index):
index = index.sibling(index.row(), World.passion.value)
return self.data(index)
def itemID(self, item):
"""Returns the ID of the given item."""
index = self.indexFromItem(item)
return self.ID(index)
def children(self, item):
"""Returns a list of all item's children."""
c = []
for i in range(item.rowCount()):
c.append(item.child(i))
return c
def listAll(self):
"""Returns a list of tupple ``(name, ID, path)`` for all items."""
lst = []
def readAll(item):
name = item.text()
ID = self.itemID(item)
path = self.path(item)
if name and ID:
lst.append((name, ID, path))
for c in self.children(item):
readAll(c)
readAll(self.invisibleRootItem())
return lst
def indexByID(self, ID):
"""Returns the index of item whose ID is ID."""
return self.indexFromItem(self.itemByID(ID))
def itemByID(self, ID):
"""Returns the item whose ID is ID."""
def browse(item):
if self.itemID(item) == ID:
return item
for c in self.children(item):
r = browse(c)
if r:
return r
r = browse(self.invisibleRootItem())
return r if r else None
def path(self, item):
"""Returns the path to the item in the form of 'ancestor > ... > grand-parent > parent'."""
path = []
while item.parent():
item = item.parent()
path.append(item.text())
path = " > ".join(path)
return path
###############################################################################
# ADDING AND REMOVE
###############################################################################
def addItem(self, title=None, parent=None):
"""Adds an item, and returns it."""
if not parent:
parent = self.selectedItem()
if not title:
title = self.tr("New item")
name = QStandardItem(title)
_id = QStandardItem(self.getUniqueID())
row = [name, _id] + [QStandardItem() for i in range(2, len(World))]
parent.appendRow(row)
return name
def getUniqueID(self):
"""Returns an unused ID"""
parentItem = self.invisibleRootItem()
vals = []
def collectIDs(item):
vals.append(int(self.itemID(item)))
for c in self.children(item):
collectIDs(c)
for c in self.children(parentItem):
collectIDs(c)
k = 0
while k in vals:
k += 1
return str(k)
def removeItem(self):
while self.selectedIndexes():
index = self.selectedIndexes()[0]
self.removeRows(index.row(), 1, index.parent())
###############################################################################
# TEMPLATES
###############################################################################
def dataSets(self):
"""Returns sets of empty data that can guide the writer for world building."""
dataset = {
self.tr("Fantasy world building"): [
(self.tr("Physical"), [
self.tr("Climate"),
self.tr("Topography"),
self.tr("Astronomy"),
self.tr("Natural ressources"),
self.tr("Wild life"),
self.tr("Flora"),
self.tr("History"),
self.tr("Races"),
self.tr("Diseases"),
]),
(self.tr("Cultural"), [
self.tr("Customs"),
self.tr("Food"),
self.tr("Languages"),
self.tr("Education"),
self.tr("Dresses"),
self.tr("Science"),
self.tr("Calendar"),
self.tr("Bodily language"),
self.tr("Ethics"),
self.tr("Religion"),
self.tr("Government"),
self.tr("Politics"),
self.tr("Gender roles"),
self.tr("Music and arts"),
self.tr("Architecture"),
self.tr("Military"),
self.tr("Technology"),
self.tr("Courtship"),
self.tr("Demography"),
self.tr("Transportation"),
self.tr("Medicine"),
]),
(self.tr("Magic system"), [
self.tr("Rules"),
self.tr("Organization"),
self.tr("Magical objects"),
self.tr("Magical places"),
self.tr("Magical races"),
]),
self.tr("Important places"),
self.tr("Important objects"),
]
}
return dataset
def emptyDataMenu(self):
"""Returns a menu with the empty data sets."""
self.menu = QMenu("menu")
for name in self.dataSets():
a = QAction(name, self.menu)
a.triggered.connect(self.setEmptyData)
self.menu.addAction(a)
return self.menu
def setEmptyData(self):
"""Called from the menu generated with ``emptyDataMenu``."""
act = self.sender()
data = self.dataSets()[act.text()]
def addItems(data, parent):
for d in data:
if len(d) == 1 or type(d) == str:
self.addItem(d, parent)
else:
i = self.addItem(d[0], parent)
addItems(d[1], i)
addItems(data, None)
self.mw.treeWorld.expandAll()
###############################################################################
# APPEARANCE
###############################################################################
def data(self, index, role=Qt.EditRole):
level = 0
i = index
while i.parent() != QModelIndex():
i = i.parent()
level += 1
if role == Qt.BackgroundRole:
if level == 0:
return QBrush(QColor(S.highlightLight))
if role == Qt.TextAlignmentRole:
if level == 0:
return Qt.AlignCenter
if role == Qt.FontRole:
if level in [0, 1]:
f = qApp.font()
f.setBold(True)
return f
if role == Qt.ForegroundRole:
if level == 0:
return QBrush(QColor(S.highlightedTextDark))
if role == Qt.SizeHintRole:
fm = QFontMetrics(qApp.font())
h = fm.height()
if level == 0:
return QSize(0, h + 12)
elif level == 1:
return QSize(0, h + 6)
return QStandardItemModel.data(self, index, role)