Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Todd Parsons 2023-04-03 09:37:28 +01:00
commit a9a0208924
74 changed files with 13355 additions and 18007 deletions

View file

@ -38,7 +38,7 @@ jobs:
- name: Install Python build dependencies
run: |
python -m pip install --upgrade pip
pip install pyqt5==5.15.7 lxml pytest pytest-faulthandler language_tool_python symspellpy pyspellchecker pyenchant
pip install pyqt5==5.15.7 lxml pytest pytest-faulthandler markdown language_tool_python symspellpy pyspellchecker pyenchant
pip install pyinstaller
- name: pyinstaller build
run: |

View file

@ -1,5 +1,61 @@
# Changelog
## [0.15.0](https://github.com/olivierkes/manuskript/tree/0.14.0) (2023-03-04)
[Full Changelog](https://github.com/olivierkes/manuskript/compare/0.14.0...0.15.0)
**Implemented enhancements:**
- Feature request: Development version indicator [\#1126](https://github.com/olivierkes/manuskript/issues/1126)
**Fixed bugs:**
- Translations breaks shortcuts [\#1135](https://github.com/olivierkes/manuskript/issues/1135)
- Missing visual indicator for collapsables like metadata fields [\#1132](https://github.com/olivierkes/manuskript/issues/1132)
- New search bug [\#1125](https://github.com/olivierkes/manuskript/issues/1125)
- One-time glitch: dragged "World" entry to top of list and it disappeared [\#1122](https://github.com/olivierkes/manuskript/issues/1122)
- Loading Error with fileno [\#1121](https://github.com/olivierkes/manuskript/issues/1121)
- 0.14 won't open [\#1105](https://github.com/olivierkes/manuskript/issues/1105)
- Search no longer works [\#1095](https://github.com/olivierkes/manuskript/issues/1095)
- click on "Plan" makes Manuskript 0.14.0 crash [\#1094](https://github.com/olivierkes/manuskript/issues/1094)
- mouse over goes blank in fiction [\#1093](https://github.com/olivierkes/manuskript/issues/1093)
- Crash when opening a plot in the cheat sheet containing deleted characters [\#1082](https://github.com/olivierkes/manuskript/issues/1082)
- Crashes on hitting "+" while editing plot step summary [\#1081](https://github.com/olivierkes/manuskript/issues/1081)
- CTD Crash To Desktop after "inserting link" [\#1071](https://github.com/olivierkes/manuskript/issues/1071)
- Spellcheck intermittantly looses location in editor [\#1065](https://github.com/olivierkes/manuskript/issues/1065)
- Translation - missing lines in .ts file etc. issues [\#1052](https://github.com/olivierkes/manuskript/issues/1052)
- Debian installer zst compression error [\#1047](https://github.com/olivierkes/manuskript/issues/1047)
- manuskriptw.exe can not be executed due to unhandled exception "NullWriter" [\#1044](https://github.com/olivierkes/manuskript/issues/1044)
- Type error on launch [\#1043](https://github.com/olivierkes/manuskript/issues/1043)
- Crash when attempting to add an inexistent reference [\#1042](https://github.com/olivierkes/manuskript/issues/1042)
- Setting the language to German deletes shortcut-functions like "Ctrl+S" [\#1012](https://github.com/olivierkes/manuskript/issues/1012)
- Plot-step summary disappearing and not being saved! [\#1008](https://github.com/olivierkes/manuskript/issues/1008)
- Don't open msk from command line [\#993](https://github.com/olivierkes/manuskript/issues/993)
- Open in new tab doesn't work from tree [\#919](https://github.com/olivierkes/manuskript/issues/919)
- Metadata: References [\#756](https://github.com/olivierkes/manuskript/issues/756)
- \[Bug\] Next Button in Characters Pane [\#584](https://github.com/olivierkes/manuskript/issues/584)
- Context/right click Menu slow and only in english [\#487](https://github.com/olivierkes/manuskript/issues/487)
- Top level World items with sub-items do not visually indicate sub-items exist [\#305](https://github.com/olivierkes/manuskript/issues/305)
- saving error [\#274](https://github.com/olivierkes/manuskript/issues/274)
- Crashing when creating a new project - locale C [\#130](https://github.com/olivierkes/manuskript/issues/130)
**Closed issues:**
- Update files about languages [\#1133](https://github.com/olivierkes/manuskript/issues/1133)
- Adding a clearer discription to contributing guidlines [\#1115](https://github.com/olivierkes/manuskript/issues/1115)
- I can't click boxes to edit them [\#1104](https://github.com/olivierkes/manuskript/issues/1104)
- Minor Python error during Installation - Linux Mint 20.3 [\#1097](https://github.com/olivierkes/manuskript/issues/1097)
- Package as App Bundle for macOS [\#567](https://github.com/olivierkes/manuskript/issues/567)
**Merged pull requests:**
- Fix to error \#1095 [\#1098](https://github.com/olivierkes/manuskript/pull/1098) ([TheShadowOfHassen](https://github.com/TheShadowOfHassen))
- Add GitHub Actions Windows CI build to commits [\#1092](https://github.com/olivierkes/manuskript/pull/1092) ([MC42](https://github.com/MC42))
- Resolve "Search" and "Cheat sheet" strings not being translated correctly in source string [\#1091](https://github.com/olivierkes/manuskript/pull/1091) ([MC42](https://github.com/MC42))
- Feature/split editor functionality [\#1060](https://github.com/olivierkes/manuskript/pull/1060) ([tcsch](https://github.com/tcsch))
- Create a macOS installer \(fixes \#567\) [\#1056](https://github.com/olivierkes/manuskript/pull/1056) ([marosoft](https://github.com/marosoft))
- Session target [\#460](https://github.com/olivierkes/manuskript/pull/460) ([nephlm](https://github.com/nephlm))
## [0.14.0](https://github.com/olivierkes/manuskript/tree/0.14.0) (2022-06-08)
[Full Changelog](https://github.com/olivierkes/manuskript/compare/0.13.1...0.14.0)
@ -11,21 +67,20 @@
**Fixed bugs:**
- Crashing when I'm trying to create the 1st project [\#1035](https://github.com/olivierkes/manuskript/issues/1035)
- crash on the "Outline" section [\#1032](https://github.com/olivierkes/manuskript/issues/1032)
- Manuskript crashing while booting [\#1021](https://github.com/olivierkes/manuskript/issues/1021)
- Crashing when I'm trying to create the 1st project [\#1035](https://github.com/olivierkes/manuskript/issues/1035)
- \[Bug\] double click causes crash in outline or plots view [\#1014](https://github.com/olivierkes/manuskript/issues/1014)
- Re-ordering items in the outline causes data loss/text overwritting [\#1001](https://github.com/olivierkes/manuskript/issues/1001)
- An unhandled exception has occurred! on cheatsheet [\#994](https://github.com/olivierkes/manuskript/issues/994)
- Crash when changing index card style [\#992](https://github.com/olivierkes/manuskript/issues/992)
- Regex search causes crash [\#989](https://github.com/olivierkes/manuskript/issues/989)
- Crash when project file is open in another application [\#950](https://github.com/olivierkes/manuskript/issues/950)
- outliner folder gets renamed and contents replaced when dragged over other folder, only in upward direction [\#719](https://github.com/olivierkes/manuskript/issues/719)
**Closed issues:**
- Creating empty language file hr-HR [\#1023](https://github.com/olivierkes/manuskript/issues/1023)
- Creating project from template dialog has fixed size [\#996](https://github.com/olivierkes/manuskript/issues/996)
- Creating empty language file hr-HR [\#1023](https://github.com/olivierkes/manuskript/issues/1023)
- Russian translation [\#990](https://github.com/olivierkes/manuskript/issues/990)
- \[Windows Version\] Two program windows pop up [\#327](https://github.com/olivierkes/manuskript/issues/327)

View file

@ -3,6 +3,7 @@
[Manuskript](https://www.theologeek.ch/manuskript) is an open-source
tool for writers.
[![pytest](https://github.com/olivierkes/manuskript/workflows/Pytest%20Run%20%28Linux%29/badge.svg)](https://github.com/olivierkes/manuskript/actions/workflows/pytest.yml)
[![manuskript](https://snapcraft.io/manuskript/badge.svg)](https://snapcraft.io/manuskript)
[![translations](https://hosted.weblate.org/widgets/manuskript/-/translations/svg-badge.svg)](https://hosted.weblate.org/projects/manuskript/translations)

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -7,9 +7,9 @@ import re
from PyQt5.Qt import qVersion, PYQT_VERSION_STR
from PyQt5.QtCore import (pyqtSignal, QSignalMapper, QTimer, QSettings, Qt, QPoint,
QRegExp, QUrl, QSize, QModelIndex)
from PyQt5.QtGui import QStandardItemModel, QIcon, QColor
from PyQt5.QtGui import QStandardItemModel, QIcon, QColor, QStandardItem
from PyQt5.QtWidgets import QMainWindow, QHeaderView, qApp, QMenu, QActionGroup, QAction, QStyle, QListWidgetItem, \
QLabel, QDockWidget, QWidget, QMessageBox, QLineEdit
QLabel, QDockWidget, QWidget, QMessageBox, QLineEdit, QTextEdit, QTreeView, QDialog, QTableView
from manuskript import settings
from manuskript.enums import Character, PlotStep, Plot, World, Outline
@ -23,6 +23,7 @@ from manuskript.models.plotModel import plotModel
from manuskript.models.worldModel import worldModel
from manuskript.settingsWindow import settingsWindow
from manuskript.ui import style
from manuskript.ui import characterInfoDialog
from manuskript.ui.about import aboutDialog
from manuskript.ui.collapsibleDockWidgets import collapsibleDockWidgets
from manuskript.ui.importers.importer import importerDialog
@ -35,6 +36,7 @@ from manuskript.ui.views.outlineDelegates import outlineCharacterDelegate
from manuskript.ui.views.plotDelegate import plotDelegate
from manuskript.ui.views.MDEditView import MDEditView
from manuskript.ui.statusLabel import statusLabel
from manuskript.ui.bulkInfoManager import Ui_BulkInfoManager
# Spellcheck support
from manuskript.ui.views.textEditView import textEditView
@ -179,6 +181,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# self.loadProject(os.path.join(appPath(), "test_project.zip"))
# Bulk Character Info Management
self.tabsData = self.saveCharacterTabs() # Used for restoring tabsData with loadCharacterTabs() methods.
self.BulkManageUi = None
self.bulkAffectedCharacters = []
self.isPersoBulkModeEnabled = False
def updateDockVisibility(self, restore=False):
"""
Saves the state of the docks visibility. Or if `restore` is True,
@ -297,18 +305,170 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# CHARACTERS
###############################################################################
def changeCurrentCharacter(self, trash=None):
"""
def setPersoBulkMode(self, enabled: bool):
if enabled and self.BulkManageUi is None: # Delete all tabs and create the manager one
# Create the widget
bulkPersoInfoManager = QWidget()
bulkPersoInfoManagerUi = Ui_BulkInfoManager()
bulkPersoInfoManagerUi.setupUi(bulkPersoInfoManager)
@return:
"""
c = self.lstCharacters.currentCharacter()
if not c:
self.tabPersos.setEnabled(False)
self.BulkManageUi = bulkPersoInfoManagerUi # for global use
model = QStandardItemModel()
# Set the column headers
model.setColumnCount(2)
model.setHorizontalHeaderLabels([self.tr("Name"), self.tr("Value")])
# Set the width
self.updatePersoInfoView(bulkPersoInfoManagerUi.tableView)
bulkPersoInfoManagerUi.tableView.setModel(model) # Set the model of tableView
self.tabPersos.clear()
self.tabPersos.addTab(bulkPersoInfoManager, self.tr("Bulk Info Manager"))
self.isPersoBulkModeEnabled = True
self.refreshBulkAffectedCharacters()
# Showing the character names on the label
labelText = self.createCharacterSelectionString()
bulkPersoInfoManagerUi.lblCharactersDynamic.setText(labelText)
# Making the connections
self.makeBulkInfoConnections(bulkPersoInfoManagerUi)
elif enabled and self.BulkManageUi is not None: # If yet another character is selected, refresh the label
labelText = self.createCharacterSelectionString()
self.BulkManageUi.lblCharactersDynamic.setText(labelText)
else: # Delete manager tab and restore the others
if self.BulkManageUi is not None:
self.tabPersos.clear()
self.loadCharacterTabs()
self.BulkManageUi = None
self.bulkAffectedCharacters.clear()
def createCharacterSelectionString(self):
self.refreshBulkAffectedCharacters()
labelText = ""
length = len(self.bulkAffectedCharacters)
for i in range(length-1):
labelText += '"' + self.bulkAffectedCharacters[i] + '"' + ", "
labelText += '"' + self.bulkAffectedCharacters[length-1] + '"'
return labelText
def makeBulkInfoConnections(self, bulkUi):
# A lambda has to be used to pass in the argument
bulkUi.btnPersoBulkAddInfo.clicked.connect(lambda: self.addBulkInfo(bulkUi))
bulkUi.btnPersoBulkRmInfo.clicked.connect(lambda: self.removeBulkInfo(bulkUi))
bulkUi.btnPersoBulkApply.clicked.connect(lambda: self.applyBulkInfo(bulkUi))
def applyBulkInfo(self, bulkUi):
selectedItems = self.lstCharacters.currentCharacterIDs()
# Get the data from the tableview
model = bulkUi.tableView.model()
if model.rowCount() == 0:
QMessageBox.warning(self, self.tr("No Entries!"),
self.tr("Please add entries to apply to the selected characters."))
return
# Loop through each selected character and add the bulk info to them
for ID in selectedItems:
for row in range(model.rowCount()):
description = model.item(row, 0).text()
value = model.item(row, 1).text()
self.lstCharacters._model.addCharacterInfo(ID, description, value)
QMessageBox.information(self, self.tr("Bulk Info Applied"),
self.tr("The bulk info has been applied to the selected characters."))
# Remove all rows from the table
model.removeRows(0, model.rowCount())
def addBulkInfo(self, bulkUi): # Adds an item to the list
charInfoDialog = QDialog()
charInfoUi = characterInfoDialog.Ui_characterInfoDialog()
charInfoUi.setupUi(charInfoDialog)
if charInfoDialog.exec_() == QDialog.Accepted:
# User clicked OK, get the input values
description = charInfoUi.descriptionLineEdit.text()
value = charInfoUi.valueLineEdit.text()
# Add a new row to the model with the description and value
row = [QStandardItem(description), QStandardItem(value)]
bulkUi.tableView.model().appendRow(row)
bulkUi.tableView.update()
def removeBulkInfo(self, bulkUi):
# Get the selected rows
selection = bulkUi.tableView.selectionModel().selectedRows()
# Iterate over the rows and remove them (reversed, so the iteration is not affected)
for index in reversed(selection):
bulkUi.tableView.model().removeRow(index.row())
def saveCharacterTabs(self):
tabsData = []
for i in range(self.tabPersos.count()):
tabData = {}
widget = self.tabPersos.widget(i)
tabData['widget'] = widget
tabData['title'] = self.tabPersos.tabText(i)
tabsData.append(tabData)
return tabsData
def loadCharacterTabs(self):
for tabData in self.tabsData:
widget = tabData['widget']
title = tabData['title']
self.tabPersos.addTab(widget, title)
def handleCharacterSelectionChanged(self):
selectedCharacters = self.lstCharacters.currentCharacters()
characterSelectionIsEmpty = not any(selectedCharacters)
if characterSelectionIsEmpty:
self.tabPersos.setEnabled(False)
return
cList = list(filter(None, self.lstCharacters.currentCharacters())) #cList contains all valid characters
character = cList[0]
self.changeCurrentCharacter(character)
if len(selectedCharacters) > 1:
self.setPersoBulkMode(True)
else:
if self.BulkManageUi is not None:
self.refreshBulkAffectedCharacters()
self.BulkManageUi.lblCharactersDynamic.setText( self.createCharacterSelectionString() )
tableview_model = self.BulkManageUi.tableView.model()
if tableview_model.rowCount() > 0:
confirm = QMessageBox.warning(
self, self.tr("Un-applied data!"),
self.tr("There are un-applied entries in this tab. Discard them?"),
QMessageBox.Yes | QMessageBox.No,
defaultButton = QMessageBox.No
)
if confirm != QMessageBox.Yes:
return
self.setPersoBulkMode(False)
self.tabPersos.setEnabled(True)
index = c.index()
def refreshBulkAffectedCharacters(self): # Characters affected by a potential bulk-info modification
self.bulkAffectedCharacters = []
for character in self.lstCharacters.currentCharacters():
self.bulkAffectedCharacters.append(character.name())
def changeCurrentCharacter(self, character, trash=None):
if character is None:
return
index = character.index()
for w in [
self.txtPersoName,
@ -325,24 +485,25 @@ class MainWindow(QMainWindow, Ui_MainWindow):
w.setCurrentModelIndex(index)
# Button color
self.updateCharacterColor(c.ID())
self.updateCharacterColor(character.ID())
# Slider importance
self.updateCharacterImportance(c.ID())
self.updateCharacterImportance(character.ID())
# POV state
self.updateCharacterPOVState(c.ID())
self.updateCharacterPOVState(character.ID())
# Character Infos
self.tblPersoInfos.setRootIndex(index)
if self.mdlCharacter.rowCount(index):
self.updatePersoInfoView()
self.updatePersoInfoView(self.tblPersoInfos)
def updatePersoInfoView(self):
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
self.tblPersoInfos.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
self.tblPersoInfos.verticalHeader().hide()
def updatePersoInfoView(self, infoView):
infoView.horizontalHeader().setStretchLastSection(True)
infoView.horizontalHeader().setMinimumSectionSize(20)
infoView.horizontalHeader().setMaximumSectionSize(500)
infoView.verticalHeader().hide()
def updateCharacterColor(self, ID):
c = self.mdlCharacter.getCharacterByID(ID)
@ -370,7 +531,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
pass
def deleteCharacter(self):
ID = self.lstCharacters.removeCharacter()
ID = self.lstCharacters.removeCharacters()
if ID is None:
return
for itemID in self.mdlOutline.findItemsByPOV(ID):
@ -903,7 +1064,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def makeUIConnections(self):
"Connections that have to be made once only, even when a new project is loaded."
self.lstCharacters.currentItemChanged.connect(self.changeCurrentCharacter, F.AUC)
self.lstCharacters.itemSelectionChanged.connect(self.handleCharacterSelectionChanged, F.AUC)
self.txtPlotFilter.textChanged.connect(self.lstPlots.setFilter, F.AUC)
self.lstPlots.currentItemChanged.connect(self.changeCurrentPlot, F.AUC)
@ -956,6 +1117,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
widget.setCurrentModelIndex(self.mdlFlatData.index(0, col))
# Characters
self.updatePersoInfoView(self.tblPersoInfos)
self.lstCharacters.setCharactersModel(self.mdlCharacter)
self.tblPersoInfos.setModel(self.mdlCharacter)
try:

View file

@ -220,6 +220,17 @@ class characterModel(QAbstractItemModel, searchableModel):
self.endInsertRows()
mainWindow().updatePersoInfoView()
def addCharacterInfo(self, ID, description, value):
c = self.getCharacterByID(ID)
self.beginInsertRows(c.index(), len(c.infos), len(c.infos))
c.infos.append(CharacterInfo(
c,
description=self.tr(description),
value=self.tr(value)
))
self.endInsertRows()
mainWindow().updatePersoInfoView(mainWindow().tblPersoInfos)
def removeCharacterInfo(self, ID):
c = self.getCharacterByID(ID)

View file

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'manuskript\manuskript\ui\bulkInfoManager.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_BulkInfoManager(object):
def setupUi(self, BulkInfoManager):
BulkInfoManager.setObjectName("BulkInfoManager")
BulkInfoManager.setWindowModality(QtCore.Qt.WindowModal)
BulkInfoManager.resize(644, 556)
self.verticalLayout = QtWidgets.QVBoxLayout(BulkInfoManager)
self.verticalLayout.setObjectName("verticalLayout")
self.lblStaticMessage = QtWidgets.QLabel(BulkInfoManager)
self.lblStaticMessage.setObjectName("lblStaticMessage")
self.verticalLayout.addWidget(self.lblStaticMessage)
self.lblCharactersDynamic = QtWidgets.QLabel(BulkInfoManager)
self.lblCharactersDynamic.setObjectName("lblCharactersDynamic")
self.verticalLayout.addWidget(self.lblCharactersDynamic)
self.tableView = QtWidgets.QTableView(BulkInfoManager)
self.tableView.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedKingdom))
self.tableView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
self.tableView.setAlternatingRowColors(True)
self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tableView.setTextElideMode(QtCore.Qt.ElideNone)
self.tableView.setCornerButtonEnabled(False)
self.tableView.setObjectName("tableView")
self.tableView.verticalHeader().setVisible(False)
self.verticalLayout.addWidget(self.tableView)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.btnPersoBulkAddInfo = QtWidgets.QPushButton(BulkInfoManager)
self.btnPersoBulkAddInfo.setText("")
icon = QtGui.QIcon.fromTheme("list-add")
self.btnPersoBulkAddInfo.setIcon(icon)
self.btnPersoBulkAddInfo.setObjectName("btnPersoBulkAddInfo")
self.horizontalLayout.addWidget(self.btnPersoBulkAddInfo)
self.btnPersoBulkRmInfo = QtWidgets.QPushButton(BulkInfoManager)
self.btnPersoBulkRmInfo.setText("")
icon = QtGui.QIcon.fromTheme("list-remove")
self.btnPersoBulkRmInfo.setIcon(icon)
self.btnPersoBulkRmInfo.setObjectName("btnPersoBulkRmInfo")
self.horizontalLayout.addWidget(self.btnPersoBulkRmInfo)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.btnPersoBulkApply = QtWidgets.QPushButton(BulkInfoManager)
self.btnPersoBulkApply.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedKingdom))
self.btnPersoBulkApply.setObjectName("btnPersoBulkApply")
self.horizontalLayout.addWidget(self.btnPersoBulkApply)
self.horizontalLayout.setStretch(0, 1)
self.horizontalLayout.setStretch(1, 1)
self.horizontalLayout.setStretch(2, 5)
self.horizontalLayout.setStretch(3, 1)
self.verticalLayout.addLayout(self.horizontalLayout)
self.retranslateUi(BulkInfoManager)
QtCore.QMetaObject.connectSlotsByName(BulkInfoManager)
def retranslateUi(self, BulkInfoManager):
_translate = QtCore.QCoreApplication.translate
BulkInfoManager.setWindowTitle(_translate("BulkInfoManager", "Form"))
self.lblStaticMessage.setText(_translate("BulkInfoManager", "Affected Characters:"))
self.lblCharactersDynamic.setText(_translate("BulkInfoManager", "NONE"))
self.btnPersoBulkAddInfo.setToolTip(_translate("BulkInfoManager", "Add entry to the list."))
self.btnPersoBulkRmInfo.setToolTip(_translate("BulkInfoManager", "Remove entry from the list."))
self.btnPersoBulkApply.setToolTip(_translate("BulkInfoManager", "Adds all items to the selected characters."))
self.btnPersoBulkApply.setText(_translate("BulkInfoManager", "Apply Changes"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
BulkInfoManager = QtWidgets.QWidget()
ui = Ui_BulkInfoManager()
ui.setupUi(BulkInfoManager)
BulkInfoManager.show()
sys.exit(app.exec_())

View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BulkInfoManager</class>
<widget class="QWidget" name="BulkInfoManager">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>644</width>
<height>556</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblStaticMessage">
<property name="text">
<string>Affected Characters:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblCharactersDynamic">
<property name="text">
<string>NONE</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="tableView">
<property name="locale">
<locale language="English" country="UnitedKingdom"/>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,5,1">
<item>
<widget class="QPushButton" name="btnPersoBulkAddInfo">
<property name="toolTip">
<string>Add entry to the list.</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="list-add">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnPersoBulkRmInfo">
<property name="toolTip">
<string>Remove entry from the list.</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnPersoBulkApply">
<property name="toolTip">
<string>Adds all items to the selected characters.</string>
</property>
<property name="locale">
<locale language="English" country="UnitedKingdom"/>
</property>
<property name="text">
<string>Apply Changes</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'D:\OpensourceWork\manuskript\manuskript\ui\characterInfoDialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_characterInfoDialog(object):
def setupUi(self, characterInfoDialog):
characterInfoDialog.setObjectName("characterInfoDialog")
characterInfoDialog.resize(481, 148)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(characterInfoDialog.sizePolicy().hasHeightForWidth())
characterInfoDialog.setSizePolicy(sizePolicy)
characterInfoDialog.setMinimumSize(QtCore.QSize(481, 148))
characterInfoDialog.setMaximumSize(QtCore.QSize(481, 148))
characterInfoDialog.setTabletTracking(False)
characterInfoDialog.setFocusPolicy(QtCore.Qt.NoFocus)
characterInfoDialog.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedKingdom))
self.gridLayout = QtWidgets.QGridLayout(characterInfoDialog)
self.gridLayout.setObjectName("gridLayout")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_2 = QtWidgets.QLabel(characterInfoDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
self.label_2.setSizePolicy(sizePolicy)
self.label_2.setObjectName("label_2")
self.horizontalLayout_2.addWidget(self.label_2)
self.valueLineEdit = QtWidgets.QLineEdit(characterInfoDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.valueLineEdit.sizePolicy().hasHeightForWidth())
self.valueLineEdit.setSizePolicy(sizePolicy)
self.valueLineEdit.setFocusPolicy(QtCore.Qt.StrongFocus)
self.valueLineEdit.setLayoutDirection(QtCore.Qt.RightToLeft)
self.valueLineEdit.setObjectName("valueLineEdit")
self.horizontalLayout_2.addWidget(self.valueLineEdit)
self.gridLayout.addLayout(self.horizontalLayout_2, 3, 0, 1, 1)
self.horizontalLayout_1 = QtWidgets.QHBoxLayout()
self.horizontalLayout_1.setObjectName("horizontalLayout_1")
self.label = QtWidgets.QLabel(characterInfoDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy)
self.label.setObjectName("label")
self.horizontalLayout_1.addWidget(self.label)
self.descriptionLineEdit = QtWidgets.QLineEdit(characterInfoDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.descriptionLineEdit.sizePolicy().hasHeightForWidth())
self.descriptionLineEdit.setSizePolicy(sizePolicy)
self.descriptionLineEdit.setFocusPolicy(QtCore.Qt.StrongFocus)
self.descriptionLineEdit.setLayoutDirection(QtCore.Qt.RightToLeft)
self.descriptionLineEdit.setObjectName("descriptionLineEdit")
self.horizontalLayout_1.addWidget(self.descriptionLineEdit)
self.gridLayout.addLayout(self.horizontalLayout_1, 2, 0, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(characterInfoDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth())
self.buttonBox.setSizePolicy(sizePolicy)
self.buttonBox.setFocusPolicy(QtCore.Qt.StrongFocus)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 4, 0, 1, 1)
self.retranslateUi(characterInfoDialog)
self.buttonBox.accepted.connect(characterInfoDialog.accept)
self.buttonBox.rejected.connect(characterInfoDialog.reject)
QtCore.QMetaObject.connectSlotsByName(characterInfoDialog)
characterInfoDialog.setTabOrder(self.descriptionLineEdit, self.valueLineEdit)
def retranslateUi(self, characterInfoDialog):
_translate = QtCore.QCoreApplication.translate
characterInfoDialog.setWindowTitle(_translate("characterInfoDialog", "Add Character Info"))
self.label_2.setText(_translate("characterInfoDialog", "Value:"))
self.label.setText(_translate("characterInfoDialog", "Name:"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
characterInfoDialog = QtWidgets.QDialog()
ui = Ui_characterInfoDialog()
ui.setupUi(characterInfoDialog)
characterInfoDialog.show()
sys.exit(app.exec_())

View file

@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>characterInfoDialog</class>
<widget class="QDialog" name="characterInfoDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>481</width>
<height>148</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>481</width>
<height>148</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>481</width>
<height>148</height>
</size>
</property>
<property name="tabletTracking">
<bool>false</bool>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle">
<string>Add Character Info</string>
</property>
<property name="locale">
<locale language="English" country="UnitedKingdom"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Value:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="valueLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="descriptionLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>descriptionLineEdit</tabstop>
<tabstop>valueLineEdit</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>characterInfoDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>259</x>
<y>136</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>147</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>characterInfoDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>327</x>
<y>136</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>147</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -315,6 +315,7 @@ class Ui_MainWindow(object):
self.lstCharacters = characterTreeView(self.groupBox)
self.lstCharacters.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.lstCharacters.setDragEnabled(True)
self.lstCharacters.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.lstCharacters.setObjectName("lstCharacters")
self.lstCharacters.headerItem().setText(0, "1")
self.verticalLayout_8.addWidget(self.lstCharacters)
@ -354,7 +355,7 @@ class Ui_MainWindow(object):
self.scrollAreaPersoInfos.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
self.scrollAreaPersoInfos.setObjectName("scrollAreaPersoInfos")
self.scrollAreaPersoInfosWidget = QtWidgets.QWidget()
self.scrollAreaPersoInfosWidget.setGeometry(QtCore.QRect(0, 0, 229, 558))
self.scrollAreaPersoInfosWidget.setGeometry(QtCore.QRect(0, 0, 453, 699))
self.scrollAreaPersoInfosWidget.setObjectName("scrollAreaPersoInfosWidget")
self.formLayout_8 = QtWidgets.QFormLayout(self.scrollAreaPersoInfosWidget)
self.formLayout_8.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
@ -1365,7 +1366,7 @@ class Ui_MainWindow(object):
self.stack.setCurrentIndex(1)
self.tabMain.setCurrentIndex(0)
self.tabSummary.setCurrentIndex(0)
self.tabPersos.setCurrentIndex(3)
self.tabPersos.setCurrentIndex(0)
self.tabPlot.setCurrentIndex(0)
self.comboBox_2.setCurrentIndex(0)
self.stkPlotSummary.setCurrentIndex(0)

View file

@ -670,6 +670,9 @@
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<column>
<property name="text">
<string notr="true">1</string>
@ -723,7 +726,7 @@
</widget>
<widget class="QTabWidget" name="tabPersos">
<property name="currentIndex">
<number>3</number>
<number>0</number>
</property>
<widget class="QWidget" name="info">
<attribute name="title">
@ -764,8 +767,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>229</width>
<height>558</height>
<width>453</width>
<height>699</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout_8">

View file

@ -2,11 +2,12 @@
# --!-- coding: utf8 --!--
from PyQt5.QtCore import QSize, QModelIndex, Qt
from PyQt5.QtGui import QPixmap, QColor, QIcon, QBrush
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QColorDialog
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QColorDialog, QDialog, QMessageBox
from manuskript.enums import Character
from manuskript.functions import iconColor, mainWindow
from manuskript.ui import style as S
from manuskript.ui import characterInfoDialog
class characterTreeView(QTreeWidget):
@ -137,15 +138,29 @@ class characterTreeView(QTreeWidget):
self._model.addCharacter(importance=curr_importance)
def removeCharacter(self):
def removeCharacters(self):
"""
Removes selected character.
Removes selected characters.
"""
ID = self.currentCharacterID()
if ID is None:
IDs = self.currentCharacterIDs()
# If none of the IDs are valid, do nothing.
if not any(IDs):
return None
self._model.removeCharacter(ID)
return ID
#Get confirmation from user
confirm = QMessageBox.warning(
self, "Delete selected character(s)?",
"Are you sure you want to delete the selected character(s)?",
QMessageBox.Yes | QMessageBox.No
)
if confirm != QMessageBox.Yes:
return None
#Delete all selected characters
for ID in IDs:
self._model.removeCharacter(ID)
return IDs
def choseCharacterColor(self):
ID = self.currentCharacterID()
@ -170,7 +185,21 @@ class characterTreeView(QTreeWidget):
mainWindow().updateCharacterPOVState(ID)
def addCharacterInfo(self):
self._model.addCharacterInfo(self.currentCharacterID())
#Setting up dialog
charInfoDialog = QDialog()
charInfoUi = characterInfoDialog.Ui_characterInfoDialog()
charInfoUi.setupUi(charInfoDialog)
if charInfoDialog.exec_() == QDialog.Accepted:
# User clicked OK, get the input values
description = charInfoUi.descriptionLineEdit.text()
value = charInfoUi.valueLineEdit.text()
# Add the character info with the input values
ID = self.currentCharacterID()
self._model.addCharacterInfo(ID, description, value)
def removeCharacterInfo(self):
self._model.removeCharacterInfo(self.currentCharacterID())
@ -182,6 +211,14 @@ class characterTreeView(QTreeWidget):
return ID
def currentCharacterIDs(self): #Exactly like currentCharacterID(), except for multiselection
IDs = []
for item in self.selectedItems():
ID = item.data(0, Qt.UserRole)
if ID is not None:
IDs.append(ID)
return IDs
def currentCharacter(self):
"""
Returns the selected character
@ -189,6 +226,16 @@ class characterTreeView(QTreeWidget):
"""
ID = self.currentCharacterID()
return self._model.getCharacterByID(ID)
def currentCharacters(self):
"""
Returns the selected characters (when multiple are selected)
@return: List of Characters
"""
IDs = self.currentCharacterIDs()
characters = []
for ID in IDs:
characters.append(self._model.getCharacterByID(ID))
return characters
def getItemByID(self, ID):
for t in range(self.topLevelItemCount()):

View file

@ -3,7 +3,7 @@
# Single source the package version
# https://packaging.python.org/guides/single-sourcing-package-version/
__version__ = "0.14.0"
__version__ = "0.15.0"
def getVersion():
return __version__

View file

@ -56,6 +56,7 @@
<launchable type="desktop-id">ch.theologeek.Manuskript.desktop</launchable>
<releases>
<release version="0.15.0" date="2023-03-04" />
<release version="0.14.0" date="2022-06-08" />
<release version="0.13.1" date="2021-12-13" />
<release version="0.12.0" date="2021-04-30" />